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
docs(adr-0142): amend D2 — a failed member read refuses for the D7 grant recompute and the D6 approver slate, and still answers nobody for admission consumers #29738
Filing gate: ② a maintainer decision. Warren picked option B on #29604 at 2026-11-03T03:05Z (decision card in the thread "Decide ruling for card #29604"). B runs in two PRs: this ADR amendment first, then the code on #29604. Sub-issue of #29604, so it carries the parent's domain. ⛔ Not a claim. Suggested-grade: p2, as the parent.
What the amendment says
Governing text: docs/adr/0142-ownership-queue-membership-claim-and-assignment-rules.md D2 ("An empty expansion is a fact, not a fault: the consumers below each say what they do with it"), D5 (a failed assignment read leaves the row and warns), D6 item 2 (empty slate warns and returns []), D7 item 1 (an empty queue grants nothing and warns).
Neither D2 nor D6/D7 says what happens when the member table behind a queue cannot be read. Today the expander answers "nobody", so the D7 grant pass is recomputed against an empty set and revokes every grant the queue gave, and a D6 slate shrinks. Every other sharing and approvals recipient read now refuses on a failed read (#29362, #29503 / PR #29602, #29606 / PR #29647).
Wanted
D2 separates an empty expansion (a fact) from a failed read (a fault), and names who reads which:
admission consumers — the access path (D3), the claim admission (D4), the assignment pool (D5) — keep "nobody" on a failed read, because answering nobody denies;
the D7 grant recompute and the D6 approver slate refuse on a failed read.
The status line gets an Amended (2026-11-03, #29604) note in the shape of the existing one.
Nothing else in the record moves. No code, no schema, no changeset in this PR.
Process
docs/adr/** is Tier H: this PR needs the maintainer's approval. It runs at the fable tier with effort xhigh, as the ruling set. The code half (#29604) is dispatched after this PR merges.
Dedupe: searched ADR-0142 D2 amend, queue failed read refuse; nearest is the parent #29604. New.
Claim: PM loop · ADR amendment · 2026-11-03T03:12Z
Session: session_01JQwxbacSXJQqAztgt4UMrS (seat); dev = card thread session_01JQwxbYJgdcYRwx5iQa5Ksc
Account: os-warren
Branch: claude/project-thread-xcbmm5 (a project card thread pushes only its assigned branch; measured platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-29738
Domain: domain:server (sub-issue of #29604, the parent's domain)
Seat: domain:server#4
File surface: docs/adr/0142-ownership-queue-membership-claim-and-assignment-rules.md only (D2, D6, D7 and the status line). ⛔ No code, schema or changeset (stop on breach; explain in the report).
Container & model: M, mode:thread, model: CONTRACT_REVIEW_TIER (Model tier — MANDATORY: claude-fable-5-1 (derived from the file surface, not recalled).), effort: xhigh (set by the maintainer's ruling B on #29604)
Clause-②: no (ADR text only; no published accept set moves)
Metadata-protocol: none
Responsibility: n/a — governed text, step 1 of ruling B on #29604
Thread-read: none
Premise: the maintainer picked B on #29604 at 2026-11-03T03:05Z; the seat's record is on #29604
Serial constraints cleared: no open PR touches docs/adr/0142-*. Tier H: the PR waits on the maintainer's approval after the seat's ACCEPT.
The dev thread for claim 6594482347 drafted the ADR-0142 amendment, then went idle at 2026-11-03T03:23Z before it pushed. Branch claude/project-thread-xcbmm5 is not on origin, and no PR exists.
The seat is re-dispatching the same order on a fresh thread. [Edit: the dev thread is alive; its commit is waiting on a maintainer permission prompt. No re-dispatch. If it is still stuck after that prompt is answered, the seat re-dispatches and re-points the claim.]
Draft PR #29865 (head 2f923ae) for #29738, step 1 of ruling B on #29604. Tier H: waits on the seat's ACCEPT and then the maintainer's approval.
{
"issue": 29738,
"status": "done",
"branch": "claude/project-thread-xcbmm5",
"pr": "https://github.com/objectstack-ai/objectstack/pull/29865",
"session": "session_01JQwxbYJgdcYRwx5iQa5Ksc",
"premise_still_valid": true,
"summary": "ADR-0142 amended, one file, +51/-1, no code, schema or changeset. The status line gains a second note in the first note's shape (Amended, third of November 2026, ruling record 6594432222 on #29604, letter B). D2 gains a paragraph that tells an empty expansion (a fact: every specification was read and reached nobody) from a failed member-table read (a fault: the expander knows nothing and nobody would be an invented answer); the admission consumers (D3 access path, D4 claim admission, D5 assignment pool) keep nobody, logged at warn, because for them nobody denies; the recompute consumers (D6 approver slate, D7 sharing-recipient grant pass) refuse, as a thrown failure naming the specification and the table. A note after D6 item 5 writes the refusal in the approvals failure class PR #29602 (#29503) landed for team and position approvers: the resolver's directory-failure catch warns that the read FAILED with the error, never expanded to nobody, and the slot is held as the queue literal so the request waits rather than advances past the queue's people; item 2's never-written-again is read as the empty case. A note after D7 item 5 writes the #29362 isolation shape: every rule-wide pass and the per-user recompute stop that rule's pass before any revoke, keep the rule's existing grants, warn naming the rule and the read, and let the other rules reconcile. Measured before writing: today's expander answers nobody on a failed read at expandSpec, holderCheck, authoredMemberSpecs and authoredQueueNames in ownership-queue-service.ts; the consumers by D-number with file and line are in the PR body's Why section.",
"tests": "none owed: docs-only diff, no package touched, so no build closure and no package test. No ablation (no tested behaviour changed).",
"gates": "local subset on head 2f923ae4 (commit 8c3d7b9c merged with origin/main 42ff86f6): `node scripts/pm/dispatch-gates.mjs --commands` derived 21 commands (a first derivation on 8c3d7b9c printed STALE TREE, 61 commits behind with 10 derivation inputs moved, so origin/main was merged and the list re-derived clean); prerequisite build of @objectstack/formula and @objectstack/lint under os-verify-lock.sh, VERDICT command-exit 0, held 168 s, waited 0 s; all 21 exit 0 with each code captured before any pipe: check-adr-links (+ --self-test), check-closing-keyword-parity (+ --self-test), check-comment-mask-corpus, ci/plan-test-core-shards --self-test, lint check:doc-formula-expressions, check:adr-anchors, check:adr-index, check:adr-symbol-anchors, check:ci-filter-parity, check:closed-ceremony-text, check:cross-package-test-inputs, check:doc-authoring, check:driver-memory-census, check:gitlink-declared, check:nul-bytes, check:pm-governed-merges, check:pm-prior-rulings, check:refd-timer-probe, check:watch-hint-literal; plus `pnpm lint` (eslint . --no-inline-config) exit 0 as the order asked. `--ran`: 21 derived, 21 run, 0 NOT-MEASURED, 0 UNRUN; pnpm lint listed as outside the derivation. `--tier`: MANDATORY claude-fable-5-1 for docs/adr/**, run at that tier, effort xhigh; changed lines 52 vs 3000: under. CI check-runs on 2f923ae4 at the time of this report: Governed Surface Queue Guard success, PR-body guards success, Check PR Size success, Check Changeset success, filter success; the Lint and Type Check lanes, Test UI, Dogfood Regression Gate, Plan Test Core shards and Check Documentation Links in_progress; the UI, Build Core, Build Docs, Temporal Conformance and opt-in lanes skipped by their path filters. Not re-run locally; the PR's check-runs are the authority.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm (Clause-②: no).",
"mcp_calls": "0 — no GitHub MCP tool was called for read or write.",
"api_writes": "2 — both POST /repos/objectstack-ai/objectstack/dispatches through the fleet-write relay: pr_create (run 41604897598, PR #29865, draft, labels [skip-changeset], no assignees, 14513 bytes sent and stored identical) and this os-dev-report comment via post-stamped.mjs. git push twice (8c3d7b9c, then the merge 2f923ae4) is not a REST write. Reads: REST GET of #29738, #29604, #29362, #29503, #29606, PR #29602, PR #29865 and the head's check-runs.",
"open_questions": [
{
"question": "For the tier review, not a blocker: the D6 note reads 'follows #29503's approvals failure class' as the class PR #29602 landed for team and position approvers, so a failed queue read HOLDS the queue literal slot (a slot no acting path admits a caller under, decidable by the override) and item 2's 'never written again' is narrowed to the empty case. Is that the intended reading?",
"options": [
"A — hold the literal and warn that the read failed (as written; the request waits rather than advances past the queue's people)",
"B — contribute no slot and let onEmptyApprovers decide (one sentence to change in the D6 note)"
],
"recommendation": "A, because B is the shrunk slate the ruling refuses (other entries carry the request past the queue's people) and under onEmptyApprovers auto_approve it approves a request on an outage; A matches the measured class (warnExpansionFailed: the slot falls back to its literal rather than route to part of its people)."
}
],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: #29604 · the ownership-queue-service.ts module header (the 'Absence is not a fault' section) declares the posture this amendment retires for D6 and D7 ('a failed read of a member table contributes nobody ... fail closed for every admission that reads it'); once this ADR merges that sentence is stale until the code half rewrites it. Noted, not filed: the code half edits that file anyway.",
"carrier: #29604 · QUEUE_READ_LIMIT silently drops holders past 10,000 rows (comment 6591670782 on #29604). Not an ADR matter; the ruling record leaves it to the code half. Noted, not filed."
],
"deviations": [
"No subscribe_pr_activity on PR #29865: os-dev.md's dispatch contract overrides the platform's PR-subscription posture; the seat drives CI readings, the tier review and the hand-over.",
"The session-context's GitHub-MCP assignee and reviewer step was skipped: the order forbids GitHub MCP; the relay requests the Tier H approvers and the card's assignee is the seat's.",
"Commit trailers are the model-free pair AGENTS.md requires (Claude-Session URL + Co-authored-by: Claude); the harness's model-named Co-Authored-By spelling was not written. PR body footer is the repo's single session-URL form; the harness's second footer form was not added.",
"PR body: the first line is the platform's attribution marker (the os-dev exception); .github/PULL_REQUEST_TEMPLATE.md's headings are folded into the os-dev section order with its Human Minimum list at the end.",
"Two container restarts between the edit (about 03:23Z) and the push (about 08:20Z) stalled the thread; the seat's progress note 6597517535 recorded it. Nothing was lost; the amendment pushed as 8c3d7b9c and origin/main was merged on top as 2f923ae4 before the gates ran."
],
"body_amendments": []
}
Addendum (round 2) for draft PR #29865, now at head 589be30, answering contract review 6599389641 and the maintainer's ruling 6599731698 on #29604. The PR body was not patched; the amendments it owes are listed under body_amendments for the seat.
{
"issue": 29738,
"status": "done",
"round": "2 — addendum to os-dev-report 6599161425, after contract review 6599389641 (FAIL) and the maintainer's ruling 6599731698 on #29604",
"branch": "claude/project-thread-xcbmm5",
"pr": "https://github.com/objectstack-ai/objectstack/pull/29865",
"session": "session_01JQwxbYJgdcYRwx5iQa5Ksc",
"premise_still_valid": true,
"summary": "Head 589be305 = commit 9ea89d0e (round 2) merged with origin/main 74fd4bf6; the PR's diff against main is still one file, docs/adr/0142, now +61/-3. Must-fix 1 as re-ruled: the D6 note now states the maintainer's target of 09:11Z (record 6599731698, letter B) — on a failed read behind the queue the slate refuses and the approval node refuses to open under every onEmptyApprovers policy (admin_rescue, auto_approve, fail, fallback): not routed to administrators, not auto-approved, not opened on a fallback slate; a loud failure of its own error class, not NO_APPROVERS and not expanded-to-nobody, naming the read that failed, retryable by re-triggering the run; no parked or auto-retry state (its own card if wanted). The ruling puts team and position approvers in the same class, and the note says it replaces the earlier follows-#29503 wording of record 6594432222. The execution point is named with symbol anchors: resolveApproverSpec's directory-failure catch (directoryFailure), the queue branch's early expanded-to-nobody return consulting it first, and openNodeRequest refusing before approver-address.ts slateNamesAPerson hands the slate to onEmptyApprovers. Item 2's never-written-again stays whole: a failed read writes no literal and no slot. Must-fix 2: D2's fault list is now every read the expansion makes — the queue's own row (sys_queue, through which an authored queue resolves), the member rows (sys_queue_member) and the member tables a specification reads — with the sentence that a queue that could not be resolved is not a queue that resolves nowhere (the first is a failed read, the second is absence). Should-fix 1: a refusal names the read, never [], null or false. Should-fix 2: item 2's literal is spelled queue colon name, the queue's machine name (D1) as the resolver writes an approver's value, and the D6 note uses the same spelling. The status line now cites both ruling records and says the D6 slate refuses with the node refusing to open; the D7 note says a failed read behind the queue (D2) rather than a member-table read. Verified against origin/main 4b71a82b before writing: approver-address.ts slateNamesAPerson is true only for an address with no colon, openNodeRequest routes a slate with none through onEmptyApprovers (admin_rescue default, fail throws NO_APPROVERS, fallback re-tests, admin_rescue opens on administrators), and in ownership-queue-service.ts authoredQueueRow catches to null and authoredQueueNames catches to [], so a failed sys_queue read was the empty case under round 1's text.",
"tests": "none owed: docs-only diff, no package touched. No ablation.",
"gates": "local subset on head 589be305: `dispatch-gates.mjs --commands` re-derived after the merge, 21 commands, no STALE TREE, the same list as round 1; prerequisite build of @objectstack/formula and @objectstack/lint under os-verify-lock.sh, VERDICT command-exit 0, held 146 s, waited 1 s; all 21 exit 0 with each code captured before any pipe (check-adr-links and its --self-test, check-closing-keyword-parity and its --self-test, check-comment-mask-corpus, ci/plan-test-core-shards --self-test, lint check:doc-formula-expressions, check:adr-anchors, check:adr-index, check:adr-symbol-anchors — the three new anchors resolveApproverSpec, openNodeRequest and slateNamesAPerson resolve — check:ci-filter-parity, check:closed-ceremony-text, check:cross-package-test-inputs, check:doc-authoring, check:driver-memory-census, check:gitlink-declared, check:nul-bytes, check:pm-governed-merges, check:pm-prior-rulings, check:refd-timer-probe, check:watch-hint-literal); `pnpm lint` exit 0. `--ran`: 21 derived, 21 run, 0 NOT-MEASURED, 0 UNRUN; pnpm lint outside the derivation. CI check-runs on 589be305 at this writing: 41 total, 25 success, 16 skipped by path filter, 0 failure, all completed. Not re-run locally.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm.",
"mcp_calls": "0 — no GitHub MCP tool was called.",
"api_writes": "1 this round — POST /repos/objectstack-ai/objectstack/dispatches through the relay for this addendum (post-stamped.mjs). git push once (9ea89d0e then the merge 589be305, one push) is not a REST write. The PR body was not patched. Reads: REST GET of PR #29865 comments, #29604 comments, the head's check-runs.",
"body_amendments": [
"Line 4 (Part of #29604 …) and the 维护者速读 改了什么 line: the two sentences describing D6 as 'refuse' alone now read as the ruled target — on a failed read behind a queue (and a team or position) approver the approval node refuses to open under every onEmptyApprovers policy, loudly, with its own retryable error class naming the failed read; cite ruling record 6599731698 beside 6594432222.",
"维护者速读 风险与回滚 line: delete the clause '(读失败时该槽位保留为队列字面量并告警「读取失败」,不再写成「展开为空」),把 D6 第 2 条「字面量永不再写」收窄为「展开为空的情形」'; replace with '按你 09:11Z 的裁决(#29604 记录 6599731698):读失败时审批节点拒绝打开,所有 onEmptyApprovers 策略一律如此,可重试;D6 第 2 条「字面量永不再写」原样保留'. 改了什么 line: '+51 / −1' becomes '+61 / −3'.",
"维护者速读 先看 ① line: replace '(「槽位保留为字面量」一句是本 PR 唯一触及既有条文含义之处)' with '(节点拒绝打开一段,含执行点:resolveApproverSpec 的 directoryFailure、queue 分支的提前返回、openNodeRequest 在 slateNamesAPerson 之前拒绝)'. 两分钟验证 line: '1 file changed, 51 insertions(+), 1 deletion(-)' becomes '1 file changed, 61 insertions(+), 3 deletions(-)'; the 3 changed lines are the status line and item 2's two lines (the literal is now spelled by the queue's machine name).",
"What changes, Status line bullet: '…from a failed member-table read (a fault): … the D6 approver slate and the D7 grant recompute refuse it' becomes '…from a failed read behind the queue (a fault): … the D7 grant recompute refuses it, and the D6 approver slate refuses it with the approval node refusing to open'; cite both ruling records.",
"What changes, D2 bullet: the fault list now reads 'any read the expansion makes — the queue's own row (sys_queue, through which an authored queue resolves), the member rows (sys_queue_member), and the member tables a specification reads (…)'; add 'A queue that could not be resolved is not a queue that resolves nowhere'; 'naming the specification and the table, never [] or false' becomes 'naming the read, never [], null or false'.",
"What changes, D6 bullet: replace the whole bullet. New text: 'A note after item 5: item 2's expanded to nobody is the empty case. A failed read behind the queue refuses the slate and the approval node refuses to open under every onEmptyApprovers policy (admin_rescue, auto_approve, fail, fallback): not routed to administrators, not auto-approved, not opened on a fallback slate; a loud failure of its own error class (not NO_APPROVERS, not expanded to nobody) naming the failed read, retryable; no parked or auto-retry state. The ruling puts team and position approvers in the same class. Execution point: resolveApproverSpec's directoryFailure; the queue branch's early return consults it first; openNodeRequest refuses before slateNamesAPerson hands the slate to onEmptyApprovers. Item 2's never written again stays whole; item 2 now spells the literal by the queue's machine name (queue:NAME).'",
"What changes, D7 bullet and 'Nothing else in the record moves' paragraph: 'A failed read behind the queue' (not 'member-table read'); add 'D6 item 2's literal spelling is aligned to the queue's machine name' to the list of what moves.",
"Acceptance notes, first bullet ('The reading taken for D6'): replace with 'The D6 note states the maintainer's ruling of 2026-11-03 09:11Z (record 6599731698 on #29604, letter B), which replaced the earlier follows-#29503 wording after the contract review (6599389641) showed openNodeRequest routes a literal-only slate through onEmptyApprovers. It names the execution point for the code half; the held-literal reading is withdrawn.' Second bullet (mechanism left to the code half): add 'The contract review notes the spec's QueueExpansionPurpose (access | addressing) is an independent axis; refuse-vs-nobody must not overload it.'",
"Verification: head 2f923ae4 becomes 589be305 (commit 9ea89d0e merged with origin/main 74fd4bf6); gate readings from the round-2 run (os-dev-report addendum on #29738)."
],
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: #29604 · unchanged from round 1: the ownership-queue-service.ts header's 'Absence is not a fault' paragraph goes stale on merge; QUEUE_READ_LIMIT silent drop (6591670782). Noted, not filed.",
"carrier: #29604 · the contract review's note that QueueExpansionPurpose (access | addressing, packages/spec/src/contracts/ownership-queue-service.ts) is an axis about switched-off positions, independent of refuse-vs-nobody; the code half must not overload it. Recorded here for the code half; the ADR deliberately leaves the spelling to that PR."
],
"deviations": [
"The D6 note no longer cites #29503's class as the outcome, per the seat's round-2 instruction and the ruling; it names the record it replaces so the history stays readable.",
"Two lines in the amended text exceed the record's usual 120-column wrap (a link-bearing Amended line at 143 and one prose line at 127); the status line was already far longer. No gate reads line length.",
"The worker process restarted once during round 2 (between the edit and the commit); the edit survived in the worktree and nothing was redone."
]
}
Release: claim 6594482347 (session_01JQwxbacSXJQqAztgt4UMrS, card thread session_01JQwxbYJgdcYRwx5iQa5Ksc, branch claude/project-thread-xcbmm5) · full landing
Produce: PR #29865 merged as d74667c0 at 2026-11-03T11:14Z, queued by the maintainer's hand (os-zhuang). ADR-0142 now separates an empty queue expansion (a fact) from a failed read behind the queue (a fault: sys_queue, sys_queue_member, and the member tables a specification reads). The admission consumers (D3, D4, D5) keep "nobody". The D7 grant recompute refuses the read and keeps the rule's grants. On a failed read at the D6 slate, the approval node refuses to open under every onEmptyApprovers policy: a retryable failure with its own error class (ruling 6599731698). Two fable contract reviews were run: FAIL 6599389641, then PASS 6600699486. Tier H ACCEPT 6600730251. Fixes #29738 closed this card as completed.
Activity
objectstack-fleet commentedon Nov 3, 2026
domain:server#4 · os-warren · session_01JQwxbacSXJQqAztgt4UMrS
Claim: PM loop · ADR amendment · 2026-11-03T03:12Z
Session:
session_01JQwxbacSXJQqAztgt4UMrS(seat); dev = card threadsession_01JQwxbYJgdcYRwx5iQa5KscAccount:
os-warrenBranch:
claude/project-thread-xcbmm5(a project card thread pushes only its assigned branch; measured platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-29738Domain:
domain:server(sub-issue of #29604, the parent's domain)Seat:
domain:server#4File surface:
docs/adr/0142-ownership-queue-membership-claim-and-assignment-rules.mdonly (D2, D6, D7 and the status line). ⛔ No code, schema or changeset (stop on breach; explain in the report).Container & model:
M,mode:thread,model: CONTRACT_REVIEW_TIER(Model tier — MANDATORY: claude-fable-5-1 (derived from the file surface, not recalled).),effort: xhigh(set by the maintainer's ruling B on #29604)Clause-②: no (ADR text only; no published accept set moves)
Metadata-protocol: none
Responsibility:
n/a — governed text, step 1 of ruling B on #29604Thread-read: none
Premise: the maintainer picked B on #29604 at 2026-11-03T03:05Z; the seat's record is on #29604
Serial constraints cleared: no open PR touches
docs/adr/0142-*. Tier H: the PR waits on the maintainer's approval after the seat's ACCEPT.objectstack-fleet commentedon Nov 3, 2026
domain:server#4 · os-warren · session_01JQwxbacSXJQqAztgt4UMrS
Progress · #29738 · 2026-11-03T07:01Z · answering triage's progress request (mailbox #29522, 6597497205).
claude/project-thread-xcbmm5is not on origin, and no PR exists.The seat is re-dispatching the same order on a fresh thread.[Edit: the dev thread is alive; its commit is waiting on a maintainer permission prompt. No re-dispatch. If it is still stuck after that prompt is answered, the seat re-dispatches and re-points the claim.]objectstack-fleet commentedon Nov 3, 2026
domain:server#4 · os-warren · session_01JQwxbYJgdcYRwx5iQa5Ksc
os-dev-report
Draft PR #29865 (head 2f923ae) for #29738, step 1 of ruling B on #29604. Tier H: waits on the seat's ACCEPT and then the maintainer's approval.
{ "issue": 29738, "status": "done", "branch": "claude/project-thread-xcbmm5", "pr": "https://github.com/objectstack-ai/objectstack/pull/29865", "session": "session_01JQwxbYJgdcYRwx5iQa5Ksc", "premise_still_valid": true, "summary": "ADR-0142 amended, one file, +51/-1, no code, schema or changeset. The status line gains a second note in the first note's shape (Amended, third of November 2026, ruling record 6594432222 on #29604, letter B). D2 gains a paragraph that tells an empty expansion (a fact: every specification was read and reached nobody) from a failed member-table read (a fault: the expander knows nothing and nobody would be an invented answer); the admission consumers (D3 access path, D4 claim admission, D5 assignment pool) keep nobody, logged at warn, because for them nobody denies; the recompute consumers (D6 approver slate, D7 sharing-recipient grant pass) refuse, as a thrown failure naming the specification and the table. A note after D6 item 5 writes the refusal in the approvals failure class PR #29602 (#29503) landed for team and position approvers: the resolver's directory-failure catch warns that the read FAILED with the error, never expanded to nobody, and the slot is held as the queue literal so the request waits rather than advances past the queue's people; item 2's never-written-again is read as the empty case. A note after D7 item 5 writes the #29362 isolation shape: every rule-wide pass and the per-user recompute stop that rule's pass before any revoke, keep the rule's existing grants, warn naming the rule and the read, and let the other rules reconcile. Measured before writing: today's expander answers nobody on a failed read at expandSpec, holderCheck, authoredMemberSpecs and authoredQueueNames in ownership-queue-service.ts; the consumers by D-number with file and line are in the PR body's Why section.", "tests": "none owed: docs-only diff, no package touched, so no build closure and no package test. No ablation (no tested behaviour changed).", "gates": "local subset on head 2f923ae4 (commit 8c3d7b9c merged with origin/main 42ff86f6): `node scripts/pm/dispatch-gates.mjs --commands` derived 21 commands (a first derivation on 8c3d7b9c printed STALE TREE, 61 commits behind with 10 derivation inputs moved, so origin/main was merged and the list re-derived clean); prerequisite build of @objectstack/formula and @objectstack/lint under os-verify-lock.sh, VERDICT command-exit 0, held 168 s, waited 0 s; all 21 exit 0 with each code captured before any pipe: check-adr-links (+ --self-test), check-closing-keyword-parity (+ --self-test), check-comment-mask-corpus, ci/plan-test-core-shards --self-test, lint check:doc-formula-expressions, check:adr-anchors, check:adr-index, check:adr-symbol-anchors, check:ci-filter-parity, check:closed-ceremony-text, check:cross-package-test-inputs, check:doc-authoring, check:driver-memory-census, check:gitlink-declared, check:nul-bytes, check:pm-governed-merges, check:pm-prior-rulings, check:refd-timer-probe, check:watch-hint-literal; plus `pnpm lint` (eslint . --no-inline-config) exit 0 as the order asked. `--ran`: 21 derived, 21 run, 0 NOT-MEASURED, 0 UNRUN; pnpm lint listed as outside the derivation. `--tier`: MANDATORY claude-fable-5-1 for docs/adr/**, run at that tier, effort xhigh; changed lines 52 vs 3000: under. CI check-runs on 2f923ae4 at the time of this report: Governed Surface Queue Guard success, PR-body guards success, Check PR Size success, Check Changeset success, filter success; the Lint and Type Check lanes, Test UI, Dogfood Regression Gate, Plan Test Core shards and Check Documentation Links in_progress; the UI, Build Core, Build Docs, Temporal Conformance and opt-in lanes skipped by their path filters. Not re-run locally; the PR's check-runs are the authority.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm (Clause-②: no).", "mcp_calls": "0 — no GitHub MCP tool was called for read or write.", "api_writes": "2 — both POST /repos/objectstack-ai/objectstack/dispatches through the fleet-write relay: pr_create (run 41604897598, PR #29865, draft, labels [skip-changeset], no assignees, 14513 bytes sent and stored identical) and this os-dev-report comment via post-stamped.mjs. git push twice (8c3d7b9c, then the merge 2f923ae4) is not a REST write. Reads: REST GET of #29738, #29604, #29362, #29503, #29606, PR #29602, PR #29865 and the head's check-runs.", "open_questions": [ { "question": "For the tier review, not a blocker: the D6 note reads 'follows #29503's approvals failure class' as the class PR #29602 landed for team and position approvers, so a failed queue read HOLDS the queue literal slot (a slot no acting path admits a caller under, decidable by the override) and item 2's 'never written again' is narrowed to the empty case. Is that the intended reading?", "options": [ "A — hold the literal and warn that the read failed (as written; the request waits rather than advances past the queue's people)", "B — contribute no slot and let onEmptyApprovers decide (one sentence to change in the D6 note)" ], "recommendation": "A, because B is the shrunk slate the ruling refuses (other entries carry the request past the queue's people) and under onEmptyApprovers auto_approve it approves a request on an outage; A matches the measured class (warnExpansionFailed: the slot falls back to its literal rather than route to part of its people)." } ], "security_findings": "none", "out_of_scope_findings": [ "carrier: #29604 · the ownership-queue-service.ts module header (the 'Absence is not a fault' section) declares the posture this amendment retires for D6 and D7 ('a failed read of a member table contributes nobody ... fail closed for every admission that reads it'); once this ADR merges that sentence is stale until the code half rewrites it. Noted, not filed: the code half edits that file anyway.", "carrier: #29604 · QUEUE_READ_LIMIT silently drops holders past 10,000 rows (comment 6591670782 on #29604). Not an ADR matter; the ruling record leaves it to the code half. Noted, not filed." ], "deviations": [ "No subscribe_pr_activity on PR #29865: os-dev.md's dispatch contract overrides the platform's PR-subscription posture; the seat drives CI readings, the tier review and the hand-over.", "The session-context's GitHub-MCP assignee and reviewer step was skipped: the order forbids GitHub MCP; the relay requests the Tier H approvers and the card's assignee is the seat's.", "Commit trailers are the model-free pair AGENTS.md requires (Claude-Session URL + Co-authored-by: Claude); the harness's model-named Co-Authored-By spelling was not written. PR body footer is the repo's single session-URL form; the harness's second footer form was not added.", "PR body: the first line is the platform's attribution marker (the os-dev exception); .github/PULL_REQUEST_TEMPLATE.md's headings are folded into the os-dev section order with its Human Minimum list at the end.", "Two container restarts between the edit (about 03:23Z) and the push (about 08:20Z) stalled the thread; the seat's progress note 6597517535 recorded it. Nothing was lost; the amendment pushed as 8c3d7b9c and origin/main was merged on top as 2f923ae4 before the gates ran." ], "body_amendments": [] }objectstack-fleet commentedon Nov 3, 2026
domain:server#4 · os-warren · session_01JQwxbacSXJQqAztgt4UMrS
Notify: ruling · #29738 · B · 6599731698 · 2026-11-03T09:14Z
onEmptyApproverspolicy.sys_queuereads) and both should-fixes stand.objectstack-fleet commentedon Nov 3, 2026
domain:server#4 · os-warren · session_01JQwxbYJgdcYRwx5iQa5Ksc
os-dev-report
Addendum (round 2) for draft PR #29865, now at head 589be30, answering contract review 6599389641 and the maintainer's ruling 6599731698 on #29604. The PR body was not patched; the amendments it owes are listed under body_amendments for the seat.
{ "issue": 29738, "status": "done", "round": "2 — addendum to os-dev-report 6599161425, after contract review 6599389641 (FAIL) and the maintainer's ruling 6599731698 on #29604", "branch": "claude/project-thread-xcbmm5", "pr": "https://github.com/objectstack-ai/objectstack/pull/29865", "session": "session_01JQwxbYJgdcYRwx5iQa5Ksc", "premise_still_valid": true, "summary": "Head 589be305 = commit 9ea89d0e (round 2) merged with origin/main 74fd4bf6; the PR's diff against main is still one file, docs/adr/0142, now +61/-3. Must-fix 1 as re-ruled: the D6 note now states the maintainer's target of 09:11Z (record 6599731698, letter B) — on a failed read behind the queue the slate refuses and the approval node refuses to open under every onEmptyApprovers policy (admin_rescue, auto_approve, fail, fallback): not routed to administrators, not auto-approved, not opened on a fallback slate; a loud failure of its own error class, not NO_APPROVERS and not expanded-to-nobody, naming the read that failed, retryable by re-triggering the run; no parked or auto-retry state (its own card if wanted). The ruling puts team and position approvers in the same class, and the note says it replaces the earlier follows-#29503 wording of record 6594432222. The execution point is named with symbol anchors: resolveApproverSpec's directory-failure catch (directoryFailure), the queue branch's early expanded-to-nobody return consulting it first, and openNodeRequest refusing before approver-address.ts slateNamesAPerson hands the slate to onEmptyApprovers. Item 2's never-written-again stays whole: a failed read writes no literal and no slot. Must-fix 2: D2's fault list is now every read the expansion makes — the queue's own row (sys_queue, through which an authored queue resolves), the member rows (sys_queue_member) and the member tables a specification reads — with the sentence that a queue that could not be resolved is not a queue that resolves nowhere (the first is a failed read, the second is absence). Should-fix 1: a refusal names the read, never [], null or false. Should-fix 2: item 2's literal is spelled queue colon name, the queue's machine name (D1) as the resolver writes an approver's value, and the D6 note uses the same spelling. The status line now cites both ruling records and says the D6 slate refuses with the node refusing to open; the D7 note says a failed read behind the queue (D2) rather than a member-table read. Verified against origin/main 4b71a82b before writing: approver-address.ts slateNamesAPerson is true only for an address with no colon, openNodeRequest routes a slate with none through onEmptyApprovers (admin_rescue default, fail throws NO_APPROVERS, fallback re-tests, admin_rescue opens on administrators), and in ownership-queue-service.ts authoredQueueRow catches to null and authoredQueueNames catches to [], so a failed sys_queue read was the empty case under round 1's text.", "tests": "none owed: docs-only diff, no package touched. No ablation.", "gates": "local subset on head 589be305: `dispatch-gates.mjs --commands` re-derived after the merge, 21 commands, no STALE TREE, the same list as round 1; prerequisite build of @objectstack/formula and @objectstack/lint under os-verify-lock.sh, VERDICT command-exit 0, held 146 s, waited 1 s; all 21 exit 0 with each code captured before any pipe (check-adr-links and its --self-test, check-closing-keyword-parity and its --self-test, check-comment-mask-corpus, ci/plan-test-core-shards --self-test, lint check:doc-formula-expressions, check:adr-anchors, check:adr-index, check:adr-symbol-anchors — the three new anchors resolveApproverSpec, openNodeRequest and slateNamesAPerson resolve — check:ci-filter-parity, check:closed-ceremony-text, check:cross-package-test-inputs, check:doc-authoring, check:driver-memory-census, check:gitlink-declared, check:nul-bytes, check:pm-governed-merges, check:pm-prior-rulings, check:refd-timer-probe, check:watch-hint-literal); `pnpm lint` exit 0. `--ran`: 21 derived, 21 run, 0 NOT-MEASURED, 0 UNRUN; pnpm lint outside the derivation. CI check-runs on 589be305 at this writing: 41 total, 25 success, 16 skipped by path filter, 0 failure, all completed. Not re-run locally.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm.", "mcp_calls": "0 — no GitHub MCP tool was called.", "api_writes": "1 this round — POST /repos/objectstack-ai/objectstack/dispatches through the relay for this addendum (post-stamped.mjs). git push once (9ea89d0e then the merge 589be305, one push) is not a REST write. The PR body was not patched. Reads: REST GET of PR #29865 comments, #29604 comments, the head's check-runs.", "body_amendments": [ "Line 4 (Part of #29604 …) and the 维护者速读 改了什么 line: the two sentences describing D6 as 'refuse' alone now read as the ruled target — on a failed read behind a queue (and a team or position) approver the approval node refuses to open under every onEmptyApprovers policy, loudly, with its own retryable error class naming the failed read; cite ruling record 6599731698 beside 6594432222.", "维护者速读 风险与回滚 line: delete the clause '(读失败时该槽位保留为队列字面量并告警「读取失败」,不再写成「展开为空」),把 D6 第 2 条「字面量永不再写」收窄为「展开为空的情形」'; replace with '按你 09:11Z 的裁决(#29604 记录 6599731698):读失败时审批节点拒绝打开,所有 onEmptyApprovers 策略一律如此,可重试;D6 第 2 条「字面量永不再写」原样保留'. 改了什么 line: '+51 / −1' becomes '+61 / −3'.", "维护者速读 先看 ① line: replace '(「槽位保留为字面量」一句是本 PR 唯一触及既有条文含义之处)' with '(节点拒绝打开一段,含执行点:resolveApproverSpec 的 directoryFailure、queue 分支的提前返回、openNodeRequest 在 slateNamesAPerson 之前拒绝)'. 两分钟验证 line: '1 file changed, 51 insertions(+), 1 deletion(-)' becomes '1 file changed, 61 insertions(+), 3 deletions(-)'; the 3 changed lines are the status line and item 2's two lines (the literal is now spelled by the queue's machine name).", "What changes, Status line bullet: '…from a failed member-table read (a fault): … the D6 approver slate and the D7 grant recompute refuse it' becomes '…from a failed read behind the queue (a fault): … the D7 grant recompute refuses it, and the D6 approver slate refuses it with the approval node refusing to open'; cite both ruling records.", "What changes, D2 bullet: the fault list now reads 'any read the expansion makes — the queue's own row (sys_queue, through which an authored queue resolves), the member rows (sys_queue_member), and the member tables a specification reads (…)'; add 'A queue that could not be resolved is not a queue that resolves nowhere'; 'naming the specification and the table, never [] or false' becomes 'naming the read, never [], null or false'.", "What changes, D6 bullet: replace the whole bullet. New text: 'A note after item 5: item 2's expanded to nobody is the empty case. A failed read behind the queue refuses the slate and the approval node refuses to open under every onEmptyApprovers policy (admin_rescue, auto_approve, fail, fallback): not routed to administrators, not auto-approved, not opened on a fallback slate; a loud failure of its own error class (not NO_APPROVERS, not expanded to nobody) naming the failed read, retryable; no parked or auto-retry state. The ruling puts team and position approvers in the same class. Execution point: resolveApproverSpec's directoryFailure; the queue branch's early return consults it first; openNodeRequest refuses before slateNamesAPerson hands the slate to onEmptyApprovers. Item 2's never written again stays whole; item 2 now spells the literal by the queue's machine name (queue:NAME).'", "What changes, D7 bullet and 'Nothing else in the record moves' paragraph: 'A failed read behind the queue' (not 'member-table read'); add 'D6 item 2's literal spelling is aligned to the queue's machine name' to the list of what moves.", "Acceptance notes, first bullet ('The reading taken for D6'): replace with 'The D6 note states the maintainer's ruling of 2026-11-03 09:11Z (record 6599731698 on #29604, letter B), which replaced the earlier follows-#29503 wording after the contract review (6599389641) showed openNodeRequest routes a literal-only slate through onEmptyApprovers. It names the execution point for the code half; the held-literal reading is withdrawn.' Second bullet (mechanism left to the code half): add 'The contract review notes the spec's QueueExpansionPurpose (access | addressing) is an independent axis; refuse-vs-nobody must not overload it.'", "Verification: head 2f923ae4 becomes 589be305 (commit 9ea89d0e merged with origin/main 74fd4bf6); gate readings from the round-2 run (os-dev-report addendum on #29738)." ], "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: #29604 · unchanged from round 1: the ownership-queue-service.ts header's 'Absence is not a fault' paragraph goes stale on merge; QUEUE_READ_LIMIT silent drop (6591670782). Noted, not filed.", "carrier: #29604 · the contract review's note that QueueExpansionPurpose (access | addressing, packages/spec/src/contracts/ownership-queue-service.ts) is an axis about switched-off positions, independent of refuse-vs-nobody; the code half must not overload it. Recorded here for the code half; the ADR deliberately leaves the spelling to that PR." ], "deviations": [ "The D6 note no longer cites #29503's class as the outcome, per the seat's round-2 instruction and the ruling; it names the record it replaces so the history stays readable.", "Two lines in the amended text exceed the record's usual 120-column wrap (a link-bearing Amended line at 143 and one prose line at 127); the status line was already far longer. No gate reads line length.", "The worker process restarted once during round 2 (between the edit and the commit); the edit survived in the worktree and nothing was redone." ] }objectstack-fleet commentedon Nov 3, 2026
domain:server#4 · os-warren · session_01JQwxbacSXJQqAztgt4UMrS
Landing record · #29738 · PR #29865 · 2026-11-03T11:14Z
git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-29865-*'git merge-base --is-ancestor d74667c0 origin/maingit grep -c 6599731698 origin/main -- docs/adr/0142-ownership-queue-membership-claim-and-assignment-rules.mdRelease: claim
6594482347(session_01JQwxbacSXJQqAztgt4UMrS, card threadsession_01JQwxbYJgdcYRwx5iQa5Ksc, branchclaude/project-thread-xcbmm5) · full landingProduce: PR #29865 merged as
d74667c0at 2026-11-03T11:14Z, queued by the maintainer's hand (os-zhuang). ADR-0142 now separates an empty queue expansion (a fact) from a failed read behind the queue (a fault:sys_queue,sys_queue_member, and the member tables a specification reads). The admission consumers (D3, D4, D5) keep "nobody". The D7 grant recompute refuses the read and keeps the rule's grants. On a failed read at the D6 slate, the approval node refuses to open under everyonEmptyApproverspolicy: a retryable failure with its own error class (ruling 6599731698). Two fable contract reviews were run: FAIL 6599389641, then PASS 6600699486. Tier H ACCEPT 6600730251.Fixes #29738closed this card as completed.pm:dispatchedandpm:blockingremoved;needs-user-decisioncomes off PR docs(adr): ADR-0142 D2 tells an empty queue expansion from a failed member read; the D6 slate and the D7 grant pass refuse a failed read #29865.pm:blocked→pm:queue). Its order follows rulings 6594432222 and 6599731698, plus the carried items in 6600766777. The maintainer has paused unstarted server work this shift, so the next shift dispatches it.