Repository navigation
feat(service-automation): a record-triggered flow's notification links to the record that started the run when it names no link - #30252
objectstack-fleet[bot] wants to merge 4 commits into
Conversation
…nk defaults to the trigger record (WIP) Claude-Session: https://claude.ai/code/session_01Utp6CZ1tD2uZm21w4Bj1xs Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CZ1tD2uZm21w4Bj1xs Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CZ1tD2uZm21w4Bj1xs Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 14 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 3 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 10 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 37c449daf493163c4437c8ac55b459d3f864e12d && git checkout 37c449daf493163c4437c8ac55b459d3f864e12d
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin bb86ff96cc6e3854d00c39488a0a8985fb1312d1 6de9d516466427f468fd35178380b7c1acac90eb && git checkout -B drift-repro bb86ff96cc6e3854d00c39488a0a8985fb1312d1 && git merge --no-ff 6de9d516466427f468fd35178380b7c1acac90eb
node scripts/docs-audit/affected-docs.mjs --json bb86ff96cc6e3854d00c39488a0a8985fb1312d1
|
|
domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF 席位意见:ACCEPT。默认只在作者一个链接都没写、且本次运行有触发记录时生效;显式写法照旧优先,删除事件不链接,组织解析不重复读。 席位核对Head-sha:
|
Requested by Bill · project thread
domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF
维护者速读
sourceObject/sourceId/actionUrl时,通知默认链到触发这次运行的那条记录;点开通知直接进记录页。os validate也通过,链接却是空的。卡 Flow notify: a record-triggered flow's notification links nowhere unless the author adds the source pair #30121「第一组:会卡住人或误导人」。actionUrl照旧优先,半对照旧丢弃,定时/API/无记录的手动运行不变,删除事件不链(记录已不在)。回滚即撤本 PR。packages/services/service-automation/src/builtin/notify-node.ts的defaultClickThroughOf与调用处,再看notify-node.test.ts末尾新的 describe。pnpm --filter @objectstack/service-automation exec vitest run --maxWorkers=2 src/builtin/notify-node.test.ts,预期 23 条全绿。Fixes #30121
Clause-②: no — no accepted key, value or exported type changes;
sourceObject/sourceId/actionUrlkeep their meaning when written, and no option or type member was added to reach the trigger record (the node already reads it throughtriggerRecordOf).Metadata-protocol: semantic
Skills-docs: follow-up owed — skills/objectstack-automation/SKILL.md (the notify example's
click-through: a PAIR, else droppedline), content/docs/automation/flows.mdx (the notifysourceIdparagraph), packages/spec/src/automation/io-node-config.zod.ts (thesourceObject/sourceIddescribes, which feed content/docs/references/automation/io-node-config.mdx). The skill line is a governed (Tier H) edit and the spec describe is out of this order's scope, so neither rides here; the seat files the card.What changes
@objectstack/service-automation— thenotifynode (src/builtin/notify-node.ts):defaultClickThroughOf(cfg, context, trigger). When the node writes none ofsourceObject,sourceIdandactionUrl, the click-through record is the run's trigger record, read through the existingtriggerRecordOf(context): the same readingrecipients: { emailField }and the organization fallback already use. The messaging service then stores it assys_notification.source_object/source_idand synthesizes/OBJECT/ID, exactly as for an authored pair.origin/mainat the run-starting doors:trigger-record-change):object+ the row,record.idpresent. Defaults.trigger-scheduletime-relative-trigger.ts):object: desc.object,record: row. That object's row is the record the run is about, so it defaults.runtimeaction-execution.ts):object+recordwith the requestedrecordIdstamped. Defaults.trigger-api:record: payloadwith noobject), manual REST start (objectbut norecord): no trigger record. Unchanged.beforeDelete,afterDelete) are not defaulted: the record is gone once the write lands, and this node already drops a half-written pair so the inbox never renders a dead link. An authored pair on a delete flow is still honoured.actionUrlwritten alone keeps today's behaviour too: the URL is the link and nosourceis defaulted beside it, per the card's "an explicitactionUrlor pair still wins".organization_idNULL on 18.0.0-next.0: the platform's own WARN says reports and cleanup that filter by organization will not see them #23284) asked[source, trigger]; a defaultedsourceis the trigger record itself, so the second candidate is skipped when it is the same object (no secondfindOne). The organization it resolves is unchanged.sourceObject,sourceIdandactionUrl(the node descriptor'sconfigSchema) says the default.Tests
src/builtin/notify-node.test.ts, one new top-leveldescribein the existing harness, six pins:sourceis{ object: 'repair_ticket', id: 't_7' }, nourl;actionUrlalone:urlas written, nosourcedefaulted;sourceObjectonly): still dropped;object, norecord): nosource;afterDelete: nosource.Local runs (head after the final commit is in the report)
pnpm --filter @objectstack/service-automation exec vitest run --maxWorkers=2 src/builtin/notify-node.test.ts: Test Files 1 passed, Tests 23 passed (17 before + 6).pnpm --filter @objectstack/service-automation test(underos-verify-lock.sh): Test Files 263 passed (263), Tests 3407 passed (3407), lock VERDICT command-exit 0.pnpm --filter @objectstack/service-automation typecheck: exit 0 (test layer included,check:test-typecheckOK, 0 debt).Ablation (one, on the behaviour the pins hold)
node scripts/ablation-replace.mjsonnotify-node.ts, anchorreturn trigger;(the default's answer) replaced byreturn trigger && undefined; // ABLATED_30121: anchor x1 to x0, replacement x0 to x1, blob 94746f6b12e1 to 381704ef410f. Run: Tests 1 failed, 22 passed; the one red is pin 1, "links a record-triggered notify that names no source to the trigger record". Restored: blob equals HEAD (94746f6b12e1),git diff HEADempty. The test imports the executor fromsrc, so no build sat between the mutation and the run.A first attempt used a bare identifier as the marker, which threw a ReferenceError and turned eight unrelated tests red; that run was discarded as a malformed mutation, not counted.
Acceptance notes
sourceObject/sourceId(packages/spec/src/automation/io-node-config.zod.ts) still say "Only takes effect together with …", which stays true for an authored pair but does not mention the default. Out of this order's scope (packages/spec/src/**); listed underSkills-docs:above.recordLoadDenied: true) still carries the requested id, so its notification links to that id, as the authoredsourceId: record.idwould. The record page applies the recipient's own access when opened.Verification
Gate list derived with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack; each command's exit code was recorded before any pipe and reconciled with--ran. Readings are in the os-dev-report comment on #30121.origin/mainwas merged once before opening (no incoming commit touchedservice-automationorpackages/spec).Generated by Claude Code