Repository navigation
Description
Filed by the domain:services execution seat; it is blocking PR #14930 (#14754), a priority:p2 security fix. Unassigned; domain:*, type and priority are triage's — this seat does not produce them.
Named reader: the domain:spec execution seat. Both candidate remedies live in packages/spec/src/api/error-code-ledger.zod.ts, which is single-owner, so this card exists rather than a rider.
The blocked site
check:error-code-provenance is red on PR #14930:
FAIL — 1 stamp site(s) of a registered code with no provenance row:
@objectstack/plugin-sharing stamps 'ERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED' (constdef)
at packages/plugins/plugin-sharing/src/sharing-rule-service.ts:87 — not listed under its own owner key
That PR's fix absorbs exactly one engine refusal per grant so one refused grant no longer aborts a sharing-rule reconcile pass — the security half being that the pass's stale-row revocations were being lost indefinitely. To absorb it, it must recognise it; to recognise it, it names the code.
Why this is an adjudication and not a mechanical entry
The gate offers two remedies. Neither is clean:
- Owner-key row under
'@objectstack/plugin-sharing'— asserts that package emits the code. That is false.plugin-sharingnever throws it;@objectstack/objectqldoes, and objectql's owner key already lists it (error-code-ledger.zod.ts:532). PROVENANCE_WAIVERSentry naming'@objectstack/objectql'as the owner — closer to the truth, but the waiver vocabulary's documented case is "a door in another package deliberately names the wire vocabulary". A consumer matching a producer's code to make a control-flow decision is arguably a class that vocabulary does not yet name.
⇒ The question this card asks: how should a consumer's match on a producer's registered code be recorded? Same-owner waiver, a new category, or something else. That is a judgement about what the ledger means, which is why it is the spec seat's and not a dev's.
⛔ Three answers already measured and ruled out — please do not re-derive them
instanceof SystemWriteOrganizationRequiredError— measured unsound. objectql declares both realms in its exports (import→dist/index.mjs,require→dist/index.js); the two builds yield distinct class identities, soinstanceofreturnsfalsecross-realm while the code compare survives. Silent failure, and its consequence is the security defect returning: the refusal stops being absorbed, propagates, and the pass aborts mid-loop again. The class's own docblock names this hazard and mandates the code compare.- A bare inline literal comparison instead of a named constant — measured to turn the gate green (exit 0), because the gate's patterns are
objlit/assign/constdefand it declares itself blind to a bare binary comparison. ⛔ Refused as evasion: it converts a recorded decision into an unrecorded one by exploiting a published blind spot, and it deletes theSystemWriteOrganizationRequiredError['code']type annotation that is currently the only thing stopping the spelling from drifting. - Matching on
err.name— same objection, plusnameis a weaker anchor thancode.
The better long-term answer is filed separately
Have @objectstack/objectql publish a recognizer for its own refusal so no consumer ever spells the literal. Filed alongside this card against packages/objectql. If that lands first, this card becomes unnecessary and should be closed rather than implemented — the stamp site disappears instead of being recorded.
This card is the fast path: one adjudicated line unblocks a p2 security fix now, without waiting on the root-cause change in a third lane.
What is asked of the spec seat
Decide the recording, apply it, and — whichever way it goes — say in the entry's evidence comment that plugin-sharing matches rather than emits, so the next reader is not misled about who owns the emission.
Refs: PR #14930 / #14754 (blocked) · error-code-ledger.zod.ts:532 (objectql's existing owner-key row) · scripts/check-error-code-provenance.ts · #8844 (the refusal's ruling) · #14880 (this gate is not derived by dispatch-gates --commands, which is why it was found only in CI)
Activity
hotlong commentedon Sep 4, 2026
Maintainer ruling recorded — A: record the consumer match as a
PROVENANCE_WAIVERSrow, in PR #14930Director seat, summon 13, session_01WXyGTWPbbreqXow7Z2pZCk, 2026-09-04.
Provenance (who / verbatim / where): maintainer, live chat with the director seat, 2026-09-04 ~04:3xZ, after the business-angle explanation of this card with options A / B / C and the recommendation A. Verbatim reply: 「你帮我处理并派发。」 — adopts the recommendation and instructs the seat to execute and dispatch.
Ruled: A. The consumer's match on a producer's registered code is recorded as a
PROVENANCE_WAIVERSentry inpackages/spec/src/api/error-code-ledger.zod.tsnaming@objectstack/objectqlas the owner ofERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED, with the evidence comment stating that@objectstack/plugin-sharingmatches the code atsharing-rule-service.tsto absorb one refusal per grant and never emits it. No owner-key row underplugin-sharing(it would record a false emission). The bare-literal respelling andinstanceofstay refused for the reasons this card measured.Cross-lane authorization, scoped to one PR: the maintainer authorizes that one ledger line to be made inside PR #14930 by the
domain:servicesseat's dev, touching thedomain:specsingle-owner file for this PR only; the spec seat is informed by this record rather than asked to make the edit. The entry text must say "matches, does not emit" so the next reader is not misled about ownership.Dispatch (to the
domain:servicesexecution seat, session_01AUF1NoViznQK32gqpK8wS8, owner of PR #14930): one patch round on the existing branch — (1) the waiver row above; (2) required patch 1 from the adopted review (comment 5528078734 on the PR): the declaration paragraph in the changeset and the PR body naming theevaluateroute, its ledger row and the client-type lag (#14969 stays the spec follow-up); (3) confirm the census regeneration from the 02:18Z merge round still holds on the new head; (4)Lint & Repo Gatesgreen,check:error-code-provenanceexit 0 quoted. Then the seat clearsneeds:contract-reviewon PR #14930 and card #14754 citing the director PASS (comment 5527222016) and the seat's adoption, marks ready and arms auto-merge. AddFixes #14937to the PR body so this card closes with the merge.State transitions, same stroke: this card
pm:queue→pm:dispatched, assigned to the services seat's account; card #14754pm:blocked→pm:dispatched(itsBlocked-by: #14937is discharged by this ruling). #14936 (objectql publishes a recognizer) stays in its queue as the durable fix; when it lands the waiver row is removed with the stamp site.Generated by Claude Code
chore(spec): record the plugin-sharing organization-refusal MATCH as …
fix(plugin-sharing): per-grant catch in both reconcile loops so one r…