An event hub whose timeline is empty until someone else acts has nothing to show and nothing to prove. Relay is an app on this forge like any other: it should be the first poster, through its own actions, with source = \"relay\".
Done looks like
[ ] When an app is registered, rotated or revoked (#7's actions), relay records an event on its own timeline: kinds app.registered, app.rotated, app.revoked; subject is the app id; summary is one line naming the app and who did it ("juniper registered bazaar"); no key, no secret, no derived value ever appears in any field, and a test asserts the freshly issued key is absent from the stored row.
[ ] On boot, one relay.deployed event: subject is the short commit, summary names the environment ("production, commit bbf8ef9"), and dedupe is the commit — so a restart, a crash loop or a second process does not repeat it, which is the dedupe rule from #4 paying for itself.
[ ] These are written through postEvent with an app identity relay builds for itself, not by an INSERT — the rules that hold for every other poster hold for relay, and if the action refuses, the failure is logged and the operation it followed still succeeds. A registration must never fail because an event could not be written.
[ ] Previews do not pollute production and production does not pollute a preview: each environment has its own database already, and the boot event names the environment so a reader can tell which is which.
[ ] The page's empty state stops being reachable in practice, which is the point: a new deploy has at least one event.
[ ] Tests: registering an app emits and stores the event; the key is not in it; two boots at the same commit store one row; a boot at a new commit stores a second; and a postEvent failure does not fail the registration.
Files:src/actions.ts, src/server.ts (the boot event, after the listener is up), src/actions.test.ts, src/server.test.ts, README.md
Risks: an event on a write path is a second thing that can fail — it must be best-effort and never in front of the answer. The boot event runs in the web process only; the terminal must not post one. Naming the person who acted puts a username on a public timeline: that is a deliberate choice, so say it in the README and keep it to the username the forge already shows.
Suggested: Scout — it is a handful of calls in actions that already exist, and it makes the hub demonstrate itself.
An event hub whose timeline is empty until someone else acts has nothing to show and nothing to prove. Relay is an app on this forge like any other: it should be the first poster, through its own actions, with
source = \"relay\".Done looks like
app.registered,app.rotated,app.revoked;subjectis the app id;summaryis one line naming the app and who did it ("juniper registered bazaar"); no key, no secret, no derived value ever appears in any field, and a test asserts the freshly issued key is absent from the stored row.relay.deployedevent:subjectis the short commit,summarynames the environment ("production, commit bbf8ef9"), anddedupeis the commit — so a restart, a crash loop or a second process does not repeat it, which is the dedupe rule from #4 paying for itself.postEventwith an app identity relay builds for itself, not by anINSERT— the rules that hold for every other poster hold for relay, and if the action refuses, the failure is logged and the operation it followed still succeeds. A registration must never fail because an event could not be written.postEventfailure does not fail the registration.Files:
src/actions.ts,src/server.ts(the boot event, after the listener is up),src/actions.test.ts,src/server.test.ts,README.mdRisks: an event on a write path is a second thing that can fail — it must be best-effort and never in front of the answer. The boot event runs in the web process only; the terminal must not post one. Naming the person who acted puts a username on a public timeline: that is a deliberate choice, so say it in the README and keep it to the username the forge already shows.
Suggested: Scout — it is a handful of calls in actions that already exist, and it makes the hub demonstrate itself.