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
notify: a written-out email address no user holds, on a node that does not name the email channel, writes an inbox row nobody can read and the node reports success #25758
Filing gate ③, a finding a contract review escalated: the ## Contract review of PR #25739 (6395784809, card #25696, flag F2) raised it as an authoring trap needing a carrier. Filed by domain:spec seat 2 (seat post #18549) · sunhaolin · session session_01PC4NPXPgPmpDRG9DdDnyXT. ⛔ Not a claim. Grade and domain are triage's. The seat suggests domain:server (messaging), and domain:spec if the fix is an authoring rule.
The trap (measured on main5874d25302)
Ruling B on #25647 (6386629237) makes an address written out in recipients an author constant, "sent as written". On a node whose channels include email, that holds: RecipientResolver.resolveOne → resolveEmail maps the address to the user who holds it, or keeps it verbatim on a miss, and the email channel mails a verbatim address (email-channel.tsEMAIL_SHAPE(recipient) branch).
On a node that does not name email, a verbatim address goes to the inbox channel, which is the messaging default when channels is absent:
packages/services/service-messaging/src/inbox-channel.ts:149 reads const userId = delivery.recipient;, and :205 writes the row with user_id: userId. There is no check that the value is a user id.
So recipients: 'exec@example.com' with no user holding that address writes a sys_inbox_message row whose user_id is the address string. No user's inbox query matches it. The delivery is recorded and the node reports success.
Live instance:examples/app-showcase/src/automation/flows/index.ts node alert_exec (around :1435): recipients: 'exec@example.com', no channels, so inbox only. The "Alert Exec" branch of that flow notifies nobody.
The #25696 describe text (PR #25739) claims nothing for this case, so it is not false. It is a silent no-op that an author, or an AI writing a flow, will not notice.
Fix directions (not chosen here)
A. Refuse at authoring. A notify node whose recipients writes out an email-shaped string, and whose channels do not include email, is refused at os validate / publish, with a message pointing to channels: 'email' or to a user id. This is loud and contract-first. It is a narrowing, so the in-repo producer above changes.
B. Refuse at delivery. The inbox channel refuses, or dead-letters, a recipient that is not a user id. This is loud at run time, but only after a run.
C. Do both.
Dedupe
Searched repo:objectstack-ai/objectstack notify recipient written-out email address inbox only channel no user: no open card covers it. #17611 (email delivery with no transport, closed) is a different path. New.
Claim: PM loop round 5 · card thread
Session: session_01R1q2xdtYgU6FKrZ7LgjPCC (the seat); the card thread is session_01GUgFY2BFn32b13fpwkZ3Jk
Account: os-project-manager (the seat's linked user; the card's assignee)
Branch: claude/project-thread-hdpxcs (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
Worktree: objectstack-issue-25758 (a linked worktree in the card thread's container)
Domain: domain:server
Seat: domain:server#1
Ruling-ref: triage 6396218293 (server half: the runtime stops reporting success); seat ruling between its two runtime arms: fail loud with a located message naming the node, the recipient and the fix, never re-route to an undeclared channel; ruling B on #25647 (6386629237) unchanged on email nodes
File surface: packages/services/service-messaging/src/** (the recipient resolver, the notify path and the channels that take a user id), the notify node's runtime in packages/services/service-automation/src/** if the failure is recorded there, examples/app-showcase/src/automation/flows/index.ts (node alert_exec, the live producer), their tests, one patch changeset. ⛔ No packages/spec/** (refusal at os validate / publish is a domain:spec card; stop on breach and explain in the report)
Container & model: M, mode:thread, default model and effort (set at thread open)
Clause-②: no
Metadata-protocol: none
Responsibility: a written-out address on a notify node that does not name email writes a sys_inbox_message row with the address in user_id, which no inbox reads, and the node reports success (inbox-channel.ts:149, :205)
Thread-read: 6396218293
Premise: holds (read 2026-10-26T05:23Z at origin/main17c5e68b: card open, unassigned, pm:queue, no other seat's claim; the dev reproduces red first)
Serial constraints cleared: no open PR names #25758; the dev measures overlap with open PRs on service-messaging before pr_create
{
"issue": 25758,
"status": "done",
"branch": "claude/project-thread-hdpxcs",
"pr": "https://github.com/objectstack-ai/objectstack/pull/25964",
"session": "session_01GUgFY2BFn32b13fpwkZ3Jk",
"premise_still_valid": true,
"summary": "A notify node whose channels do not include email (inbox default, inbox, sms) now fails when its recipients write out an email address no user holds, or write one as user:ADDRESS, naming the node, each such recipient and the fix (add email to channels, or name a user: user id, audience selector such as role:NAME, or the address a user holds, bare). Nothing is written and the email channel is never added. The check lives in the notify node (notify-node.ts refuseUndeliverableAddresses), the one place that knows both the recipient's provenance and the node's channels; no channel changes. Measured channels on main: inbox keys any value as user_id silently; sms takes a user id or literal phone and already fails an address at delivery; email takes either. Showcase alert_exec now notifies role:owner: the showcase's mail goes through plugin-email's default log transport, so adding email would only log a mail to example.com, while role:owner reaches the Default Organization's admin. DEPARTURE FROM THE CLAIM: the claim's line reads 'Clause-②: no' with no arm; measured against AGENTS.md this is a run-time narrowing (a run that completed now fails at this node), so the PR body and changeset carry 'Clause-②: no (narrowing: ...)' with 'Metadata-protocol: none' and patch, following PR #25954 and the run-time half in .changeset/25572-*. The contract review is owed before the queue. Reading chosen: the ruling's 'written-out address' is read as the card's title, an address no user holds; an address a user holds still reaches that user's inbox.",
"tests": "Red first at fc0c961b on main 17c5e68b: new notify-written-address-channels.integration.test.ts 7 failed / 3 passed (each failure 'expected true to be false' on run.success). Fixed head 011221d3: service-automation test 204 files / 2677 passed, typecheck with check:test-typecheck exit 0; example-showcase test 39 files / 484 passed, typecheck exit 0 (after building its closure); eslint --no-inline-config on the 3 changed TS files exit 0. Ablation via scripts/ablation-replace.mjs at 47c6ea05 (anchor 'written.length === 0' to a greater-or-equal-zero test, hit 1 to 0, blob 33f2d3a7 to 08cf50f0; the test imports the node from src, no dist in the path): 7 failed / 26 passed across the new suite and the email-field suite, the 7 exactly the refusal cases; restore blob 33f2d3a7 == HEAD, git diff HEAD empty.",
"gates": "dispatch-gates --commands at 011221d3: 79 families, all run on that head with exit 0 captured before any pipe; --ran reconciliation: 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN. Earlier pass (47c6ea05) found check:where-matcher red on the new test's data-engine double (a combinator read as a field name) and check:engine-double-contract asking for a ledger row: both fixed (011221d3, e6878f86). PR check-runs on 011221d3: 46 total, 36 success, 10 skipped (UI lanes, opt-in harnesses, Build Docs), 0 failed: Test Core and its 8 shards, Build Core, Dogfood Regression Gate, TypeScript Type Check, Lint & Repo Gates, Lint · ESLint, Check Changeset, The card this PR closes must claim this branch, No other open PR may claim the same issue, Governed Surface Queue Guard all success.",
"dogfood_battery": "47c6ea05 · os-verify-lock VERDICT command-exit 0 (pnpm --filter @objectstack/dogfood test, closure built) · Test Files 296 passed, 3 skipped (299) · Tests 2523 passed, 18 skipped (2541) · no failures. Later commits e6878f86 and 011221d3 touch only the engine-double ledger json and the new test's double; not re-run.",
"mcp_calls": "3 — mcp__github__issue_read get, mcp__github__issue_read get_comments, mcp__github__pull_request_read get_check_runs (all reads)",
"api_writes": "2 — fleet-write relay pr_create (objectstack-ai/objectstack, PR #25964, assignees os-project-manager, read back identical) and this os-dev-report comment via post-stamped.mjs; plus git push (not REST). Unauthenticated public GETs read rulings 6386629237 and 6393736930 and PR #25954's body.",
"open_questions": [
{
"status": "needs_decision",
"question": "Should a COMPUTED recipient that evaluates to an address no user holds, on a notify node that does not name email, also fail the node? Today it still writes an inbox row whose user_id is the address and the node reports success, the same silent no-op this card fixes for written-out addresses. Ruling A on #25647 (6393736930) says computed recipients on such nodes are not screened, so this PR leaves them.",
"options": [
"A: keep as is. Written-out addresses fail; computed ones on inbox/sms nodes stay silent.",
"B: extend the same deliverability check to computed recipients on nodes without email (about 5 lines in refuseUndeliverableAddresses, same lookup, message points to the record's value or channels: email / emailField)."
],
"recommendation": "B. Real business need: live producers exist; app-showcase notify nodes over record.owner / record.assignee evaluate to email addresses on inbox-only nodes, so a hand-entered owner that is not a user loses the notification silently today (seeded owners are provisioned, pinned by inert-wirings.test.ts). Long-term soundness: one rule, 'a node without email delivers only to users', instead of a provenance split where the same address fails written and succeeds silently computed. AI-error resistance: fail loud beats the silent tolerance that hides batch mistakes. Startup focus: no new gate, no new surface, a few lines in the check this PR adds. Cost: it refines ruling A's wording, which was about the mail-security screen, not deliverability, so it is the maintainer's call."
}
],
"out_of_scope_findings": [
"carrier: the domain:spec half of #25758 (direction A, refusal at os validate / publish) · noted, not filed · @objectstack/spec io-node-config.zod.ts recipients describe text says a written-out address goes 'to the user who holds it, or else, on the email channel, to the address itself' and does not say a node without email now fails",
"承接者:无 · noted in PR Acceptance notes, not filed · a node whose channels include both inbox and email mails an unheld written-out address as written (ruling B) and its inbox delivery still writes a row whose user_id is the address; no in-repo producer names both channels"
]
}
{
"issue": 25758,
"status": "done",
"branch": "claude/project-thread-hdpxcs",
"pr": "https://github.com/objectstack-ai/objectstack/pull/25964",
"session": "session_01GUgFY2BFn32b13fpwkZ3Jk",
"premise_still_valid": true,
"summary": "Rework round after contract review 6411272864 (FAIL), on the maintainer's option B. Head 45c95ee3. Since the first report (6410135308): d352c68a judges a computed address on a notify node without email like a written-out one (named by its envelope source, never its value); 55f6fc27 fixes a showcase test that pinned the junk inbox row; d0e593bb + 45c95ee3 answer F1: notify_cleared (showcase_invoice_signoff) notified record.owner, and the seeded invoice owners ada@/linus@/grace@example.com are deliberately not users (ADR-0055 isolation fixture; packages/qa/dogfood/test/showcase-invoice-seed-isolation.dogfood.test.ts signs UP as ada@example.com, which a provisioned user would refuse), so provisioning them would delete that demo. The node now notifies role:owner, the Default Organization's admin on a dev boot (ensure-default-organization.ts), who also holds the finance and legal positions that clear the request. approval-resume-relation-expand.test.ts now boots the dev-boot directory (admin as owner member, a provisioned persona) and approves the app's own INV-1010 seed row, whose owner holds no account, through notify_cleared to end_ok, asserting the notice lands in the admin's inbox. The changeset's Who-moves now names alert_exec, notify_cleared and why, the provisioned project/task owners, and (F6) the four admin@objectos.ai inbox nodes digest, log_fail, notify_done, report: they deliver on a dev boot and fail loud on a boot without that user. F5 (inbox+email junk row) is left to the seat, per the seat.",
"tests": "B red first at 011221d3: 3 computed refusal cases failed, 2 controls passed. F1 red at d0e593bb (test only, flow unchanged): the seeded-INV-1010 approval failed with RESUME_FAILED at notify_cleared ('names channels inbox and not email, and has a recipient no user receives'), 11 other cases passed; green at 45c95ee3. At 45c95ee3: example-showcase 39 files / 484 passed, typecheck exit 0; service-automation 204 files / 2682 passed, typecheck exit 0 (run at d352c68 + wording fix 55f6fc27; 45c95ee3 touches only showcase files); eslint on changed files exit 0. Ablation of B (delete the computed push into addressed): 5 failed (3 new computed cases + E5 x2), 33 passed; restore blob == HEAD, git diff HEAD empty.",
"gates": "dispatch-gates --commands at 45c95ee3: 79 families, all exit 0 captured before any pipe; --ran: 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN. PR check-runs on 45c95ee3: 47 total, 36 success, 11 skipped, 0 failed (Test Core and its 8 shards, Build Core, Dogfood Regression Gate, TypeScript Type Check, Lint & Repo Gates, Check Changeset all success).",
"dogfood_battery": "45c95ee3 · os-verify-lock VERDICT command-exit 0 (pnpm --filter @objectstack/dogfood test, service-automation dist rebuilt with B) · Test Files 296 passed, 3 skipped (299) · Tests 2523 passed, 18 skipped (2541) · no failures. Also green at d352c68 (same counts).",
"mcp_calls": "0 this round (3 reads in the first round, no writes)",
"api_writes": "1 this round — this os-dev-report comment via post-stamped.mjs; total 3 (pr_create, report 6410135308, this one); plus git pushes. PR body not patched by the dev (os-dev: written once); the seat holds the body edits.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: the domain:spec half of #25758 · noted, not filed · @objectstack/spec io-node-config.zod.ts recipients describe text does not say a node without email fails on an address no user holds, written out or computed",
"carrier: the server seat (F5, filing itself) · inbox+email node: unheld address mailed as written and a junk inbox row still written"
],
"deviations": "B shipped as two commits (d352c68a, 55f6fc27), not one: the showcase consequence was found after the first push, and force-push needs AGENTS.md §3. F1 added d0e593bb (red test) and 45c95ee3 (flow + changeset)."
}
State: this card closed by Fixes (completed); pm:dispatched removed. Option B as ruled; #25990 (both-channels inbox row) is dispatched on top of it (claim 6412253095).
Activity
objectstack-fleet commentedon Oct 25, 2026
Triage: first grade —
bug·priority:p2·domain:server·area:workflow·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-25T09:57Z⛔ Not a claim, ⛔ not a dispatch.
domain:speccard.Generated by Claude Code
objectstack-fleet commentedon Oct 26, 2026
Claim: PM loop round 5 · card thread
Session:
session_01R1q2xdtYgU6FKrZ7LgjPCC(the seat); the card thread issession_01GUgFY2BFn32b13fpwkZ3JkAccount:
os-project-manager(the seat's linked user; the card's assignee)Branch:
claude/project-thread-hdpxcs(the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)Worktree:
objectstack-issue-25758(a linked worktree in the card thread's container)Domain:
domain:serverSeat:
domain:server#1Ruling-ref: triage 6396218293 (server half: the runtime stops reporting success); seat ruling between its two runtime arms: fail loud with a located message naming the node, the recipient and the fix, never re-route to an undeclared channel; ruling B on #25647 (6386629237) unchanged on email nodes
File surface:
packages/services/service-messaging/src/**(the recipient resolver, the notify path and the channels that take a user id), the notify node's runtime inpackages/services/service-automation/src/**if the failure is recorded there,examples/app-showcase/src/automation/flows/index.ts(nodealert_exec, the live producer), their tests, onepatchchangeset. ⛔ Nopackages/spec/**(refusal atos validate/ publish is adomain:speccard; stop on breach and explain in the report)Container & model:
M,mode:thread, default model and effort (set at thread open)Clause-②: no
Metadata-protocol: none
Responsibility: a written-out address on a notify node that does not name
emailwrites asys_inbox_messagerow with the address inuser_id, which no inbox reads, and the node reports success (inbox-channel.ts:149,:205)Thread-read: 6396218293
Premise: holds (read 2026-10-26T05:23Z at
origin/main17c5e68b: card open, unassigned,pm:queue, no other seat's claim; the dev reproduces red first)Serial constraints cleared: no open PR names #25758; the dev measures overlap with open PRs on
service-messagingbeforepr_createobjectstack-fleet commentedon Oct 26, 2026
os-dev-report
{ "issue": 25758, "status": "done", "branch": "claude/project-thread-hdpxcs", "pr": "https://github.com/objectstack-ai/objectstack/pull/25964", "session": "session_01GUgFY2BFn32b13fpwkZ3Jk", "premise_still_valid": true, "summary": "A notify node whose channels do not include email (inbox default, inbox, sms) now fails when its recipients write out an email address no user holds, or write one as user:ADDRESS, naming the node, each such recipient and the fix (add email to channels, or name a user: user id, audience selector such as role:NAME, or the address a user holds, bare). Nothing is written and the email channel is never added. The check lives in the notify node (notify-node.ts refuseUndeliverableAddresses), the one place that knows both the recipient's provenance and the node's channels; no channel changes. Measured channels on main: inbox keys any value as user_id silently; sms takes a user id or literal phone and already fails an address at delivery; email takes either. Showcase alert_exec now notifies role:owner: the showcase's mail goes through plugin-email's default log transport, so adding email would only log a mail to example.com, while role:owner reaches the Default Organization's admin. DEPARTURE FROM THE CLAIM: the claim's line reads 'Clause-②: no' with no arm; measured against AGENTS.md this is a run-time narrowing (a run that completed now fails at this node), so the PR body and changeset carry 'Clause-②: no (narrowing: ...)' with 'Metadata-protocol: none' and patch, following PR #25954 and the run-time half in .changeset/25572-*. The contract review is owed before the queue. Reading chosen: the ruling's 'written-out address' is read as the card's title, an address no user holds; an address a user holds still reaches that user's inbox.", "tests": "Red first at fc0c961b on main 17c5e68b: new notify-written-address-channels.integration.test.ts 7 failed / 3 passed (each failure 'expected true to be false' on run.success). Fixed head 011221d3: service-automation test 204 files / 2677 passed, typecheck with check:test-typecheck exit 0; example-showcase test 39 files / 484 passed, typecheck exit 0 (after building its closure); eslint --no-inline-config on the 3 changed TS files exit 0. Ablation via scripts/ablation-replace.mjs at 47c6ea05 (anchor 'written.length === 0' to a greater-or-equal-zero test, hit 1 to 0, blob 33f2d3a7 to 08cf50f0; the test imports the node from src, no dist in the path): 7 failed / 26 passed across the new suite and the email-field suite, the 7 exactly the refusal cases; restore blob 33f2d3a7 == HEAD, git diff HEAD empty.", "gates": "dispatch-gates --commands at 011221d3: 79 families, all run on that head with exit 0 captured before any pipe; --ran reconciliation: 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN. Earlier pass (47c6ea05) found check:where-matcher red on the new test's data-engine double (a combinator read as a field name) and check:engine-double-contract asking for a ledger row: both fixed (011221d3, e6878f86). PR check-runs on 011221d3: 46 total, 36 success, 10 skipped (UI lanes, opt-in harnesses, Build Docs), 0 failed: Test Core and its 8 shards, Build Core, Dogfood Regression Gate, TypeScript Type Check, Lint & Repo Gates, Lint · ESLint, Check Changeset, The card this PR closes must claim this branch, No other open PR may claim the same issue, Governed Surface Queue Guard all success.", "dogfood_battery": "47c6ea05 · os-verify-lock VERDICT command-exit 0 (pnpm --filter @objectstack/dogfood test, closure built) · Test Files 296 passed, 3 skipped (299) · Tests 2523 passed, 18 skipped (2541) · no failures. Later commits e6878f86 and 011221d3 touch only the engine-double ledger json and the new test's double; not re-run.", "mcp_calls": "3 — mcp__github__issue_read get, mcp__github__issue_read get_comments, mcp__github__pull_request_read get_check_runs (all reads)", "api_writes": "2 — fleet-write relay pr_create (objectstack-ai/objectstack, PR #25964, assignees os-project-manager, read back identical) and this os-dev-report comment via post-stamped.mjs; plus git push (not REST). Unauthenticated public GETs read rulings 6386629237 and 6393736930 and PR #25954's body.", "open_questions": [ { "status": "needs_decision", "question": "Should a COMPUTED recipient that evaluates to an address no user holds, on a notify node that does not name email, also fail the node? Today it still writes an inbox row whose user_id is the address and the node reports success, the same silent no-op this card fixes for written-out addresses. Ruling A on #25647 (6393736930) says computed recipients on such nodes are not screened, so this PR leaves them.", "options": [ "A: keep as is. Written-out addresses fail; computed ones on inbox/sms nodes stay silent.", "B: extend the same deliverability check to computed recipients on nodes without email (about 5 lines in refuseUndeliverableAddresses, same lookup, message points to the record's value or channels: email / emailField)." ], "recommendation": "B. Real business need: live producers exist; app-showcase notify nodes over record.owner / record.assignee evaluate to email addresses on inbox-only nodes, so a hand-entered owner that is not a user loses the notification silently today (seeded owners are provisioned, pinned by inert-wirings.test.ts). Long-term soundness: one rule, 'a node without email delivers only to users', instead of a provenance split where the same address fails written and succeeds silently computed. AI-error resistance: fail loud beats the silent tolerance that hides batch mistakes. Startup focus: no new gate, no new surface, a few lines in the check this PR adds. Cost: it refines ruling A's wording, which was about the mail-security screen, not deliverability, so it is the maintainer's call." } ], "out_of_scope_findings": [ "carrier: the domain:spec half of #25758 (direction A, refusal at os validate / publish) · noted, not filed · @objectstack/spec io-node-config.zod.ts recipients describe text says a written-out address goes 'to the user who holds it, or else, on the email channel, to the address itself' and does not say a node without email now fails", "承接者:无 · noted in PR Acceptance notes, not filed · a node whose channels include both inbox and email mails an unheld written-out address as written (ruling B) and its inbox delivery still writes a row whose user_id is the address; no in-repo producer names both channels" ] }Generated by Claude Code
fix(service-automation)!: a notify node that does not name email also…
objectstack-fleet commentedon Oct 26, 2026
os-dev-report
{ "issue": 25758, "status": "done", "branch": "claude/project-thread-hdpxcs", "pr": "https://github.com/objectstack-ai/objectstack/pull/25964", "session": "session_01GUgFY2BFn32b13fpwkZ3Jk", "premise_still_valid": true, "summary": "Rework round after contract review 6411272864 (FAIL), on the maintainer's option B. Head 45c95ee3. Since the first report (6410135308): d352c68a judges a computed address on a notify node without email like a written-out one (named by its envelope source, never its value); 55f6fc27 fixes a showcase test that pinned the junk inbox row; d0e593bb + 45c95ee3 answer F1: notify_cleared (showcase_invoice_signoff) notified record.owner, and the seeded invoice owners ada@/linus@/grace@example.com are deliberately not users (ADR-0055 isolation fixture; packages/qa/dogfood/test/showcase-invoice-seed-isolation.dogfood.test.ts signs UP as ada@example.com, which a provisioned user would refuse), so provisioning them would delete that demo. The node now notifies role:owner, the Default Organization's admin on a dev boot (ensure-default-organization.ts), who also holds the finance and legal positions that clear the request. approval-resume-relation-expand.test.ts now boots the dev-boot directory (admin as owner member, a provisioned persona) and approves the app's own INV-1010 seed row, whose owner holds no account, through notify_cleared to end_ok, asserting the notice lands in the admin's inbox. The changeset's Who-moves now names alert_exec, notify_cleared and why, the provisioned project/task owners, and (F6) the four admin@objectos.ai inbox nodes digest, log_fail, notify_done, report: they deliver on a dev boot and fail loud on a boot without that user. F5 (inbox+email junk row) is left to the seat, per the seat.", "tests": "B red first at 011221d3: 3 computed refusal cases failed, 2 controls passed. F1 red at d0e593bb (test only, flow unchanged): the seeded-INV-1010 approval failed with RESUME_FAILED at notify_cleared ('names channels inbox and not email, and has a recipient no user receives'), 11 other cases passed; green at 45c95ee3. At 45c95ee3: example-showcase 39 files / 484 passed, typecheck exit 0; service-automation 204 files / 2682 passed, typecheck exit 0 (run at d352c68 + wording fix 55f6fc27; 45c95ee3 touches only showcase files); eslint on changed files exit 0. Ablation of B (delete the computed push into addressed): 5 failed (3 new computed cases + E5 x2), 33 passed; restore blob == HEAD, git diff HEAD empty.", "gates": "dispatch-gates --commands at 45c95ee3: 79 families, all exit 0 captured before any pipe; --ran: 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN. PR check-runs on 45c95ee3: 47 total, 36 success, 11 skipped, 0 failed (Test Core and its 8 shards, Build Core, Dogfood Regression Gate, TypeScript Type Check, Lint & Repo Gates, Check Changeset all success).", "dogfood_battery": "45c95ee3 · os-verify-lock VERDICT command-exit 0 (pnpm --filter @objectstack/dogfood test, service-automation dist rebuilt with B) · Test Files 296 passed, 3 skipped (299) · Tests 2523 passed, 18 skipped (2541) · no failures. Also green at d352c68 (same counts).", "mcp_calls": "0 this round (3 reads in the first round, no writes)", "api_writes": "1 this round — this os-dev-report comment via post-stamped.mjs; total 3 (pr_create, report 6410135308, this one); plus git pushes. PR body not patched by the dev (os-dev: written once); the seat holds the body edits.", "open_questions": [], "out_of_scope_findings": [ "carrier: the domain:spec half of #25758 · noted, not filed · @objectstack/spec io-node-config.zod.ts recipients describe text does not say a node without email fails on an address no user holds, written out or computed", "carrier: the server seat (F5, filing itself) · inbox+email node: unheld address mailed as written and a junk inbox row still written" ], "deviations": "B shipped as two commits (d352c68a, 55f6fc27), not one: the showcase consequence was found after the first push, and force-push needs AGENTS.md §3. F1 added d0e593bb (red test) and 45c95ee3 (flow + changeset)." }Generated by Claude Code
objectstack-fleet commentedon Oct 26, 2026
Landed
PR #25964 merged at 2026-10-26T09:18Z by the merge queue as
b0384f3fe5onmain(Fixes #25758; ACCEPT6412184723).git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-25964-*'origin/mainby contentgit cat-file -e origin/main:packages/services/service-automation/src/builtin/notify-written-address-channels.integration.test.tsgit merge-base --is-ancestor b0384f3fe5 origin/mainState: this card closed by
Fixes(completed);pm:dispatchedremoved. Option B as ruled; #25990 (both-channels inbox row) is dispatched on top of it (claim6412253095).Generated by Claude Code