Skip to content

docs(adr): amend ADR-0142 D5 — an organization authors its own assignment rules, evaluated before the declared ones; answer merge question 11 - #30828

Merged
os-zhuang merged 1 commit into
mainfrom
claude/project-thread-kl2al6
Nov 6, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/project-thread-kl2al6

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Elon · project thread

domain:server#1 · os-elon-musk · session_016WV4d14C8K4gMehVb6jBvA

Part of #30066

Clause-②: no
Metadata-protocol: none

Claim: 6672306838 (amended 6672490095, 6673262187, 6674205693, 6674382817) · Branch: claude/project-thread-kl2al6 · Ruling-ref: 6631036940 (letter A), execution parameters 6670178869

维护者速读

What changes

One file, docs/adr/0142-ownership-queue-membership-claim-and-assignment-rules.md, recording ruling A on #30066 (record 6631036940, with the execution parameters of 6670178869):

  • Status line: a new Amended (2026-11-05) entry naming the ruling: D5 gains its second source, and merge question 11 is answered.
  • TL;DR item 4: a parenthetical Amended note pointing to D5.
  • D5: a new paragraph after What the rule writes, a second source: an organization's own rules, with seven points:
    • Shape: a sys_assignment_rule row, owned by @objectstack/plugin-sharing beside sys_queue and sys_sharing_rule; organization_id NOT NULL; one rule with one entry per row.
    • One namespace: a row may not take a declared rule's name (ADR-0131 D4); a row a later-installed package shadows is not evaluated and is reported.
    • Order: first-match stays; the organization's active rows first (by sort_order, then name), the declared rules as the fallback; why the other order cannot work (the activation ledger has no organization column); a failed read of the organization's rows routes by no rule.
    • Validated on save: criteria and load compiled by the two paths the seam evaluates by; the declared schema's entry refusals; a user target must be an active member.
    • A user target at insert, from either source: owns the row only while an active member; otherwise ownerless, logged once, never refused. The os lint warning on declared user targets stands.
    • A lapsed queue target: unchanged, for both sources.
    • Out of this record's code: the dedicated Setup page is the Console's.
  • Merge question 11: an Answered (2026-11-05) sentence pointing to D5.

Why

Ruling A asks for this record. The runtime half shipped in #30760 (merged as ac890f5); this PR follows it on the same branch, serially, and is never bundled with it. Each point above states the behaviour #30760 merged, so the record and the code read the same.

Tests

None: a docs-only change to one ADR. No code, schema, generated artifact or published file moves.

Acceptance notes

Verification

Local gates at 4b26915 (dispatch-gates --commands on this diff, 21 commands)
node scripts/check-adr-links.mjs :: exit 0
node scripts/check-adr-links.mjs --self-test :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0
pnpm check:adr-anchors :: exit 0
pnpm check:adr-index :: exit 0
pnpm check:adr-symbol-anchors :: exit 0
pnpm check:ci-filter-parity :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:pm-governed-merges :: exit 0
pnpm check:pm-prior-rulings :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:watch-hint-literal :: exit 0

node scripts/pm/dispatch-gates.mjs --ran: 21 derived, 21 run, 0 NOT-MEASURED, 0 UNRUN (exit 0). node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD: 1 message clean.
CI families outside the derivation (artifact rosters, wide-population families, the type-check lanes) are CI's; this PR's check-runs are their record.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (not touched)
  • 2. Every name I added uses the casing for its kind. (none added)
  • 3. No formatter ran; pnpm lint passes. (no source file touched)
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. (publishes nothing: skip-changeset)
  • 6. packages/spec touched: its generated artifacts are regenerated and committed. (not touched)
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.

Generated by Claude Code

…ment rules, evaluated before the declared ones; answer merge question 11

D5 gains its second source: `sys_assignment_rule` rows an organization
authors in Setup, owned by plugin-sharing beside sys_queue and
sys_sharing_rule, one rule with one entry per row. The amendment records
the one namespace with declared rules, the first-match order (the
organization's rows first, by sort_order then name, the declared rules as
the fallback) and why the other order cannot work, what the save guard
refuses, and the active-member rule for a user target from either source.
Merge question 11, which deferred organization-authored routing, is
marked answered.

Claude-Session: https://claude.ai/code/session_016WV4d14C8K4gMehVb6jBvA
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Nov 6, 2026
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation labels Nov 6, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review November 6, 2026 15:06
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 4b26915ef8fb30363300e45ced377f987d727130
Local-runs: none
Scope: docs/adr/0142-ownership-queue-membership-claim-and-assignment-rules.md + packages/objectql/src/assignment-rules.ts, packages/objectql/src/engine.ts (the mayRoute call site), packages/plugins/plugin-sharing/src/assignment-rule-hooks.ts, packages/plugins/plugin-sharing/src/objects/sys-assignment-rule.object.ts, packages/plugins/plugin-sharing/src/sharing-plugin.ts (boot wiring), packages/platform-objects/src/system/sys-metadata-activation.object.ts (the ledger's columns), docs/adr/0131-total-organization-ownership-no-null-organization-id.md (D4, D6), the ruling record 6631036940 and the execution parameters 6670178869 on #30066

Head confirmed at review time: 4b26915ef8fb30363300e45ced377f987d727130 (the PR has not moved). One file, +38 / -3, merge base c17719dd6c0fbf364869872527f81a3e81d30f6a. The code this record describes is PR #30760, merged as ac890f5a, which is an ancestor of the merge base, so the diff was written against a main that already carried the behaviour.

① Derived judgments

Must-fix: none.

Should-fix (not blocking):

  1. Validated on save lists the guard's refusals with an ellipsis and leaves two out that the guard makes on every save: an object_name that is not a registered object or has no ownership-queue column (assignment-rule-hooks.ts:164-178), and a name that is not snake_case (assignment-rule-hooks.ts:147-153). Neither contradicts the text, and the ellipsis covers them, but a reader of D5 alone would not learn that a rule on a federated object is refused at save rather than warned at insert. A half-line would close it.
  2. The new Status-line entry nests parentheses, (2026-11-05, ruling A on #30066 (record …, agreed 「同意」)), so it ends in )). Readable, and ADR-0131 line 444 uses a similar inline shape, but the other two entries on this line use a flat (date, ruling … on #N, letter A). Cosmetic.
  3. Pre-existing and out of scope: the first Status-line entry links comment 6457475657 on #25769, which the API now returns 404 for. The PR keeps that text as written, which is right for an additions-only amendment; noting it so nobody reads it as this PR's link.

Confirmed, point by point, against origin/main:

  • Shape. sys_assignment_rule is owned by plugin-sharing: packages/plugins/plugin-sharing/src/objects/sys-assignment-rule.object.ts, registered beside sys-queue.object.ts and sys-sharing-rule.object.ts in the same folder and mounted at sharing-plugin.ts:658. organization_id is required: true (object L77-82), and the guard refuses a row that lands in no organization (assignment-rule-hooks.ts:137-145). One row is one rule with one entry named after the rule: authoredRuleOf (assignment-rules.ts:197-211). The columns the ADR lists (object_name, criteria, sort_order, recipient_type/recipient_id as queue or user, strategy, load, active) are the object's fields (L105-180). The cursor key stays (rule, entry, organization): roundRobin (assignment-rules.ts:631).
  • One namespace. The guard refuses a name a declared rule holds (assignment-rule-hooks.ts:154-162, via declaredRuleNames, switched on or off). A shadowed row is skipped, not evaluated, with a warnOnce at insert (assignment-rules.ts:417-424), and reported at error at boot by reportShadowedAuthoredAssignmentRules (assignment-rule-hooks.ts:277-304), called from the plugin's boot path at sharing-plugin.ts:795-796. ADR-0131 D4 is the one-namespace rule the text cites ("code-declared and environment-authored items share it", ADR-0131 L416-417).
  • Order. Organization rows are read per organization under a pinned system context, sorted by sort_order then name (assignment-rules.ts:402-415), active is filtered (L425), and the merged list is [...own, ...fallback] with the declared rules switched on by the ledger as the fallback (L339-346, L369). First match across both: assignOne returns after the first matching entry (L449-455), and a target that does not resolve returns without trying the next rule (route, L482-500), so "its target stands even when it does not resolve" holds. The ledger claim holds: sys_metadata_activation has no tenant column (sys-metadata-activation.object.ts:45-46, systemFields: { tenant: false } at L112), and switchedOn queries it by type and name only (assignment-rules.ts:661-678). A failed organization read maps to null, logs at warn, and the row is skipped (continue), never routed by the fallback (L350-359, L366-368, L402-412). apply never throws (L373-380). Pinned by ownership-queue.test.ts:545 (the "go first, fallback" describe) and L642-648 (the failed read).
  • Validated on save. criteria is compiled by ExpressionEngine.compile and load by compileCelToFilter in assignmentExpressionRefusals (assignment-rules.ts:227-244), the same two paths matches (L459-467) and leastLoaded (L587) evaluate by; the guard asks it at assignment-rule-hooks.ts:201-211. The entry shape is judged by AssignmentRuleSchema (L180-199). A user target must be member from organizationMemberStanding: a sys_member row in that organization and no ban in force (assignment-rules.ts:260-274); banned, not_member and unconfirmable are all refused (assignment-rule-hooks.ts:237-245). The guard is bound on beforeInsert and beforeUpdate (L265-267).
  • A user target at insert, from either source. routeToUser (assignment-rules.ts:535-571): member writes the owner (L557-560); otherwise the row stays ownerless with one warnOnce naming rule, user and organization (L562-570); nothing throws. The rules array merges both sources, so the declared source is tightened as the text says.
  • A lapsed queue target. route L482-500 is the same code for both sources; unchanged from the existing paragraph.
  • Out of this record's code. The Setup page is parameter 8's separate domain:ui card. The object ships a by_object list view (object L60-72), which is the "generic record list serves them" the text promises.
  • Engine call site. engine.ts:5970-5994: mayRoute(object) is a registry read (assignment-rules.ts:319-327), and apply runs after resolveSystemInsertOrganization and before the driver write, as the existing D5 text already says.
  • Ruling match. All eight execution parameters are recorded: 1 order, 2 user target, 3 lapsed queue, 4 names, 5 criteria/load, 6 tenancy, 7 this ADR PR separate and after the code PR, 8 the UI half as a separate card. Nothing the ruling or the parameters did not decide is added: the boot report and the failed-read handling are what the merged code does under ADR-0131 D4 and the existing "every other failure" paragraph, not new decisions. The text says "two paths" where parameter 5 said "the same CEL path"; the code has two, and the ADR is the more exact statement.
  • Dating and status line. Ruling record 2026-11-04T12:50Z; parameters agreed 2026-11-05T21:34Z and recorded 2026-11-05T21:36Z. The amendment is dated 2026-11-05, the agreement date, which matches how the line's second entry dates itself by its ruling records. The **Amended** (date, …) — … shape matches ADR-0005, ADR-0131 L444 and this ADR's own two earlier entries; the in-body **Answered** (date, …): shape matches ADR-0139 L339.
  • Additions only. Checked by line: of the 3 removed lines, the Status line is split-extended (the new entry is inserted before "docs/adr/** is Tier H", prefix and suffix kept byte-for-byte), TL;DR item 4 and merge question 11 are prefix-extended (the old line is a byte-for-byte prefix of the new one). 36 new lines; no existing sentence is altered.
  • Links. [Decision] Can an organization author its own assignment rules, or do they stay package-declared only? #30066 and comments 6631036940 and 6670178869 resolve (fetched). ADR-0131 D4 and D6 exist; "ADR-0131 D6 regime C" for sharing_rule is at ADR-0131 L527, and this ADR already charts queue under regime C (D1). No new in-repo anchor is introduced.

② Semver level

skip-changeset is right: docs/adr/** publishes nothing from any released package. Clause-②: no is right: no packages/spec/src/**, no published export, no narrowing. Metadata-protocol: none is right: no object, field or protocol shape moves. Check Changeset is skipped as expected.

③ Boundary flags

  • The PR body raises none. Out-of-scope items it names (the docs page and skill line under card docs+skills: teach organization-authored assignment rules (sys_assignment_rule) and the active-member rule for a user target (PR #30760) #30826; the stale "deferred" text in packages/spec/liveness/assignment_rule.json and liveness/README.md; the remaining locales) are correctly left to their own seats.
  • Author user.login is objectstack-fleet[bot]; no relay login note is owed.
  • Check-runs on the head: 41 names, latest run per name, every one success or skipped; none red, none pending. "Governed Surface Queue Guard" success; "Lint & Repo Gates", "Lint · docs & code guards" and "Check Documentation Links" success. No PR comments and no reviews on the PR at review time.
  • Mergeable: mergeable: true, mergeable_state: clean. Main has not touched ADR-0142 since the merge base (empty git log c17719dd..origin/main -- <adr>), so nothing on main conflicts with or supersedes this text.
  • Tier H: the landing is the maintainer's hand; this record is the contract review, not an approval.

④ Design judgment

The amendment holds against its first consumer, which is the code already on main (#30760 / ac890f5a): every behavioural sentence maps to a line in the evaluator, the guard or the object, as ① lists. It holds against the execution plan: the record changes no step of the plan, keeps "intake is never refused" as the invariant, and routes the UI half to a separate card exactly as parameter 8 does. The only gap is the two unlisted save refusals in should-fix 1, which is an omission in prose, not a contradiction, and does not block.

Implemented-by: claude/project-thread-kl2al6
Reviewed-by: session_016WV4cytLmJxfAmgPVjUbbW

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW

维护者速读

席位核对 · ACCEPT · 2026-11-06T15:19Z · #30066 (ADR-0142 D5 amendment, Tier H)

Head-sha: 4b26915

  • Taken over on the maintainer's order (seat thread, verbatim: 「30828 让 server 车道接手,这个好像没契约复审」). It had no contract review until record 6688304222.
  • Shape: one file, docs/adr/0142-ownership-queue-membership-claim-and-assignment-rules.md, +38 / -3, additions only apart from the three lines the amendment notes extend. Part of #30066; the card closed with the code PR feat(objectql,plugin-sharing): an organization authors its own assignment rules as sys_assignment_rule records #30760 (ac890f5a).
  • Premise measured: the review checked each of the seven D5 points against origin/main by file:line (packages/objectql/src/assignment-rules.ts, packages/plugins/plugin-sharing/src/assignment-rule-hooks.ts, engine.ts mayRoute), and ruling A (6631036940) with its eight execution parameters (6670178869). Nothing beyond them is decided.
  • Gates: 41 check names on this head, the latest run of each success or skipped, none red or pending; mergeable_state clean; main has not touched ADR-0142 since the merge base.
  • Accepted as is: two wording should-fixes (the save-validation point omits the unregistered-object and non-snake_case-name refusals; nested parentheses on the Status line) and one pre-existing dead link on the first Status-line entry, left as written in an additions-only PR.
  • Landing: Tier H (docs/adr/**). pm:awaiting-merge on this PR and review requested from os-zhuang and hotlong. After an APPROVE the seat arms auto-merge through the relay.

@objectstack-fleet objectstack-fleet Bot added the pm:awaiting-merge PR only: landing waits on the maintainer's own review and merge (SKILL.md 复核 ②); never on an issue label Nov 6, 2026
@os-zhuang
os-zhuang added this pull request to the merge queue Nov 6, 2026
@objectstack-fleet objectstack-fleet Bot removed the pm:awaiting-merge PR only: landing waits on the maintainer's own review and merge (SKILL.md 复核 ②); never on an issue label Nov 6, 2026
Merged via the queue into main with commit 3d8a835 Nov 6, 2026
55 checks passed
@os-zhuang
os-zhuang deleted the claude/project-thread-kl2al6 branch November 6, 2026 16:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants