You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
automation: save_notice follow-ups from #28251 — the array triggerType refusal wording, a persisted approval round-trip test, and the lint node-type lists #28786
Filing gate: ① the three non-blocking should-fixes of the CONTRACT_REVIEW_TIER review 6562490492 on PR #28753 (merged as a00f3359, closing #28251). Filed by domain:server seat 3. ⛔ Not a claim.
Wanted
Refusal wording.packages/spec/src/automation/save-notice-placement.ts: a start node whose config.triggerType is an array is refused, which is the right verdict (the array form is unsupported and never binds, flow record trigger: consider multi-event triggerType (array / unions beyond create-or-update) #3457). The sentence says the flow "has no record trigger", which misnames the shape. Name the array form in the prescription and say to use one trigger type. Pin the sentence.
Persisted round-trip test. The accepted HotCRM shape runs save_notice ahead of an approval in a record-triggered run. The run suspends with the channel in its context. It is persisted through a SuspendedRunStore; JSON drops the function, leaving { locale }. Then it resumes. Pin end to end that the original write's answer carried the notice and that a save_notice on the resumed leg refuses by name. Today the in-memory closed-channel and no-channel cases are pinned, but the persisted round trip is only reasoned.
Lint record-of-readings lists.packages/lint/src/lint-flow-patterns.tsINERT_CONDITION_NODE_TYPES and FALLIBLE_NODE_TYPES are lists that every new builtin has to be checked into, and neither names save_notice. Decide its row in each list and add it, with the reason.
⛔ No change to the save-notice contract, the placement rule or the wire notice.
Dedupe
Read the open titles for save_notice, ctx.notice and save notice: none besides #28251 (closed). New.
Reader who acts: domain:server (packages/spec automation, packages/services/service-automation, packages/lint).
Ruling-ref: the maintainer, 2026-11-01T12:11Z: 「定级你可以自己决定」.
Class: hardening follow-ups of a landed feature. No wrong answer is served today: the array case is refused with the right verdict, the persisted round trip is reasoned correct, and the lint lists only miss a classification. p3.
Direction: the three items as filed, in one PR. Wording pin, one persisted-store integration test, and the lint list rows. Expected Clause-②: no, Metadata-protocol: none.
Claim: PM loop round 1 · card thread · 2026-11-01T19:46Z
Session: session_01FEkQ5kE5BrPUPNMMyv6oCH (the seat); the card thread is session_01FEkQ5omF1nCbQTGgW1nbRA
Account: os-project-manager (the seat's linked user; the card's assignee)
Branch: claude/project-thread-9kerqb (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
Worktree: the card thread's own container checkout
Domain: domain:server
Seat: domain:server#3
Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」, and 2026-11-01T06:39Z 「server 队列还是很多任务,再开一个席位吧」. Seat 3 graded it p3 under 2026-11-01T12:11Z 「定级你可以自己决定」.
File surface: packages/spec/src/automation/save-notice-placement.ts (the refusal sentence) and its pin, packages/services/service-automation/** tests (one persisted round-trip integration test), packages/lint/src/lint-flow-patterns.ts and its tests, and changesets. ⛔ No ui/**; ⛔ no change to the save-notice contract.
Container & model: S, mode:thread, model: opus (--tier names no path mandate: PM's call, default), effort: default (the coordinator sets effort only from the maintainer's words)
Clause-②: no — expected: a wording fix on an existing refusal, a coverage test and lint classification rows; nothing accepted or refused differently. The dev measures and declares.
Metadata-protocol: none (expected; the dev measures and declares)
Responsibility: the code is packages/spec save-notice placement, service-automation suspend/resume, packages/lint flow patterns · the platform path is a record-triggered flow with save_notice before an approval · reached by publishing or running such a flow
Thread-read: 6562950408
Premise: holds as filed (read by the #28753 review at 36c1fb8f); the dev re-reads on main at a00f3359 or later
Serial constraints cleared: none: PR #28753 merged as a00f3359; the dev re-reads overlap at start and before pr_create.
Resume-from: none — the branch restarts from origin/main at a00f3359 or later (its PR #28753 is merged)
State: → pm:dispatched, assigned to os-project-manager, recorded by this claim. Order: pm-orders/server/order-28786.md (project folder).
domain:server#3 · os-project-manager · session_01FEkQ5omF1nCbQTGgW1nbRA
os-dev-report
{
"issue": 28786,
"status": "done",
"branch": "claude/project-thread-9kerqb",
"pr": "#28805",
"head": "6f15ad27f7406f90547af738b90b99797147bbb3",
"session": "session_01FEkQ5omF1nCbQTGgW1nbRA",
"premise_still_valid": true,
"summary": "The three should-fixes of review 6562490492. (1) save-notice-placement.ts names the array triggerType form in its refusal (quotes the array, says it never binds, asks for ONE trigger type, record-after-write for create-or-update); verdict unchanged, sentence pinned with the issue code and path. (2) New plugin-approvals integration test over the real ObjectStoreSuspendedRunStore (kernel: ObjectQLPlugin + SqlDriver, AutomationServicePlugin default store, RecordChangeTriggerPlugin; real ApprovalService on the real engine): record-after-create -> save_notice -> approval -> save_notice. The create's onNotice heard the sentence; the paused sys_automation_run row's context_json holds no saveNotice.set; the decision resumes from the store and the second save_notice refuses by name ('this run holds no record write to answer'), the history row is failed with that error, and decide throws the existing stranded-decision failure naming it. The round trip behaved as the order reasoned: no defect. (3) lint-flow-patterns.ts: save_notice joins INERT_CONDITION_NODE_TYPES and FALLIBLE_NODE_TYPES, each by reading its executor.",
"tests": {
"red_first": [
"spec save-notice-node.test.ts array-form pin: 1 failed of 18 before, 18/18 after",
"lint lint-flow-patterns.test.ts inert-condition + fallible readings: 2 failed before, 245/245 after"
],
"ablation": "item 2 coverage pin: service-automation dist/index.js no-channel refuseNode -> return { success: true } (ablation-replace anchor 1->0, blob ea8be53d -> b587fb82): round-trip test red (decide did not throw); restored by hand to blob ea8be53d (ablation-replace cannot restore an untracked dist file), green again",
"suites": {
"@objectstack/spec vitest run": "exit 0",
"@objectstack/lint vitest run": "exit 0",
"@objectstack/plugin-approvals vitest run": "exit 0"
}
},
"gates": {
"derived": 84,
"run": 84,
"not_measured": 0,
"unrun": 0,
"reconcile": "dispatch-gates --ran exit 0",
"note": "5 first exited 3 (prerequisite not met: 4 spec gates on a dist older than a later test edit, check:dual-build-cjs-loads missing dists); rebuilt and reran, all exit 0",
"eslint": "--no-inline-config over packages/spec packages/lint packages/plugins/plugin-approvals: exit 0"
},
"dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
"line_budget": "no budget in the order; diff 6 files changed, 265 insertions(+), 5 deletions(-) (hand-written non-test about 25 lines; the rest tests and the changeset)",
"deviations": [
"Item 2 ablation was made on service-automation's built dist/index.js, the file the plugin-approvals test resolves, not on src; restore verified by blob hash.",
"The round-trip test does not pin the terminal row's node_id: the store records the suspension node ('ask') there, not the failing one; the error text names tell_after."
],
"files_changed": [
".changeset/28786-save-notice-follow-ups.md",
"packages/lint/src/lint-flow-patterns.test.ts",
"packages/lint/src/lint-flow-patterns.ts",
"packages/plugins/plugin-approvals/src/save-notice-approval-round-trip.integration.test.ts",
"packages/spec/src/automation/save-notice-node.test.ts",
"packages/spec/src/automation/save-notice-placement.ts"
],
"mcp_calls": "2: mcp__github__issue_read x2 (get #28786, get_comments #28786); no write tool",
"api_writes": "3 of 3: git push (new branch, the merged branch had been auto-deleted), fleet-write pr_create (run 41349097955, draft PR #28805, no labels, no assignees, read-back identical 6393 bytes), this report comment (post-stamped.mjs). No GitHub MCP writes.",
"open_questions": [],
"out_of_scope_findings": [
"A save_notice placed after an approval in a record-triggered flow passes the parse (it cannot see where a run suspends); at run time the approver's decision is recorded and decide answers RESUME_FAILED (stranded decision) naming the node. Pinned as is, not changed. A static lint finding for a save_notice downstream of a suspending node would catch it at authoring, but that is a new gate, so not proposed."
]
}
Activity
objectstack-fleet commentedon Nov 1, 2026
domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH
Path: 能用的自动化 | none | P③
Triage: p3 ·
domain:server·area:automation· 2026-11-01T19:44Z⛔ Not a claim.
Clause-②: no,Metadata-protocol: none.objectstack-fleet commentedon Nov 1, 2026
domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH
Claim: PM loop round 1 · card thread · 2026-11-01T19:46Z
Session:
session_01FEkQ5kE5BrPUPNMMyv6oCH(the seat); the card thread issession_01FEkQ5omF1nCbQTGgW1nbRAAccount:
os-project-manager(the seat's linked user; the card's assignee)Branch:
claude/project-thread-9kerqb(the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)Worktree: the card thread's own container checkout
Domain:
domain:serverSeat:
domain:server#3Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」, and 2026-11-01T06:39Z 「server 队列还是很多任务,再开一个席位吧」. Seat 3 graded it p3 under 2026-11-01T12:11Z 「定级你可以自己决定」.
File surface:
packages/spec/src/automation/save-notice-placement.ts(the refusal sentence) and its pin,packages/services/service-automation/**tests (one persisted round-trip integration test),packages/lint/src/lint-flow-patterns.tsand its tests, and changesets. ⛔ Noui/**; ⛔ no change to the save-notice contract.Container & model:
S,mode:thread,model: opus(--tiernames no path mandate: PM's call, default),effort: default (the coordinator sets effort only from the maintainer's words)Clause-②: no — expected: a wording fix on an existing refusal, a coverage test and lint classification rows; nothing accepted or refused differently. The dev measures and declares.
Metadata-protocol: none (expected; the dev measures and declares)
Responsibility: the code is
packages/specsave-notice placement,service-automationsuspend/resume,packages/lintflow patterns · the platform path is a record-triggered flow withsave_noticebefore anapproval· reached by publishing or running such a flowThread-read: 6562950408
Premise: holds as filed (read by the #28753 review at
36c1fb8f); the dev re-reads onmainata00f3359or laterSerial constraints cleared: none: PR #28753 merged as
a00f3359; the dev re-reads overlap at start and beforepr_create.Resume-from: none — the branch restarts from
origin/mainata00f3359or later (its PR #28753 is merged)State: →
pm:dispatched, assigned toos-project-manager, recorded by this claim. Order:pm-orders/server/order-28786.md(project folder).objectstack-fleet commentedon Nov 1, 2026
domain:server#3 · os-project-manager · session_01FEkQ5omF1nCbQTGgW1nbRA
os-dev-report
{
"issue": 28786,
"status": "done",
"branch": "claude/project-thread-9kerqb",
"pr": "#28805",
"head": "6f15ad27f7406f90547af738b90b99797147bbb3",
"session": "session_01FEkQ5omF1nCbQTGgW1nbRA",
"premise_still_valid": true,
"summary": "The three should-fixes of review 6562490492. (1) save-notice-placement.ts names the array triggerType form in its refusal (quotes the array, says it never binds, asks for ONE trigger type, record-after-write for create-or-update); verdict unchanged, sentence pinned with the issue code and path. (2) New plugin-approvals integration test over the real ObjectStoreSuspendedRunStore (kernel: ObjectQLPlugin + SqlDriver, AutomationServicePlugin default store, RecordChangeTriggerPlugin; real ApprovalService on the real engine): record-after-create -> save_notice -> approval -> save_notice. The create's onNotice heard the sentence; the paused sys_automation_run row's context_json holds no saveNotice.set; the decision resumes from the store and the second save_notice refuses by name ('this run holds no record write to answer'), the history row is failed with that error, and decide throws the existing stranded-decision failure naming it. The round trip behaved as the order reasoned: no defect. (3) lint-flow-patterns.ts: save_notice joins INERT_CONDITION_NODE_TYPES and FALLIBLE_NODE_TYPES, each by reading its executor.",
"tests": {
"red_first": [
"spec save-notice-node.test.ts array-form pin: 1 failed of 18 before, 18/18 after",
"lint lint-flow-patterns.test.ts inert-condition + fallible readings: 2 failed before, 245/245 after"
],
"ablation": "item 2 coverage pin: service-automation dist/index.js no-channel refuseNode -> return { success: true } (ablation-replace anchor 1->0, blob ea8be53d -> b587fb82): round-trip test red (decide did not throw); restored by hand to blob ea8be53d (ablation-replace cannot restore an untracked dist file), green again",
"suites": {
"@objectstack/spec vitest run": "exit 0",
"@objectstack/lint vitest run": "exit 0",
"@objectstack/plugin-approvals vitest run": "exit 0"
}
},
"gates": {
"derived": 84,
"run": 84,
"not_measured": 0,
"unrun": 0,
"reconcile": "dispatch-gates --ran exit 0",
"note": "5 first exited 3 (prerequisite not met: 4 spec gates on a dist older than a later test edit, check:dual-build-cjs-loads missing dists); rebuilt and reran, all exit 0",
"eslint": "--no-inline-config over packages/spec packages/lint packages/plugins/plugin-approvals: exit 0"
},
"dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
"line_budget": "no budget in the order; diff 6 files changed, 265 insertions(+), 5 deletions(-) (hand-written non-test about 25 lines; the rest tests and the changeset)",
"deviations": [
"Item 2 ablation was made on service-automation's built dist/index.js, the file the plugin-approvals test resolves, not on src; restore verified by blob hash.",
"The round-trip test does not pin the terminal row's node_id: the store records the suspension node ('ask') there, not the failing one; the error text names tell_after."
],
"files_changed": [
".changeset/28786-save-notice-follow-ups.md",
"packages/lint/src/lint-flow-patterns.test.ts",
"packages/lint/src/lint-flow-patterns.ts",
"packages/plugins/plugin-approvals/src/save-notice-approval-round-trip.integration.test.ts",
"packages/spec/src/automation/save-notice-node.test.ts",
"packages/spec/src/automation/save-notice-placement.ts"
],
"mcp_calls": "2: mcp__github__issue_read x2 (get #28786, get_comments #28786); no write tool",
"api_writes": "3 of 3: git push (new branch, the merged branch had been auto-deleted), fleet-write pr_create (run 41349097955, draft PR #28805, no labels, no assignees, read-back identical 6393 bytes), this report comment (post-stamped.mjs). No GitHub MCP writes.",
"open_questions": [],
"out_of_scope_findings": [
"A save_notice placed after an approval in a record-triggered flow passes the parse (it cannot see where a run suspends); at run time the approver's decision is recorded and decide answers RESUME_FAILED (stranded decision) naming the node. Pinned as is, not changed. A static lint finding for a save_notice downstream of a suspending node would catch it at authoring, but that is a new gate, so not proposed."
]
}
objectstack-fleet commentedon Nov 1, 2026
domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH
PR #28805 accepted (seat ACCEPT #28805 (comment), contract review PASS #28805 (comment)) and enqueued for merge. Landing record follows after merge.
objectstack-fleet commentedon Nov 1, 2026
domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH
Landing record · #28786 · PR #28805
domain:serverseat 3 ·session_01FEkQ5kE5BrPUPNMMyv6oCH· 2026-11-01T21:38Zgit ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-28805-*'git merge-base --is-ancestor 70943dd6 origin/maingit grep -n "describe('\[#28786\]" origin/main -- packages/plugins/plugin-approvals/src/save-notice-approval-round-trip.integration.test.ts70943dd6. The three should-fixes from the Save notice from a sandboxed hook or a flow: hook context and flow node set the write answer's notice #28251 contract review are onmain:triggerTyperefusal now names the array form;save_notice→ approval suspend → resume;save_notice.CONTRACT_REVIEW_TIER): PASS6563799258on the landed head6f15ad27. Seat ACCEPT6564001429.Fixes #28786closed this card on merge.save_noticeplaced after a suspending node strands every decision) is automation: a save_notice placed after an approval, wait or screen node passes publish and then strands every decision with RESUME_FAILED #28806. It unblocks now and is dispatched next.