Automations and webhooks for the AT Protocol airglow.run

refactor(logs): serialize delivery-log rows for the islands in one place #70

Closed tyb.there-hugo.dev
Closed opened by tyb.there-hugo.dev

Depends on #65.

Optional, low priority.

Problem #

Four places build the JSON a delivery-log island reads, each by hand. #56 was one of them missing runState.

Evidence #

  • The four hand-built row maps:
    • app/routes/api/automations/[rkey].ts:71-87
    • app/routes/api/automations/[rkey]/logs.ts:23-39
    • app/routes/u/[handle]/[rkey]/logs.tsx:108-121
    • lib/actions/logs-query.ts:43-66 (serializeLogRow, which also omits recordUri)
  • 1908205 added the missing field to only one of them.

Expected #

One helper in lib/actions/logs-query.ts builds the per-automation row shape (id, actionIndex, stepId, runId, itemIndex, eventTimeUs, statusCode, message, error, recordUri, dryRun, attempt, runState, createdAt). serializeLogRow extends it with the automation name and rkey. All four sites use it.

Acceptance criteria #

Out of scope #

Rendering recordUri in LogsBrowser or AdminLogsBrowser.

Queued: the loop will work on this version of the issue.

loop:queued cid=bafyreid37bybsl7dx55j3oljtm6vdjeeaxkxe5y2p3inmvjbbyd2vw3qzm

Working on this, attempt 1.

loop:claim run=contribute-20261028-141842-3myumucpw4s22 branch=loop/3myumucpw4s22 attempt=1 issue=70

refactor(logs): serialize delivery-log rows for the islands in one place

There is now one helper in lib/actions/logs-query.ts, serializeDeliveryLogRow, that builds the delivery-log row JSON the islands read. Before this, four places built that row by hand, and #56 happened because one of them left out runState. serializeLogRow now extends the shared helper with the automation's uri, name and rkey. The three route files that had hand-written row maps now call the shared helper.

Changes #

  • lib/actions/logs-query.ts: new DeliveryLogRowJson type and serializeDeliveryLogRow helper with these fields: id, actionIndex, stepId, runId, itemIndex, eventTimeUs, statusCode, message, error, recordUri, dryRun, attempt, runState, createdAt. SerializedLogRow is now DeliveryLogRowJson & { automationUri, automationName, automationRkey }.
  • app/routes/api/automations/[rkey].ts, app/routes/api/automations/[rkey]/logs.ts and app/routes/u/[handle]/[rkey]/logs.tsx now do logs.map(serializeDeliveryLogRow).
  • serializeLogRow (used by /api/delivery-logs and /settings/logs) now includes recordUri. Before, it left it out. LogsBrowser still doesn't display it, since that's out of scope.

Verification #

  • pnpm run check and pnpm run test pass: 178 files, 2738 tests. That includes the existing route tests for /api/automations/:rkey, /api/automations/:rkey/logs and /u/:handle/:rkey/logs.
  • Type test in app/islands/DeliveryLog.test.tsx: every key of the island's LogEntry must be in DeliveryLogRowJson, and DeliveryLogRowJson must be assignable to LogEntry. I removed recordUri from the shared type on purpose and vp check failed on this test with TS2344. Then I put it back.
  • Unit test in lib/actions/logs-query.test.ts: toStrictEqual on the output of both serializers. It fails if a column is dropped, and also if a server-only column leaks into the output (payload, countsTowardRateLimit).
  • No UI changed, so there was no keyboard check to do.

Acceptance criteria #

Decisions you can reverse #

  • Names: serializeDeliveryLogRow / DeliveryLogRowJson.
  • DeliveryLog.tsx keeps its own LogEntry type and the test pins it to the shared shape. The other option was to import the shared type into the island.
  • I left AdminSerializedLogRow alone. Its query selects its own columns from a join and is not one of the four sites the issue lists.

Review: https://tangled.org/exosphere.site/airglow/compare/main...loop/3myumucpw4s22

loop:pushed run=contribute-20261028-141842-3myumucpw4s22 sha=631d33409285c4c959023e3aa04b5b79c909f7f0

Verdict: merge. The branch adds one helper, serializeDeliveryLogRow in lib/actions/logs-query.ts, that builds the per-automation row with the 14 fields the issue lists. serializeLogRow now spreads that helper and adds the automation uri, name and rkey, so it gains recordUri. All four sites the issue names now use the helper. Check and tests pass, and the new type test does catch a dropped column.

What I checked:

  • Criterion 1. The three route files (api/automations/[rkey].ts, api/automations/[rkey]/logs.ts, u/[handle]/[rkey]/logs.tsx) now just call logs.map(serializeDeliveryLogRow). No hand-written row map is left in them.
  • Other row builders. I searched the whole tree for more places that build rows, using runState, createdAt.getTime(), initialLogs and the serializer names. /api/delivery-logs and /settings/logs already go through serializeLogRow. The only other builder is admin-logs-query.ts (AdminSerializedLogRow). It selects its own columns from a join, the issue does not list it, and the contributor called out leaving it alone as a choice the owner can reverse.
  • Criterion 2. I compared the new helper with the three removed maps: same keys, same order, same createdAt epoch-ms conversion. The only change is that the cross-automation serializeLogRow output gains recordUri, which the issue asks for. The automation fields move to the end of each object, which changes only the key order in the JSON. The existing route tests for the three endpoints pass.
  • Criterion 3. In a scratch edit I removed runState from both DeliveryLogRowJson and the helper. vp check then failed with TS2344 on the new expectTypeOf test in DeliveryLog.test.tsx, plus errors where it is used. I restored the file afterwards. The new logs-query.test.ts uses toStrictEqual, so it also catches a dropped column, or a server-only one such as payload leaking into the output.
  • Checks. pnpm run check passes. pnpm run test passes: 178 files, 2738 tests.
  • Scope. There are no UI, migration or owner-only file changes. recordUri is not rendered in LogsBrowser, as the issue's out-of-scope section says.

loop:verdict run=review-20261028-142528-3myumucpw4s22 sha=631d33409285c4c959023e3aa04b5b79c909f7f0 verdict=merge

Merged onto main as acb8f87d6f53b3662a829251a975dcb2636e90cc.

loop:merged sha=acb8f87d6f53b3662a829251a975dcb2636e90cc head=631d33409285c4c959023e3aa04b5b79c909f7f0

Sign up or Sign in to add to the discussion.