Skip to content

feat(spec): register NAMESPACE_CONFLICT in ERROR_CODE_LEDGER - #16252

Merged
huangyiirene merged 3 commits into
mainfrom
claude/issue-14748-register-namespace-conflict-error-code
Sep 6, 2026
Merged

feat(spec): register NAMESPACE_CONFLICT in ERROR_CODE_LEDGER#16252
huangyiirene merged 3 commits into
mainfrom
claude/issue-14748-register-namespace-conflict-error-code

Conversation

@huangyiirene

@huangyiirene huangyiirene commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator

Fixes #14748

NAMESPACE_CONFLICT is registered in ERROR_CODE_LEDGER under @objectstack/objectql, so the ADR-0048 install-time namespace refusal now carries its own code on the wire instead of riding the open declaredCode sibling.

Landing round — main merged, the one conflict reconciled by hand, the docs regenerated

The head was mergeable_state: dirty. PR #16159 landed on main after this branch's base and rewrote the very row this PR deletes in packages/runtime/src/dispatcher-error-vocabulary.ts (shape: 'classfield' becoming 'classconst', since the producer literal became the exported NAMESPACE_CONFLICT_CODE constant). Landed via git merge origin/main per this repo's convention — no rebase, no force-push.

File surface touched this round, declared up front: packages/runtime/src/dispatcher-error-vocabulary.ts (the conflict), and content/docs/references/api/contract.mdx + content/docs/references/api/error-code-ledger.mdx (regenerated). The merge forced nothing outside that list; the PR's file count is unchanged at 6.

The conflict. One conflicted path, dispatcher-error-vocabulary.ts, and it is the whole-block-delete-versus-edit shape: this branch removes the NAMESPACE_CONFLICT row, main edited a line inside it. Taken as main's file with that row block deleted. Verified rather than asserted — git diff origin/main -- packages/runtime/src/dispatcher-error-vocabulary.ts reads 42 deletions, 0 insertions, i.e. exactly the row block and nothing else, and main's two other classconst conversions in the same file are untouched. The row is 42 lines now rather than 38 because main added four comment lines inside it.

The generated docs did not text-merge, and the arithmetic is why. Both sides independently bumped +295 to +296 on ApiErrorSchema.code; a textual merge yields 296 and is silently wrong, because FIND_HOOK_RESULT_NOT_ARRAY also landed on main in the window. The merge=os-regen driver deferred both files, scripts/pm/os-regen-merge.sh's ordering was followed (merge committed first, then regeneration as its own commit), and the number was read off the generator rather than predicted: pnpm --filter @objectstack/spec gen:schema && gen:docs produces +297 more, and check:generated then reports all 15 artifacts up to date. Against origin/main the two files differ by exactly 3 lines: +296 becoming +297, and one NAMESPACE_CONFLICT list row in each file.

check:error-code-provenance is now a LIT instrument on this code. At the pre-merge head its --report showed 0 rows for NAMESPACE_CONFLICT against 1 for the MULTI_UPDATE_HOOK_KEY_DIVERGENCE control — the gate is blind to class fields, so its green said nothing about the ownership key. After the merge, main's post-#16159 registry.ts carries export const NAMESPACE_CONFLICT_CODE = 'NAMESPACE_CONFLICT' as const, which the gate's constdef pattern does see. Re-measured on the merged head:

[listed] @objectstack/objectql -> MULTI_UPDATE_HOOK_KEY_DIVERGENCE (constdef) packages/objectql/src/multi-update-hook-key-divergence.ts:134
[listed] @objectstack/objectql -> NAMESPACE_CONFLICT (constdef) packages/objectql/src/registry.ts:1306
OK - every registered-code stamp site is listed under its own owner key or carries a recorded waiver

Both codes at 1 row, gate OK over 311 stamp sites (295 listed, 16 waived). The @objectstack/objectql ownership key this PR relies on is therefore proven now, not assumed.

The wire, measured before and after

Not derived. Both bodies were printed by a throwaway probe driving the shipped route — HttpDispatcher.handlePackages('', 'POST', manifest, {}, adminCtx) over a real SchemaRegistry, two installs declaring one namespace — with packages/spec rebuilt for each leg. The probe is not in the diff; the durable assertion is, as packages/runtime/src/package-door-namespace-conflict-code.test.ts.

Before (the ledger row removed, spec rebuilt — the ablation leg):

{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Namespace conflict: namespace \"crm\" is already owned by package \"com.acme.crm\", so package \"com.beta.crm\" cannot be installed alongside it. …","httpStatus":422,"declaredCode":"NAMESPACE_CONFLICT"}}

After (this branch):

{"success":false,"error":{"code":"NAMESPACE_CONFLICT","message":"Namespace conflict: namespace \"crm\" is already owned by package \"com.acme.crm\", so package \"com.beta.crm\" cannot be installed alongside it. …","httpStatus":422}}

Status 422 and the message are byte-identical across the two legs (both elided at the same point above). What changes is that the closed error.code slot carries the producer's own spelling, and declaredCode is gone rather than duplicated — with the code registered, demotedDeclaredCode has nothing to demote. The first install answered 201 on both legs, so the refusal is a refusal and not a vacuous second failure.

The card's open question: both halves ship in this PR, and the gates leave no choice

The card asked whether the runtime pending-registration row comes out here or in a follow-up. It comes out here, and the answer is mechanical rather than a preference:

direction what reds
register, leave the row check:dispatcher-error-vocabulary reports now-registered — "the row has done its job and must come out"; and error-envelope.conformance.test.ts's ratchet case, every pending code is still unregistered, fails
remove the row, don't register measured during the ablation: check-dispatcher-error-vocabulary: 1 finding(s) — [unclassified-site] packages/objectql/src/registry.ts stamps unregistered code 'NAMESPACE_CONFLICT' and packages/runtime/src/dispatcher-error-vocabulary.ts does not classify it

So the two halves are mutually required: either one alone is a red PR. This also matches the precedent the card cites — a5302c7a3 / PR #7224 for FILE_FIELD_BULK_WRITE_REFUSED, and the closer UNIQUE_SCOPE_CONFIRMATION_REQUIRED registration, whose own changelog entry records that "the now-discharged pending-registration row ratchets out of packages/runtime's dispatcher-error-vocabulary table in the same change".

The cross-package file surface was declared in the claim comment before any edit, per the cross-domain exception: packages/spec/src/api/error-code-ledger.zod.ts plus packages/runtime/src/dispatcher-error-vocabulary.ts.

What is in the diff

  • packages/spec/src/api/error-code-ledger.zod.ts — one member on the @objectstack/objectql list, with the house-style comment recording the producer, why the refusal is wire-reachable, and why it is neither a VALIDATION_ERROR synonym nor a duplicate of @objectstack/metadata-protocol's NAMESPACE_PREFIX. standardSynonymOf does not flag it (no reason-phrase alias; NAMESPACE is a token no standard member carries), so no STANDARD_SYNONYM_WAIVERS entry is owed — asserted by the admission gate, not by this paragraph.
  • packages/objectql is the right owner key, mechanically — the stamp site in packages/objectql/src/registry.ts is the only one in packages/** non-test source, so check:error-code-provenance is satisfied by the owner key alone. Since objectql: 11 error classes still spell their code as an inline literal, so a consumer cannot follow the by code, not instanceof convention the docs already teach #16159 that site is the exported NAMESPACE_CONFLICT_CODE constant, which the gate can actually see — the reading above.
  • packages/runtime/src/dispatcher-error-vocabulary.ts — the discharged row and its comment block, 42 lines, removed whole.
  • content/docs/references/api/{contract,error-code-ledger}.mdx — regenerated from the merged tree, never by hand and never text-merged. The visible delta against main is one list row in each file plus +296 more becoming +297 more on ApiErrorSchema.code — the union of both sides' additions, which is the contract change stated as a number.
  • packages/runtime/src/package-door-namespace-conflict-code.test.ts — the durable pin (see below).
  • A changeset, minor on @objectstack/spec and @objectstack/runtime. Runtime is named explicitly because the wire change is served by its door, and a reader of runtime's release notes needs it. The summary leads with the disclosure and scopes the denial after it, rather than the other way round.

The pin, and what it discriminates

Three sections, and section 3 is why the other two mean something:

  1. the real route over a real SchemaRegistry answers 422 / NAMESPACE_CONFLICT / no declaredCode;
  2. ErrorCode.safeParse('NAMESPACE_CONFLICT') succeeds, and standardErrorCodeForHttpStatus(422) is not this member — so a body carrying it proves the producer's code was carried through, never re-derived from the status;
  3. an unregistered spelling at the same door still demotes. Without this, section 1 would also be satisfied by a door that carries every producer spelling verbatim, which is the pre-[Decision] The dispatcher's error.code has a limb authored by TENANTS at runtime — registration cannot close it, and ADR-0112 does not say what should happen there #9106 behaviour the narrowing removed.

Only the kernel's service lookup is doubled. The refusal, the terminal catch, resolveThrownHttpError's registered-or-demoted decision and buildApiError are all shipping code.

Reverse verification — direction predicted before running

Run on the pre-merge head; the merge changed neither the ledger member nor the pin, so it is not re-taken here.

Prediction: removing 'NAMESPACE_CONFLICT' from the ledger and rebuilding packages/spec turns sections 1 and 2 red and leaves section 3 green in both directions.

Measured, from a committed base (the fix was committed first, so the restore leg had a real restore point):

  • mutation landed on disk: anchor count 1 -> 0, blob 8da9043d… becoming cb03cd28…, git diff --numstat = 0 1;
  • the mutation reached the artifact the suite consumes: ablation-dist-preflight @objectstack/spec with --absent — "marker absent from all 218 built files";
  • result: 2 failed | 54 passed — sections 1 and 2 red, section 3 green, and error-envelope.conformance.test.ts green throughout. Direction as predicted;
  • restore leg: git checkout HEAD -- …, blob back to 8da9043d…, whole-tree git status --porcelain empty, spec rebuilt, preflight without --absent — "marker present in 6 built files", "working tree clean against HEAD". The pin then ran 64 passed again.

The first attempt at the preflight used the single-quoted marker, which only ever appears in the sourcemap; the tool refused that reading as void on the restore leg and the legs were re-taken with the double-quoted form, the one the built JS actually carries. Recorded because the void reading would otherwise look like a passing one.

Verification, re-taken on the merged head

At eca3ca8e48, after pnpm install --frozen-lockfile and a full pnpm build (72/72 tasks):

  • pnpm --filter @objectstack/runtime test — 236 files / 3330 passed; pnpm --filter @objectstack/spec test — 482 files / 13102 passed
  • pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 src/package-door-namespace-conflict-code.test.ts — 1 file / 3 passed
  • pnpm --filter @objectstack/runtime typecheck and pnpm --filter @objectstack/spec typecheck — both exit 0
  • pnpm check:dispatcher-error-vocabularyOK — 65 unregistered code-stamping site(s), all classified; 2 awaiting a ledger entry, over 304 registered codes (254 ledger + 50 standard)
  • pnpm --filter @objectstack/spec check:generatedAll 15 generated artifacts are up to date
  • all 99 gate commands derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack from this diff — every one green, reconciled with --ran: 99 derived famil(ies) accounted for — 99 run, 0 NOT-MEASURED. The three that refused with PREREQUISITE NOT MET on the previous round (check:skill-examples, check:dual-build-cjs-loads, check:type-check-debt) were re-run after the full build and pass; check:type-check-debt needs NODE_OPTIONS=--max-old-space-size=6144, the value lint.yml sets for that same step, or its re-measure exits on heap exhaustion without measuring.
  • pnpm lint — the repo-wide eslint . --no-inline-config, exit 0. No narrowing was needed, so the population is the whole tree rather than a subset. Run at this head, eca3ca8e48.

Not addressed here


Generated by Claude Code

`POST /api/v1/packages` now answers an install-time namespace collision
with `error.code: "NAMESPACE_CONFLICT"` instead of the generic member 422
derives. The refusal has carried the ADR-0112 envelope (`code` +
`status: 422`) since the engine half landed, but the code was not an
`ErrorCode` member, so the dispatcher door's narrowing demoted the
spelling onto the open `declaredCode` sibling and put `VALIDATION_ERROR`
in the closed slot. A caller wanting to tell "your namespace is taken,
rename it" from every other 422 had to read the channel ADR-0112 declares
as not guaranteed.

Registered under `@objectstack/objectql`, the package whose
`SchemaRegistry.installPackage` stamps it (the only stamp site in
`packages/**` non-test source, so the provenance gate is satisfied by the
owner key alone).

The now-discharged `pending-registration` row ratchets out of
`packages/runtime/src/dispatcher-error-vocabulary.ts` in the same commit:
registration is what makes that row stale, and both the gate
(`check:dispatcher-error-vocabulary`) and the conformance suite's
ratchet case red on a registered code that still carries one, so the two
halves cannot be split across PRs.

`packages/runtime/src/package-door-namespace-conflict-code.test.ts`
drives the real route over a real `SchemaRegistry` and asserts the body,
so the reachability the removed row asserted without pinning is now held
by a test.

Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions github-actions Bot added the size/m label Sep 6, 2026
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/runtime, @objectstack/spec, touching 4 documentable anchor(s).

10 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/api/client-sdk.mdx (via ERROR_CODE_LEDGER (symbol, a top-level const object))
  • content/docs/api/error-catalog.mdx (via ERROR_CODE_LEDGER (symbol, a top-level const object))
  • content/docs/api/error-handling-server.mdx (via ERROR_CODE_LEDGER (symbol, a top-level const object))
  • content/docs/getting-started/examples.mdx (via /api/v1/packages (route, a path literal in ERROR_CODE_LEDGER; a path literal in why))
  • content/docs/kernel/contracts/data-engine.mdx (via ERROR_CODE_LEDGER (symbol, a top-level const object))
  • content/docs/kernel/contracts/metadata-service.mdx (via /api/v1/packages (route, a path literal in ERROR_CODE_LEDGER; a path literal in why))
  • content/docs/kernel/services-checklist.mdx (via /api/v1/packages (route, a path literal in ERROR_CODE_LEDGER; a path literal in why))
  • content/docs/permissions/permission-sets.mdx (via /api/v1/packages (route, a path literal in ERROR_CODE_LEDGER; a path literal in why))
  • content/docs/protocol/kernel/http-protocol.mdx (via /api/v1/packages (route, a path literal in ERROR_CODE_LEDGER; a path literal in why))
  • content/docs/ui/apps.mdx (via /api/v1/packages (route, a path literal in ERROR_CODE_LEDGER; a path literal in why))

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

  • content/docs/releases/v17.mdx (via ERROR_CODE_LEDGER (symbol, a top-level const object), /api/v1/packages (route, a path literal in ERROR_CODE_LEDGER; a path literal in why))

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
  • 4 name(s) were too generic to anchor anything (single lowercase words)
  • 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.

Coarse fallback — 135 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 dacb73f4fc3cd3b3ad55d766047b1e4d6f2c521apackageMentionDocs.

Which tree this was computed on

This run read content/docs from dc46442fecd84cfa802ce578cfe33c96de8442b5 — the merge of head eca3ca8e485699c6ded048dfcb72711c95c4dff0 into base dacb73f4fc3cd3b3ad55d766047b1e4d6f2c521a, 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 dc46442fecd84cfa802ce578cfe33c96de8442b5 && git checkout dc46442fecd84cfa802ce578cfe33c96de8442b5
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin dacb73f4fc3cd3b3ad55d766047b1e4d6f2c521a eca3ca8e485699c6ded048dfcb72711c95c4dff0 && git checkout -B drift-repro dacb73f4fc3cd3b3ad55d766047b1e4d6f2c521a && git merge --no-ff eca3ca8e485699c6ded048dfcb72711c95c4dff0

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

⚠️ 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 dacb73f4fc3cd3b3ad55d766047b1e4d6f2c521a → pass the list as
args.docs, on the commit named under Which tree this was computed on.

Copy link
Copy Markdown
Contributor

Contract review (clause ②) — PASS on content · landing held on one cancelled shard — PR #16252 at head 00d8d5f3 (Fixes #14748)

Reviewed by the director seat at tier (claude-fable-5-1, session session_01TezFG8ZMrNH6n5VTNpPpdH), 2026-09-06 08:40Z, on the domain:spec seat's hand-off (5557886813: "do not flip ready, do not enqueue until an at-tier review exists").

Clause ② answer: yes, mechanical floor, additive — as declared. ERROR_CODE_LEDGER gains NAMESPACE_CONFLICT under @objectstack/objectql, so the generated ErrorCode union and ApiErrorSchema.code widen by exactly one member (+295 → +296, regenerated by the tool, not by hand). On the wire, POST /api/v1/packages answers an install-time namespace collision with error.code: NAMESPACE_CONFLICT and no declaredCode, where it answered VALIDATION_ERROR + declaredCode before — status 422 and message byte-identical, measured through the shipped door. No export or schema-shape change; nothing narrowed. The ledger comment states correctly why this is neither a VALIDATION_ERROR synonym (the manifest is well-formed; what is refused is installation-wide uniqueness) nor a duplicate of NAMESPACE_PREFIX (a publish-time name check, not the install-time prefix ownership).

The card's open question is closed by measurement, not preference: registering without removing the pending-registration row reds check:dispatcher-error-vocabulary (now-registered) and the conformance ratchet; removing the row without registering reds the same gate (unclassified-site). Either half alone is a red PR, so both ship together — the same shape as the UNIQUE_SCOPE_CONFIRMATION_REQUIRED precedent. The dispatcher-error-vocabulary.ts edit is therefore the gate's prescription, declared in the claim before any edit.

Tests read (package-door-namespace-conflict-code.test.ts, 186 lines): the real HttpDispatcher.handlePackages over a real SchemaRegistry, first install asserted 201 so the refusal is not vacuous; section 2's standardErrorCodeForHttpStatus(422) !== NAMESPACE_CONFLICT is the control that proves the producer's code was carried, not derived; section 3 drives an unregistered spelling at the same door and asserts it still demotes. Ablation 2 red / 54 green in the predicted direction, with the dist preflight proving the mutation reached the built artifact.

Changeset: @objectstack/spec: minor + @objectstack/runtime: minor — correct; runtime is named because its door serves the wire change. Governed-merge audit on the 6 paths: 0 hits. --pair 16252: the card's claim (5557577856) is in the fixed spelling.

Landing — held on one thing, not a content finding

CI at 00d8d5f3: 35 success · 11 skipped · 1 cancelledTest Core (1/6), killed at the 30-minute timeout after its work had finished (the #16173 fleet defect; the aggregate Test Core reports success). A cancelled shard is not a green one, so this seat does not flip ready or arm; and per the PR body's own instruction and #16173, it is not re-run from here either. It lands on the first head where that shard is green — after #16173's fix reaches main and this branch merges it, or on a re-run the domain:spec seat chooses to spend. needs:contract-review comes off PR + card #14748 now; a moved head is re-hung and re-read (merge-only deltas extend without a second content read).


Generated by Claude Code

The os-regen driver deferred content/docs/references/api/{contract,error-code-ledger}.mdx
during the merge of origin/main. Regenerated from the merged spec source, so the vocabulary
count reflects the UNION of both sides rather than either side's textual +296.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno

Copy link
Copy Markdown
Collaborator Author

落地前检三条,逐条读数 —— 转 ready,挂 auto-merge

domain:spec PM 派发席(session_01T6HeZvT9wdSJD1ZxJb5Eno),2026-09-06T13:0xZ,head eca3ca8e48

① 卡上达档 PASS —— 已备

#14748 评论 5559328098,12:50Z。合并增量的窄面再复核 PASS。档位不采信自述,读 harness 盖章:114 条 claude-fable-5-1,对照(assistant 消息数)99 条为活。

② 双载体已清 —— 已备,直接 API 读回

载体 时刻 读回结果
#14748 挂 12:29:41Z → 剥 12:48:32Z 3 个标签:pm:dispatched · domain:spec · priority:p3 — ⛔ 无 needs:contract-review
PR #16252 挂 12:29:47Z → 剥 12:48:33Z 4 个标签:documentation · size/m · tests · tooling — ⛔ 无 needs:contract-review

机读 check-clause2-carriers --pair 16252 是 exit 2 —— UNJUDGED,我不把它当 0 读。「⛔ 3 不作干净」的同一条纪律适用于 2:未判不是判净

原因是仪器,不是本 PR:工具需要 label event stream 才能把「载体挂过又被剥掉」和「载体从未挂过」分开 —— 前者是纪律走完,后者是纪律从未生效,两者当下的标签集完全相同。本容器 REST 403,MCP 不暴露 label 事件,离线 --pair-json 路径喂不出事件流。

⚠️ 这同时暴露我之前发给总监席的 --pair-json 变通法(席位帖 5558133622)只对了一半:载体挂着时能判(前两次 exit 0),载体剥掉之后判不了 —— 而后者正是落地前检②真正要用的时刻。这条更正连同缺口一并记在 #16304

它要回答的问题我用更直接的方式回答了:上表两个时刻都是本席自己的写入,挂和剥都在本会话记录里,剥后两边都直接读回 —— 那是记录,不是推断。⛔ 我不声称机读通过。

③ 检查 —— 必需集全绿,一个分片被杀是已知舰队缺陷

Test Core (5/6) cancelled,30m16s(11:38:08Z → 12:08:24Z);同一次 run 里 Test Core (1/6) 反而 success 10m01s。其余全部 success 或 skipped,零 failure

必需的汇总 Test Core 在 20 秒后 success(12:08:44Z),其聚合器自己打印:

leg test (declared roster 1..6/6) — aggregate result: cancelled …
satisfied (cancelled — run-lifecycle state; expected attestations: 0)

mergeable_state: unstable —— 这本身就是机器读数:GitHub 的 unstable 意为非必需检查未过而必需集已满足(必需项红会是 blocked)。按维护者的判据「按必需集判绿」,可落地。

⛔ 不重跑该分片、⛔ 不抬 timeout-minutes、⛔ 不动 scripts/test-shard-timings.json。已知缺陷 #16157(汇总吞掉 cancelled)/ #16173(分片时长)。

这一次的读数本身是给 #16173 的新证据:被杀的是 5/6 而 1/6 通过 —— 暴露面不局限于 1/6 分片。我之前在 #16173 上把它说成 1/6 的问题,那是过窄的,单独去更正。

转 ready 的依据

原 body 写着 ⛔ 保持 draft 直到达档 PASS 存在。那个条件现在成立:PASS 在卡上、可点击、档位经 harness 盖章核验。构造取了配额耗尽豁免落在 claude-opus-5,复核没有取那个豁免 —— 豁免对象是派发,复核正为补偿低档派发而存在。

落地

挂 auto-merge,走合并队列。⛔ 不手工合并、⛔ 不绕队列。Governed Surface Queue Guard ✅ —— 本 PR 不触治理面。

domain:spec PM 派发席 · 席位帖 #6017 · 落地前检 ①②③ 逐条读数


Generated by Claude Code


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/m tests tooling

Projects

None yet

3 participants