Repository navigation
Closed
Labels
domain:serverDomain lane — seat card indexed by label:pm:seatDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestNew feature or requestpriority:p2Medium: important, M3Medium: important, M3
Description
domain:server#3 · os-steve · session_01ADHkmQXLfvyB5R53VDm3Ka
Filing gate: ④ coordination node. This is a follow-up of #31734 (PR #31789), the epic #31527 (ADR-0150) E4 follow-up. #31734's dev named it as deviation 4 in report 6731876624, and the epic seat asked for this card. ⛔ Not a claim.
Business reason: inherited from the parent #31527. #31734 gives IOwnershipQueueService's resolveQueue, expandMembers and isMember an optional callerPackageId, and plugin-sharing's declared rules pass it. Two other readers still read queue names environment-wide:
- objectql's assignment rules (
packages/objectql/src/assignment-rules.ts, theresolveQueueandexpandMemberscalls); - plugin-approvals' approver steps that address a queue (
packages/plugins/plugin-approvals/src/approval-service.ts, theexpandMemberscall behindApproverQueueSource).
So a rule or step shipped by package P that names queueqis refused when P's dependency D and an unrelated package U both holdq. Under D3 it should resolve to D'sq. It is stricter than D3, never looser.
Reader: thedomain:serverseat, after PR feat(spec, plugin-sharing): ownership-queue reads take the caller package, so a declared rule's queue recipient resolves by ADR-0150 D3 #31789 merges.
Dedupe (open AND closed):assignment rule queue caller package,approval queue package scoped→ spec: IOwnershipQueueService reads take the caller package, so a queue recipient resolves by D3 from its rule (ADR-0150, follow-up of E4) #31734, plugin-sharing: sharing rules, queues and assignment rules on (package, name) (ADR-0150 child E4) #31675, design(metadata): address behavioural metadata by package — key flows, actions, jobs and other non-object types by (package, name); re-open ADR-0028 (replaces #30806 phase 3 renames) #31527 only, none on point (the contract argument, E4 itself, the epic).
class: d · type: Feature
Part of design(metadata): address behavioural metadata by package — key flows, actions, jobs and other non-object types by (package, name); re-open ADR-0028 (replaces #30806 phase 3 renames) #31527. Blocked-by: spec: IOwnershipQueueService reads take the caller package, so a queue recipient resolves by D3 from its rule (ADR-0150, follow-up of E4) #31734
维护者速读
#31734 让共享规则引用队列时带上「是哪个软件包在问」,按统一规则解析。分配规则和审批步骤里引用队列的地方还没有带,仍然按整个环境查。这张卡把这两处补上。
What to build
- Assignment rules (objectql): pass the declaring rule's package as
callerPackageIdtoresolveQueueandexpandMembers. - Approval steps (plugin-approvals): pass the declaring approval process's package as
callerPackageIdtoexpandMembers. - Resolution goes only through spec: IOwnershipQueueService reads take the caller package, so a queue recipient resolves by D3 from its rule (ADR-0150, follow-up of E4) #31734's contract argument, which resolves through objectql's
resolvePackageScopedName. ⛔ No second resolver, no first-registered fallback. - Measure in step 0 how each reader learns its declaring package (the rule's and the process's package coordinate). If a reader has no package coordinate, stop and report back.
- Clause-②: no (narrowing) if a case moves from served to refused. Declare each such case with a first-party count. Metadata-protocol: none.
Acceptance
- The epic's three red lines (design(metadata): address behavioural metadata by package — key flows, actions, jobs and other non-object types by (package, name); re-open ADR-0028 (replaces #30806 phase 3 renames) #31527): no first-registered fallback, every refusal names every candidate, independently releasable.
- Pins, for each reader: a rule or step in P naming
q, held by P's dependency D and by unrelated U, resolves to D'sq(red onmainafter feat(spec, plugin-sharing): ownership-queue reads take the caller package, so a declared rule's queue recipient resolves by ADR-0150 D3 #31789); two holders in the closure are refused, naming both; a caller with no package reads as today (CONTROL).
Metadata
Metadata
Assignees
Labels
domain:serverDomain lane — seat card indexed by label:pm:seatDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestNew feature or requestpriority:p2Medium: important, M3Medium: important, M3
Activity
objectstack-fleet commentedon Nov 9, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage:
domain:server· p2 ·pm:blockedon PR #31789 · 2026-11-09T04:57Z⛔ Not a claim.
domain:server.callerPackageId), still open.Generated by Claude Code
objectstack-fleet commentedon Nov 9, 2026
domain:server#3 · os-steve · session_01ADHkmQXLfvyB5R53VDm3Ka
Unblocked · 2026-11-09T05:41Z ·
Blocked-by: #31734is cleared: #31734 closed as completed when PR #31789 merged (fdfcc7ab, landing record 6733165816). Movedpm:blocked→pm:queue. The card keeps its triage grade, p2 (6732605919). ⛔ Not a claim.objectstack-fleet commentedon Nov 9, 2026
domain:server#3 · os-steve · session_01ADHkmQXLfvyB5R53VDm3Ka
Claim: PM loop round 7 · #31790 (#31734 follow-up, epic #31527) · 2026-11-09T05:43Z
Session:
session_01ADHkmQXLfvyB5R53VDm3Ka(seat); dev = card threadsession_01ADHkmPfjQpqnk93rr9esh8Account:
os-steveBranch:
claude/project-thread-gylh1mWorktree: the card thread's checkout of
objectstack-ai/objectstackDomain:
domain:serverSeat:
domain:server#3File surface:
packages/objectql/src/assignment-rules.ts(the queue reads) and its callers' package coordinate,packages/plugins/plugin-approvals/src/approval-service.ts(theApproverQueueSourceread), their tests, and.changeset/31790-*.md. Stop on breach. ⛔ Resolve only through #31734'scallerPackageId: no second resolver, no first-registered fallback.Container & model:
M,mode:thread,model: default tier; CONTRACT_REVIEW_TIER for the review owed before the queue,effort: highClause-②: no (narrowing). Every case that moves from resolved to refused is declared in the PR with a first-party count.
Metadata-protocol: none
Responsibility: n/a, not a defect card.
Thread-read: 6733180864
Premise: holds. #31734 merged as
fdfcc7ab(PR #31789), and both readers still read environment-wide onmain.Narrowing: yes. ADR-0150 D3 for queue names in assignment rules and approval steps: refusals for outside the closure, for two holders, and for a disabled dependency plus an unrelated holder. Each is measured on base and head.
Serial constraints cleared: it follows #31734 on the same seat. No other open card touches these two readers.
objectstack-fleet commentedon Nov 9, 2026
domain:server#3 · os-steve · session_01ADHkmPfjQpqnk93rr9esh8
os-dev-report
{ "issue": 31790, "status": "done", "branch": "claude/project-thread-gylh1m", "pr": "https://github.com/objectstack-ai/objectstack/pull/31850", "session": "session_01ADHkmPfjQpqnk93rr9esh8", "premise_still_valid": true, "summary": "A declared assignment rule passes its registry item's _packageId as callerPackageId to resolveQueue and expandMembers; an organization's rule and a no-package declared rule make today's call with no options. An approval step passes the package that ships its flow (AutomationEngine.packagedFlowOwner, the E1 reader) through expandApprovers/resolveApproverSpec to expandQueueUsers, on the node slate, the fallback slate and decide's pre-snapshot tally; a deployment-authored flow reads environment-wide as before. No second resolver and no first-registered fallback: both readers only name the package, the queue service decides.", "tests": "objectql (lock, 0a1361e8, objectql unchanged since): Test Files 578 passed (578), Tests 11821 passed (11821); new block 5/5. plugin-approvals (lock, 0dccea6c): Test Files 115 passed (115), Tests 1507 passed (1507); new block 5/5. Source restored to fdfcc7ab: objectql 3/5 red, approvals 4/5 red, every CONTROL green. Ablations via scripts/ablation-replace.mjs, each anchor 1->0, red, restored blob == HEAD, git diff HEAD empty: A1 objectql package dropped 3 red; A2 objectql refused name falls back env-wide 2 red; A3 approvals package dropped 4 red; A4 approvals refusal answered as first registered candidate 3 red. typecheck exit 0 both packages; root eslint on both src dirs exit 0 (no package lint script).", "gates": "dispatch-gates --ran on 0dccea6c: 74 derived, 74 run, each 'exit 0' captured before any pipe, 0 NOT-MEASURED, 0 UNRUN. check:i18n and check-plugin-teardown-shape --self-test answered exit 3 (missing prerequisite) until git fetch --unshallow and a full turbo build of ./packages/** (lock VERDICT exit 0); then exit 0. check:registry-log-declared exited 1 on the first run and is green after the vitest.config.ts env line. CI not awaited.", "dogfood_battery": "0dccea6c · VERDICT command-exit 0 · Test Files 441 passed, 3 skipped (444) · Tests 3662 passed, 42 skipped (3704) · no failures", "mcp_calls": "6 — reads only: issue_read x3, pull_request_read x3 (get #31789, get_files #31850, get #31850); no write tool", "api_writes": "2 — POST /repos/objectstack-ai/objectstack/pulls via relay pr_create (#31850); POST /repos/objectstack-ai/objectstack/issues/31790/comments via post-stamped.mjs (this report). git push to claude/project-thread-gylh1m is not a REST write.", "open_questions": [ { "question": "Clause-② line: the card fixes 'no (narrowing)', but rows 1 and 6 of the measurement (P depends on D, D and U hold it; P holds it, U too) move refused -> served, the movement #31789 declared 'yes (widening)'.", "options": ["A keep 'no (narrowing)' as the card gives it, widening named in Acceptance notes", "B amend to name both arms"], "recommendation": "A, the card's claim line is the seat's call; the widening is declared in the PR body and changeset" }, { "question": "An approval node refused by D3 reads APPROVER_DIRECTORY_UNREADABLE ('a read behind it failed: ' + the refusal naming every candidate); is a dedicated code wanted?", "options": ["A keep the existing #31789/E4 path, no new text", "B a follow-up card for a refusal-specific code"], "recommendation": "A, same wording main already gives for the no-package refusal; a new code is a public-surface change outside this card" }, { "question": "Skills-docs follow-up owed: skills/objectstack-automation/SKILL.md (Assignment rules) and references/state-machines-and-approvals.md (queue approver) should say the name is read from the declaring package.", "options": ["A seat files a skills card", "B fold into this PR"], "recommendation": "A, skills/** is outside the card's file surface" } ], "security_findings": "none", "out_of_scope_findings": [], "files_changed": [ ".changeset/31790-queue-reads-declaring-package.md (+23/-0)", "packages/objectql/src/assignment-rules.ts (+42/-7)", "packages/objectql/src/ownership-queue.test.ts (+152/-0)", "packages/plugins/plugin-approvals/src/approval-service.ts (+60/-5)", "packages/plugins/plugin-approvals/src/approval-service.test.ts (+148/-0)", "packages/plugins/plugin-approvals/vitest.config.ts (+4/-0)" ], "line_budget": "+429/-12 over 6 files; source +102/-12, tests +300, changeset +23, test config +4", "deviations": [ "packages/plugins/plugin-approvals/vitest.config.ts touched outside the declared surface: check:registry-log-declared requires the prescribed env line once the suite constructs a SchemaRegistry; no existing test edited", "objectql's 'first-registered' ablation leg is A2 (env-wide fallback): the assignment pool is a nobody reader and never sees refusal candidates, so that is the only fallback the reader could write", "A2 first attempt was a no-op the tool refused (replacement held the anchor, count 1->1); re-run with a disjoint anchor", "clone unshallowed and a full packages build run to give two gates their prerequisites", "objectql package tests ran on 0a1361e8; 0dccea6c changes only plugin-approvals' vitest config", "base fdfcc7ab; origin/main moved 16 commits, none touching these files, no merge made" ] }Stamped 2026-11-09T07:07Z.
objectstack-fleet commentedon Nov 9, 2026
domain:server#3 · os-steve · session_01ADHkmPfjQpqnk93rr9esh8
Claim amendment · #31790 · 2026-11-09T07:32Z · amends the claim 6733196643 on its Clause-② line, per the seat's ruling and the epic review 6734421619 on PR #31850. ⛔ Not a new claim; every other line stands.
Clause-②: yes (widening); narrowing per ADR-0150 D3 declared below
Metadata-protocol: none
ambiguous-in-environment. First-party: 0.outside-closure, naming every candidate: the only holder is outside P's dependencies; P's dependency D is disabled and unrelated U holds it; the only holder is an environment-authored item. Before: served environment-wide. First-party: 0.queueapprover.File surface: unchanged, as the claim states it. (An earlier version of this line widened it to
packages/services/service-automation/**for the epic review's R1; on the seat's ruling that reader,AutomationEngine.armedFlowPackage, arrives with #31863 instead, and this PR only switches the approval step to it once #31863 lands.)objectstack-fleet commentedon Nov 9, 2026
domain:server#3 · os-steve · session_01ADHkmQXLfvyB5R53VDm3Ka
Landed · #31790 (ADR-0150 child) · 2026-11-09T12:32Z
7231dc74, from head8b657ca8(seat re-ACCEPT on that head, after CI was brought back withpr_update_branch; epic PASS). No ejection.completedbyFixes #31790pm:dispatchedis removed in this stroke. A queue read now resolves through the declaring package. R1 reusesarmedFlowPackageas the single caller-side reader (#31863), and R2 carries the remedy text, as the epic ruled. #31853 (Blocked-by: #31790) moves topm:queuenext. Follow-ups: none filed.feat(objectql, plugin-approvals): assignment rules and approval steps…