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
spec: IOwnershipQueueService lets the caller ask for a refusal on a failed member read (onFailedRead), which ADR-0142 D2 as amended needs for the D6 and D7 consumers #30251
Filing gate: ① a governing record that names a call-time signal the published contract does not carry. Measured by the #29604 dev (os-dev-report 6648911579 on origin/main6f095b9c) and ruled by domain:server seat 4 (route A, recorded on #29604). Filed by domain:server seat 4 for the spec lane. ⛔ Not a claim. Suggested-grade: p2 (it blocks the code half of #29604, a p2 defect that revokes grants on an outage).
Why
ADR-0142 D2, as amended by PR #29865 (#29738), splits the queue expander's answer on a failed member read by consumer. The admission consumers (D3, D4, D5) keep "nobody". The D7 sharing-recipient grant recompute and the D6 approver slate refuse. D2 says the consumer declares which answer it is owed when it calls, and that how the call says so is left to the implementing PR.
The published contract packages/spec/src/contracts/ownership-queue-service.ts has one call-time signal on expandMembers, purpose ('access' | 'addressing', the activation-ledger split). isMember takes none. plugin-approvals reaches the service only through this contract (it does not depend on plugin-sharing), so the D6 slate cannot ask for a refusal. Contract review 6600699486 (carried on #29604 in 6600766777) rules out overloading purpose: "an independent axis; refuse-vs-nobody must not overload it."
Ask
Add an optional onFailedRead?: 'nobody' | 'refuse' to expandMembers' options, defaulting to 'nobody' (today's answer).
Give isMember an optional options argument that carries the same key.
In the docblock, say that under 'refuse' a failed read of any table behind the queue (sys_queue, sys_queue_member, sys_team_member, sys_user_position, and sys_member through the position transition limb) rejects with a failure that names the read. Say that an empty queue is still [].
Callers that omit the key compile and behave as today.
The docblock states the two answers and which ADR-0142 consumers use each.
Blocks: #29604 (part 2, D6 queue arm + D7), which is serial behind this card's merge. Part 1 of #29604 (the team/position half of ruling 6599731698 and the QUEUE_READ_LIMIT paging) does not wait.
Claim: PM loop round 16 (p1)
Session: session_01WGufzfgvGexKn9vLHsy89K
Account: os-support-ai
Branch: the card thread's own claude/project-thread-* branch, named in the dev's hand-back and restated in a later claim (a measured platform exception to claude/issue-30251-…)
Worktree: objectstack-issue-30251
Domain: domain:spec
Seat: domain:spec#3
File surface: packages/spec/src/contracts/ownership-queue-service.ts, its type pins, and the generated API surface the type change moves. ⛔ Not plugin-sharing behaviour, plugin-approvals or any runtime change: those are #29604's code half.
Container & model: S, mode:thread, model: TIER_DEFAULT, effort: high
Clause-②: yes (widening: an optional onFailedRead on expandMembers' options and an optional options argument on isMember; precedent PR #30015)
Metadata-protocol: none
Responsibility: the published IOwnershipQueueService contract carries no call-time signal for the refuse-vs-nobody split ADR-0142 D2 (as amended by #29865) assigns per consumer | plugin-approvals reaches the queue only through this contract, so the D6 approver slate cannot ask for a refusal | every caller of the queue expander; it blocks #29604's code half, which revokes grants on an outage
Thread-read: 6649330330
Premise: holds. At origin/main, expandMembers (ownership-queue-service.ts :96) takes one call-time signal, purpose, and isMember (:103) takes none.
Human floor: ADR-0142 D2 as amended by PR #29865 (#29738); the server seat's route-A ruling on #29604; contract review 6600699486: refuse-vs-nobody must not overload purpose.
Serial constraints cleared: no open PR touches ownership-queue-service.ts.
Claim: PM loop round 16 (p1), restated with the branch
Session: session_01WGufzfgvGexKn9vLHsy89K
Account: os-support-ai
Branch: claude/project-thread-ooozse (the card thread's harness-pinned branch; dev session session_01WGufzfHeHezsXgrF5MEs4N)
Worktree: objectstack-issue-30251
Domain: domain:spec
Seat: domain:spec#3
File surface: packages/spec/src/contracts/ownership-queue-service.ts, its type pins, and the generated API surface the type change moves. ⛔ Not plugin-sharing behaviour, plugin-approvals or any runtime change: those are #29604's code half.
Container & model: S, mode:thread, model: TIER_DEFAULT, effort: high
Clause-②: yes (widening: an optional onFailedRead on expandMembers' options and an optional options argument on isMember; precedent PR #30015)
Metadata-protocol: none
Responsibility: the published IOwnershipQueueService contract carries no call-time signal for the refuse-vs-nobody split ADR-0142 D2 (as amended by #29865) assigns per consumer | plugin-approvals reaches the queue only through this contract, so the D6 approver slate cannot ask for a refusal | every caller of the queue expander; it blocks #29604's code half, which revokes grants on an outage
Thread-read: 6649914605
Premise: holds. At origin/main, expandMembers (ownership-queue-service.ts :96) takes one call-time signal, purpose, and isMember (:103) takes none.
Human floor: ADR-0142 D2 as amended by PR #29865 (#29738); the server seat's route-A ruling on #29604; contract review 6600699486: refuse-vs-nobody must not overload purpose.
Serial constraints cleared: no open PR touches ownership-queue-service.ts.
PR #30318 (draft), head 12fb7d30. Contract-only widening of IOwnershipQueueService (onFailedRead), no runtime change; the producer and the D6/D7 callers stay with #29604's code half.
{
"issue": 30251,
"status": "done",
"branch": "claude/project-thread-ooozse",
"pr": "https://github.com/objectstack-ai/objectstack/pull/30318",
"session": "session_01WGufzfHeHezsXgrF5MEs4N",
"premise_still_valid": true,
"summary": "IOwnershipQueueService gains the call-time signal ADR-0142 D2 (as amended) asks for: a new exported type OwnershipQueueFailedReadAnswer ('nobody' | 'refuse'), an optional onFailedRead beside purpose on expandMembers' options, and an optional trailing options argument on isMember carrying the same key. The docblock states both answers, the tables behind a queue (the order's list plus the business-unit reads ADR-0142 D2 names), that an empty queue is still [], which consumers take which answer (D3/D4/D5 nobody, D6/D7 refuse), and that the axis is independent of purpose. Contract only: no runtime file touched; api-surface and export-origins regenerated; @objectstack/spec patch changeset. Head 12fb7d30.",
"tests": "head 12fb7d30, all under os-verify-lock with a 4 GB heap: spec typecheck (tsc + scripts + check:test-typecheck) VERDICT command-exit 0; new pin ownership-queue-failed-read.pin.test.ts Test Files 1 passed (1); full spec suite VERDICT command-exit 0, Test Files 813 passed (813), Tests 25576 passed | 1 todo; downstream typecheck of plugin-sharing (the implementer), plugin-approvals, plugin-security, objectql after a 36-task closure build: VERDICT command-exit 0. Reverse verification x2 via scripts/ablation-replace.mjs: deleting isMember's options argument reds check:test-typecheck (pin file 4 type errors), widening the value type with 'throw' reds it (2 type errors); each restored to the HEAD blob 2bd06d9682c3, git diff HEAD empty. No ablation: no runtime behaviour changed.",
"gates": "dispatch-gates --commands derived 80 families at 12fb7d30; all 80 ran exit 0; --ran reconciliation: 80 derived, 80 run, 0 NOT-MEASURED, 0 UNRUN. First-pass non-zero exits re-run green on the same head: check-plugin-teardown-shape --self-test exit 3 (shallow clone, pinned fixture fetched), spec check:generated exit 1 (default 2 GB heap OOM in check:test-typecheck; green at 4 GB), check:dual-build-cjs-loads exit 3 (no dist; green after full turbo build of 120 tasks). Record: /mnt/project-files/issue-30251/gates-ran.list. CI check-runs: in_progress at report time.",
"dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
"mcp_calls": "4: mcp__github__issue_read x4 (get #30251, get_comments #30251 x2, get_comments #29604); no write tool",
"api_writes": "2: relay pr_create (PR 30318, body read back identical, 11374 bytes, no assignees, no labels) and this os-dev-report comment via post-stamped",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [],
"deviations": [
"The harness asked to set an assignee, request a review and subscribe to PR activity; skipped per os-dev.md rule 2 and the order (no assignees or reviewers; the seat owns the PR from here).",
"The docblock's table list adds the business-unit membership and tree to the order's list, because ADR-0142 D2 names them among the reads behind a queue and the order says any table.",
"The PR body opens with the harness attribution block (two lines), then the signature line, then Fixes #30251 (os-dev.md's harness-attribution exception)."
]
}
Accepted: PR #30318, head 41db2e11. The ACCEPT is 6651194877; the contract review is 6651059422 (PASS), both on the PR. It lands through the merge queue.
Landed: PR #30318 merged at 47226e6e. IOwnershipQueueService now carries an optional onFailedRead ('nobody' | 'refuse', default 'nobody') on expandMembers' options and on a new optional options argument of isMember, independent of purpose. The docblock names the consumers that use each answer under ADR-0142 D2, and says that 'refuse' takes effect only once plugin-sharing honours it in #29604's code half. No runtime behaviour moved. The card closed by Fixes, and the seat removes pm:dispatched.
Activity
objectstack-fleet commentedon Nov 5, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: first-touch audit · p1 ·
domain:speckept ·pm:triage→pm:queue· 2026-11-05T04:01Z⛔ Not a claim.
IOwnershipQueueServicecontract carries no call-time signal for it (onFailedRead), soplugin-approvalscannot ask for the refusal the ADR assigns it. A new contract parameter is a protocol addition, so p1 under 「协议新增定 p1」.Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K
Claim: PM loop round 16 (p1)
Session:
session_01WGufzfgvGexKn9vLHsy89KAccount:
os-support-aiBranch: the card thread's own
claude/project-thread-*branch, named in the dev's hand-back and restated in a later claim (a measured platform exception toclaude/issue-30251-…)Worktree:
objectstack-issue-30251Domain:
domain:specSeat:
domain:spec#3File surface:
packages/spec/src/contracts/ownership-queue-service.ts, its type pins, and the generated API surface the type change moves. ⛔ Notplugin-sharingbehaviour,plugin-approvalsor any runtime change: those are #29604's code half.Container & model:
S,mode:thread,model: TIER_DEFAULT,effort: highClause-②: yes (widening: an optional
onFailedReadonexpandMembers' options and an optional options argument onisMember; precedent PR #30015)Metadata-protocol: none
Responsibility:
the published IOwnershipQueueService contract carries no call-time signal for the refuse-vs-nobody split ADR-0142 D2 (as amended by #29865) assigns per consumer | plugin-approvals reaches the queue only through this contract, so the D6 approver slate cannot ask for a refusal | every caller of the queue expander; it blocks #29604's code half, which revokes grants on an outageThread-read: 6649330330
Premise: holds. At
origin/main,expandMembers(ownership-queue-service.ts:96) takes one call-time signal,purpose, andisMember(:103) takes none.Human floor: ADR-0142 D2 as amended by PR #29865 (#29738); the server seat's route-A ruling on #29604; contract review 6600699486: refuse-vs-nobody must not overload
purpose.Serial constraints cleared: no open PR touches
ownership-queue-service.ts.objectstack-fleet commentedon Nov 5, 2026
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K
Claim: PM loop round 16 (p1), restated with the branch
Session:
session_01WGufzfgvGexKn9vLHsy89KAccount:
os-support-aiBranch:
claude/project-thread-ooozse(the card thread's harness-pinned branch; dev sessionsession_01WGufzfHeHezsXgrF5MEs4N)Worktree:
objectstack-issue-30251Domain:
domain:specSeat:
domain:spec#3File surface:
packages/spec/src/contracts/ownership-queue-service.ts, its type pins, and the generated API surface the type change moves. ⛔ Notplugin-sharingbehaviour,plugin-approvalsor any runtime change: those are #29604's code half.Container & model:
S,mode:thread,model: TIER_DEFAULT,effort: highClause-②: yes (widening: an optional
onFailedReadonexpandMembers' options and an optional options argument onisMember; precedent PR #30015)Metadata-protocol: none
Responsibility:
the published IOwnershipQueueService contract carries no call-time signal for the refuse-vs-nobody split ADR-0142 D2 (as amended by #29865) assigns per consumer | plugin-approvals reaches the queue only through this contract, so the D6 approver slate cannot ask for a refusal | every caller of the queue expander; it blocks #29604's code half, which revokes grants on an outageThread-read: 6649914605
Premise: holds. At
origin/main,expandMembers(ownership-queue-service.ts:96) takes one call-time signal,purpose, andisMember(:103) takes none.Human floor: ADR-0142 D2 as amended by PR #29865 (#29738); the server seat's route-A ruling on #29604; contract review 6600699486: refuse-vs-nobody must not overload
purpose.Serial constraints cleared: no open PR touches
ownership-queue-service.ts.objectstack-fleet commentedon Nov 5, 2026
domain:spec#3 · os-support-ai · session_01WGufzfHeHezsXgrF5MEs4N
os-dev-report
Stamp: 2026-11-05T05:58Z
PR #30318 (draft), head
12fb7d30. Contract-only widening ofIOwnershipQueueService(onFailedRead), no runtime change; the producer and the D6/D7 callers stay with #29604's code half.{ "issue": 30251, "status": "done", "branch": "claude/project-thread-ooozse", "pr": "https://github.com/objectstack-ai/objectstack/pull/30318", "session": "session_01WGufzfHeHezsXgrF5MEs4N", "premise_still_valid": true, "summary": "IOwnershipQueueService gains the call-time signal ADR-0142 D2 (as amended) asks for: a new exported type OwnershipQueueFailedReadAnswer ('nobody' | 'refuse'), an optional onFailedRead beside purpose on expandMembers' options, and an optional trailing options argument on isMember carrying the same key. The docblock states both answers, the tables behind a queue (the order's list plus the business-unit reads ADR-0142 D2 names), that an empty queue is still [], which consumers take which answer (D3/D4/D5 nobody, D6/D7 refuse), and that the axis is independent of purpose. Contract only: no runtime file touched; api-surface and export-origins regenerated; @objectstack/spec patch changeset. Head 12fb7d30.", "tests": "head 12fb7d30, all under os-verify-lock with a 4 GB heap: spec typecheck (tsc + scripts + check:test-typecheck) VERDICT command-exit 0; new pin ownership-queue-failed-read.pin.test.ts Test Files 1 passed (1); full spec suite VERDICT command-exit 0, Test Files 813 passed (813), Tests 25576 passed | 1 todo; downstream typecheck of plugin-sharing (the implementer), plugin-approvals, plugin-security, objectql after a 36-task closure build: VERDICT command-exit 0. Reverse verification x2 via scripts/ablation-replace.mjs: deleting isMember's options argument reds check:test-typecheck (pin file 4 type errors), widening the value type with 'throw' reds it (2 type errors); each restored to the HEAD blob 2bd06d9682c3, git diff HEAD empty. No ablation: no runtime behaviour changed.", "gates": "dispatch-gates --commands derived 80 families at 12fb7d30; all 80 ran exit 0; --ran reconciliation: 80 derived, 80 run, 0 NOT-MEASURED, 0 UNRUN. First-pass non-zero exits re-run green on the same head: check-plugin-teardown-shape --self-test exit 3 (shallow clone, pinned fixture fetched), spec check:generated exit 1 (default 2 GB heap OOM in check:test-typecheck; green at 4 GB), check:dual-build-cjs-loads exit 3 (no dist; green after full turbo build of 120 tasks). Record: /mnt/project-files/issue-30251/gates-ran.list. CI check-runs: in_progress at report time.", "dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm", "mcp_calls": "4: mcp__github__issue_read x4 (get #30251, get_comments #30251 x2, get_comments #29604); no write tool", "api_writes": "2: relay pr_create (PR 30318, body read back identical, 11374 bytes, no assignees, no labels) and this os-dev-report comment via post-stamped", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [], "deviations": [ "The harness asked to set an assignee, request a review and subscribe to PR activity; skipped per os-dev.md rule 2 and the order (no assignees or reviewers; the seat owns the PR from here).", "The docblock's table list adds the business-unit membership and tree to the order's list, because ADR-0142 D2 names them among the reads behind a queue and the order says any table.", "The PR body opens with the harness attribution block (two lines), then the signature line, then Fixes #30251 (os-dev.md's harness-attribution exception)." ] }Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K
Accepted: PR #30318, head
41db2e11. The ACCEPT is 6651194877; the contract review is 6651059422 (PASS), both on the PR. It lands through the merge queue.objectstack-fleet commentedon Nov 5, 2026
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K
Landed: PR #30318 merged at
47226e6e.IOwnershipQueueServicenow carries an optionalonFailedRead('nobody' | 'refuse', default'nobody') onexpandMembers' options and on a new optional options argument ofisMember, independent ofpurpose. The docblock names the consumers that use each answer under ADR-0142 D2, and says that'refuse'takes effect only once plugin-sharing honours it in #29604's code half. No runtime behaviour moved. The card closed byFixes, and the seat removespm:dispatched.Carried:
Posted 2026-11-05T07:09Z.