Skip to content

refactor(plugin-sharing,spec): retire the ERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED provenance waiver with its stamp site - #19668

Merged
os-justin merged 3 commits into
mainfrom
claude/issue-16160-retire-provenance-waiver
Sep 22, 2026
Merged

os-justin merged 3 commits into
mainfrom
claude/issue-16160-retire-provenance-waiver

Conversation

@os-justin

Copy link
Copy Markdown
Collaborator

Fixes #16160

Clause-②: no

What this does

Retires the ERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED provenance waiver together with its stamp site. Both halves ship here, and neither can ship alone: check:error-code-provenance reconciles a waiver in three directions at once, so removing the stamp site alone reddens it on the stale waiver, and removing the waiver alone reddens it on the orphaned site. That is measured below, not asserted.

It was four references, exactly as triage counted

Triage's line-by-line read recorded 「删常量会连带四处引用,取卡人排期时按 4 处算,不是 2 处」. Located by symbol, not by line — every number had drifted by +21 since that read:

triage's line line on this tree what it is disposition
:137-138 :138-139 the constant itself, typed SystemWriteOrganizationRequiredError['code'] deleted; the type-only import goes with it
:1631 :1652 docblock {@link ENGINE_ORGANIZATION_REFUSAL_CODE} repointed at SYSTEM_WRITE_ORGANIZATION_REQUIRED_CODE
:1645 :1666 docblock {@link ENGINE_ORGANIZATION_REFUSAL_CODE} reworded to name the recognizer
:1683 :1704 if (err?.code !== ENGINE_ORGANIZATION_REFUSAL_CODE) throw err; now if (!isSystemWriteOrganizationRequiredError(err)) throw err;
:1691 :1712 code: ENGINE_ORGANIZATION_REFUSAL_CODE, now code: SYSTEM_WRITE_ORGANIZATION_REQUIRED_CODE, — see the judgement below

Four references plus the declaration. After the edit git grep ENGINE_ORGANIZATION_REFUSAL_CODE over packages/ returns nothing.

The :1691 judgement, stated rather than carried along

The card and triage both flagged this site as a separate judgement, on the reading that plugin-sharing emits the code there in its own refusal envelope. On this tree that reading does not hold, and this PR records why.

:1712 is not an envelope. It is the second argument of this.logger?.warn?.(message, meta) — a structured log field on the refusal the catch has just absorbed. The enclosing method's own contract is explicit that nothing leaves it carrying this code: "Returns true when the grant landed, false when it was refused — never throws for the refusal, and the caller counts what it is told." So plugin-sharing recognises this code and reports what it absorbed; it emits it nowhere.

Two consequences, both deliberate:

  • The waiver's premise 「Matches the code, never emits it」 survives the re-read — it was never resting on the site the card suspected. Nothing here needs re-adjudicating, and the waiver is retired on its own stated expiry rather than on a changed premise.
  • So the site takes the published constant, and this is not the "larger change" branch. There is no re-emission to stop, so widening the card into one would be a change with no defect under it. The engine's own SYSTEM_WRITE_ORGANIZATION_REQUIRED_CODE is the right value for a log field that must name the code, and an identifier in code: position is not a check:error-code-provenance stamp site — the objlit pattern matches a quoted literal only.
  • It is pinned, and was before this PR. field-recipient.test.ts asserts the warn payload carries code: 'ERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED', and separately that a grant refused with any other code rethrows. Both stay green, so the swap is proven to have moved neither the reported code nor the width of the catch.

Premise re-measured on this tree, against the built artifact

The card's whole basis is that @objectstack/objectql publishes the recognizer. Measured at packages/objectql/dist/index.d.ts, not at source:

2231:declare const SYSTEM_WRITE_ORGANIZATION_REQUIRED_CODE: "ERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED";
2277:declare function isSystemWriteOrganizationRequiredError(err: unknown): boolean;
3246:export { …, SYSTEM_WRITE_ORGANIZATION_REQUIRED_CODE, …, isSystemWriteOrganizationRequiredError, … };

plugin-sharing declares @objectstack/objectql in dependencies and its tsconfig carries no paths remap, so the compiler reads that declaration file through the package exports. A negative control proves the reading is live rather than cached: renaming the imported member to one objectql does not export turns the package typecheck red with

src/sharing-rule-service.ts(39,3): error TS2724: '"@objectstack/objectql"' has no exported member named
  'isSystemWriteOrganizationRequiredErrorNOSUCHEXPORT'. Did you mean 'isSystemWriteOrganizationRequiredError'?

and the restore is proven byte-identical (blob == HEAD, git diff HEAD empty).

check:error-code-provenance — the load-bearing gate, before and after

Both readings are from pnpm --filter @objectstack/spec run check:error-code-provenance, exit code captured before any pipe.

Before (exit 0):

scanned 2411 files; 339 registered-code stamp site(s): 322 listed, 17 waived
OK — every registered-code stamp site is listed under its own owner key or carries a recorded waiver (10 waiver(s), all live)

After (exit 0):

scanned 2411 files; 338 registered-code stamp site(s): 322 listed, 16 waived
OK — every registered-code stamp site is listed under its own owner key or carries a recorded waiver (9 waiver(s), all live)

Sites 339 → 338, waived 17 → 16, waivers 10 → 9, and listed unmoved at 322 — the drop triage asked to be confirmed, in each of the three counts. --report before the edit named exactly one waived site for the pair, packages/plugins/plugin-sharing/src/sharing-rule-service.ts:138 (constdef); it is absent after.

"One PR or neither" — measured, in both directions

Two one-legged ablations through scripts/ablation-replace.mjs, each committed-state, each with its on-disk landing proven and its restore proven (blob == HEAD, git diff HEAD empty). Predicted direction before running: red, both.

A. The stamp site back, the waiver still gone — the catch re-spelled as a local *_CODE constdef:

scanned 2411 files; 339 registered-code stamp site(s): 322 listed, 16 waived
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:1705 — not listed under its own owner key

B. The waiver back, the stamp site still gone:

scanned 2411 files; 338 registered-code stamp site(s): 322 listed, 16 waived
FAIL — 1 provenance-waiver problem(s):
  waiver @objectstack/plugin-sharing → ERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED matches NO stamp site in the scan —
  its subject is gone (or moved beyond the published patterns); remove the waiver, or extend STAMP_PATTERNS …

Each half reddens the gate on its own, as the card said. The green above is therefore a reading, not a vacuum. Neither ablation left anything behind: the working tree is clean at the final commit.

Verification

All readings taken at 17e22cbd1 (the final commit, origin/main merged in at 8f30c188a).

  • Derived gates: 83 derived, 83 run, 0 NOT-MEASURED, 0 UNRUN, all exit 0. Derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack after the changeset existed, exit codes captured before any pipe, reconciled with --ran carrying each command's code. Two gates first answered exit 3 PREREQUISITE NOT MET rather than a verdict — check:dual-build-cjs-loads and check:i18n; both prerequisites were built and both re-ran green (104 published require entry point(s) across 67 package(s) load; 9 package(s) — all bundles in sync).
  • pnpm --filter @objectstack/spec --filter @objectstack/plugin-sharing run typecheck — exit 0, both packages including their script and test layers.
  • pnpm --filter @objectstack/plugin-sharing test — Test Files 37 passed (37), Tests 913 passed (913).
  • pnpm --filter @objectstack/spec test — Test Files 512 passed (512), Tests 14953 passed | 1 todo (14954).
  • pnpm --filter @objectstack/spec check:generated — All 15 generated artifacts are up to date. Nothing to regenerate: no schema, no export and no authorable key moved.
  • pnpm lint (repo-wide, not narrowed) — eslint . --no-inline-config, exit 0, 6996 files linted, 0 errors, 0 warnings, file count read from --format json.
  • Heavy runs went through scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-16160; every verdict is its VERDICT command-exit line, never a bare shell status.

Changeset

patch for both @objectstack/spec and @objectstack/plugin-sharing, judged against each package.json's files[] after a build rather than by inspection:

  • @objectstack/plugin-sharing ships dist. Its built dist/index.js and dist/index.mjs now contain isSystemWriteOrganizationRequiredError and no longer contain ENGINE_ORGANIZATION_REFUSAL_CODE (positive control: an unrelated symbol in the same file still matches). Published bytes moved.
  • @objectstack/spec ships both dist and src/**/*.zod.ts, and error-code-ledger.zod.ts matches that second entry — so the edited file ships twice over, compiled and verbatim. The retired waiver's reason text is absent from dist after the build (positive control: a sibling waiver's reason still matches).

So skip-changeset is not available to this diff on either package.

Acceptance notes

  • sharing-service.ts mentions the literal ERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED in two docblocks. Those are comments, the gate masks comments before scanning, and both statements are accurate about the engine's refusal — an observation, not a finding, and deliberately untouched.
  • Nothing in the (a)/(b)/(c) filing classes turned up on this diff.

维护者速读(草稿)

改了什么

删掉了一条「到期债务」:plugin-sharing 过去自己抄了一份引擎错误码的字面量,台账里为此挂了一条豁免记录。现在引擎自己把识别函数发布出来了,plugin-sharing 改用它,那条豁免记录随之删除。两处改动必须同一个 PR,分开做任何一半都会让门禁变红。

为什么改

那条豁免记录自己写了到期条件——「等 objectql 发布识别器后,与打码点一起删除」——而没有任何门禁会在条件满足时提醒任何人。不删,它就从一条有期限的记录变成永久居留,下一个读台账的人会以为这是个长期决定。本次改动同时消掉一处重复的字符串字面量:抄写的那一份一旦和引擎抛出的不一致,失效形态是一个永远不会触发的 catch,不是一个失败的测试。

风险与代价(含回滚)

风险低。对外错误面零变化:ERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED 仍然注册在 @objectstack/objectql 名下,ERROR_CODE_LEDGER 与 StandardErrorCode 的成员一个没动,本次只动了 PROVENANCE_WAIVERS 数组里的一个元素。吸收范围也没变宽:两个既有测试分别钉住「吸收这一个码」与「别的码照样抛出」,都是绿的。回滚 = revert 这一个 PR;两处改动在同一次提交里,不存在只回滚一半的形态。

席位意见

你要做的

无需动作。这是记账债务的按期兑付,不是行为变更;Clause-②: no,两个包各一条 patch changeset 已随 PR 提交。


Generated by Claude Code

…ON_REQUIRED provenance waiver with its stamp site

plugin-sharing recognised the engine's organization refusal through a local
re-spelling of the literal (`ENGINE_ORGANIZATION_REFUSAL_CODE`), which is a
`check:error-code-provenance` `constdef` stamp site for a code this package
only ever matches. The waiver that excused it carried its own expiry: removed
together with the stamp site once objectql published a recognizer.

objectql now publishes `SYSTEM_WRITE_ORGANIZATION_REQUIRED_CODE` and
`isSystemWriteOrganizationRequiredError` for exactly this consumer, so the
compare is performed without authoring the string here. Both halves ship
together because the gate reconciles a waiver in three directions at once and
either half alone reddens it.

Claude-Session: https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1
Co-authored-by: Claude <noreply@anthropic.com>
…ring

Both packages' published `files[]` content moves: plugin-sharing's `dist`
drops the local constant and gains the engine recognizer call, and spec ships
`error-code-ledger.zod.ts` both compiled into `dist` and verbatim through its
`src/**/*.zod.ts` entry.

Claude-Session: https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling labels Sep 22, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/plugin-sharing, @objectstack/spec, touching 6 documentable anchor(s).

⛔ 1 release-owned page(s) name something this change touched. These are read-only:

  • content/docs/releases/v17/17-3.mdx (via ERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED (literal, a string literal in ENGINE_ORGANIZATION_REFUSAL_CODE; a string literal in PROVENANCE_WAIVERS))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 2 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 60 of 215 client-bound route-ledger rows — the other 155 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 155: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 100 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 136 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json d3a233192d6def825f64c314ce122ce29b890699 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 33fe159dc9391abe5aa2c23153aaa337be5eee87 — the merge of head 17e22cbd1f2070e95f9faa5569e6d032ac3f443e into base d3a233192d6def825f64c314ce122ce29b890699, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 33fe159dc9391abe5aa2c23153aaa337be5eee87 && git checkout 33fe159dc9391abe5aa2c23153aaa337be5eee87
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin d3a233192d6def825f64c314ce122ce29b890699 17e22cbd1f2070e95f9faa5569e6d032ac3f443e && git checkout -B drift-repro d3a233192d6def825f64c314ce122ce29b890699 && git merge --no-ff 17e22cbd1f2070e95f9faa5569e6d032ac3f443e

node scripts/docs-audit/affected-docs.mjs --json d3a233192d6def825f64c314ce122ce29b890699

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs d3a233192d6def825f64c314ce122ce29b890699 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 17e22cbd1f2070e95f9faa5569e6d032ac3f443e

In-seat at tier. Clause-②: no. The domain:spec lane owes this record on every round it delivers, no included. Taken 2026-09-22T05:47Z, read off the branch source and the API; ⛔ not off the dev's report.

① Derived judgments

⭐ The headline is a correction, and it overturns BOTH the card and triage — verified by this seat in the source, ⛔ not accepted on the dev's word. The card and triage 5556867586 both describe the fourth site as plugin-sharing 「在自己的拒绝信封里再发一次该 code」. Read on origin/main before the diff:

if (err?.code !== ENGINE_ORGANIZATION_REFUSAL_CODE) throw err;
this.logger?.warn?.(
  '[sharing-rule] grant refused by the engine organization rule — counted, pass continues',
  { rule, object, record, recipient, code: ENGINE_ORGANIZATION_REFUSAL_CODE },
);
return false;

⇒ that code: is a field in the second argument of logger.warn(message, meta) — a structured log field. It is ⛔ not a refusal envelope: the method return falses and nothing leaves it carrying the code.

Consequence, and it is the one that matters: the waiver's premise 「Matches the code, never emits it」 survives the re-read. It never rested on that site, so the waiver retires on its own stated expiry and ⛔ nothing needs re-adjudicating. The dispatch reserved a 「stop and report」 branch for a real re-emission; there is none, so the site correctly takes the published constant with the other three.

Site count and drift, re-read by this seat: 5 occurrences = 1 declaration + 4 references — exactly triage's 「按 4 处算,不是 2 处」. All five had drifted +21 lines since the 2026-09-06 read (137→138, 1631→1652, 1645→1666, 1683→1704, 1691→1712), which is why the dispatch required locating by symbol.

The local spelling is gone: git grep ENGINE_ORGANIZATION_REFUSAL_CODE over packages/ on the branch ⇒ 0, with a positive control in the same file (isSystemWriteOrganizationRequiredError ⇒ 3) so the zero is a real zero.

The import comment earns its place — it now records why a code compare rather than instanceof: 「instanceof is unsound across the dual build and fails SILENTLY, as a catch that never fires」. That is the failure mode this class of code actually has.

「One PR or neither」 is measured, ⛔ not asserted. Two one-legged ablations, each restored with proof: (A) stamp site back, waiver gone ⇒ 「FAIL — 1 stamp site(s) of a registered code with no provenance row」; (B) waiver back, stamp site gone ⇒ 「FAIL — 1 provenance-waiver problem(s): … matches NO stamp site in the scan」. That is exactly the three-way reconciliation the card said would redden on either half alone.

② Semver level

Patch on both @objectstack/spec and @objectstack/plugin-sharing, and skip-changeset is unavailable — re-verified by this seat rather than taken on the category: packages/spec's files[] is [dist, json-schema, liveness, prompts, llms.txt, README.md, **src/**/*.zod.ts**, CHANGELOG.md, api-surface, spec-changes.json], and the edited packages/spec/src/api/error-code-ledger.zod.ts matches that entry ⇒ the file ships verbatim as well as compiled. A changeset is owed and exists.

Clause-②: no confirmed on the tree: ERROR_CODE_LEDGER / StandardErrorCode membership does not move — ERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED stays registered under the @objectstack/objectql owner key, and the only ledger change is one element of the PROVENANCE_WAIVERS array.

③ Boundary flags

  1. ⚠️ This seat could NOT re-run check:error-code-provenance — no node_modules in this checkout, which is a prerequisite failure that measures nothing. So its before/after (sites 339→338, waived 17→16, waivers 10→9, listed unmoved at 322) is the dev's reading, ⛔ not this seat's. It does not stand alone, though: the two ablations above are its discriminating controls, and both reddened in the predicted direction.
  2. ⚠️ File surface: a third file. The claim declared two; the diff carries .changeset/…md. ⛔ Not a breach — a changeset is the mandated companion of a publishing diff, and § ② shows both packages publish. Declared by the dev rather than absorbed.
  3. ⚠️ Two gates first answered exit 3 PREREQUISITE NOT MET (check:dual-build-cjs-loads, check:i18n) and measured nothing. Both prerequisites were built and both re-ran green; only the exit-0 rerun is recorded, and ⛔ neither exit 3 is reported as a pass or as a finding. Correct handling of the trap this shift hit four separate times.
  4. ⚠️ origin/main advanced during flight (5ce370505 → 8f30c188a, one file — scripts/check-tenant-audit-census.mjs, which the gate derivation reads). Merged in, that gate and its --self-test re-run green, then re-derived; the final reconciliation carries no STALE TREE warning. ⭐ Note the coincidence: that one file is this seat's own landing fix(scripts): decouple the clean-census self-test control from the live tree #19651.
  5. ⚠️ CI is still converging at this reading — 32 distinct checks, 13 success, 3 skipped, 16 incomplete, zero non-green. This PASS is a verdict on the diff; enqueue waits on green read latest-per-name.
  6. ℹ️ Gates 83 derived / 83 run / 83 exit 0. mcp_calls: 0. Occupancy re-checked by the dev at push time over 23 open PRs (this seat's census read 19 — main moved), both landing paths still free.

Implemented-by: claude/issue-16160-retire-provenance-waiver
Reviewed-by: session_01Sfe5YjBLwB9J3y8fvm2xq1

VERDICT: PASS


Generated by Claude Code

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 tooling

Projects

None yet

2 participants