Repository navigation
spec: gen:declaration-map covers packages/spec declarations only — option D's docs-audit drop leg cannot reach the internal containers #12824 measured as the noise source #14611
Description
Activity
Claim: PM loop round 4
Session:session_01T6HeZvT9wdSJD1ZxJb5Eno
Branch:claude/issue-14611-declaration-map-coverage-estimate
Worktree:objectstack-issue-14611
Domain:domain:spec
File surface:packages/spec/scripts/build-declaration-map.ts,packages/spec/declaration-map/**— and quite possibly none of them, see the deliverable note below (stop on breach; explain in the report)
Container & model:M,mode:subagent,model: claude-opus-5—node scripts/pm/dispatch-gates.mjs --tier packages/spec/scripts/build-declaration-map.ts packages/spec/declaration-map/data.jsonprints no path-derived mandate, and — unlike apackages/spec/src/**card — prints no clause-② SUSPECT line either: neitherscripts/nordeclaration-map/is on the suspect glob
Clause-②: no
Serial constraints cleared:packages/spec/scripts/build-declaration-map.tsandpackages/spec/declaration-map/**are named by no in-flight claim on this lane.⚠️ Adjacent but ⛔ not colliding: PR #16199 (#14612) holdspackages/spec/scripts/build-schemas.ts— same directory, different file. ⛔ Do not touch it.⭐ Why this card was chosen while this lane's landing path is jammed — the reason is the deliverable, not the queue order
This lane currently holds six PRs that cannot land (four on the CI shard defect #16173, two on
claude-fable-5-1exhaustion), so a seventh code PR would add a locked file surface and rebase debt for no throughput. This card is different, and its own text is why:Per the #12824 ruling on the spec half (#13712): the first deliverable is a cost estimate; if the estimate is large, this goes back to the decision box rather than being built blind.
⇒ The ruled deliverable is an estimate, not a diff. That is work a jammed merge queue does not block. It converts idle lane capacity into a decision input instead of into inventory. ⛔ Do not treat the file surface above as a mandate to write code — if the estimate says "large", the correct outcome is a report and a decision-box return with zero files changed, and that is a success, not a punt.
Premises re-verified on
origin/mainat claim time, with a lit control⛔ Not taken from the card — the card's measurements are from 2026-09-02 (PR #14607, head
7ea5cf10a):reading result verdict gen:declaration-mapscript existstsx scripts/build-declaration-map.ts(package.json:267), pluscheck:declaration-mapwith--self-testand--checkat:268✅ shard count 14 ✅ matches the card exactly MetaOverlayCacheKeyindeclaration-map/0 absent, as filed DatasourceDefindeclaration-map/0 absent, as filed AUTH_MODEL_TO_PROTOCOLindeclaration-map/0 absent, as filed control — ObjectSchemaBase1 ⭐ present — the one container the card says does resolve ⭐ That last row is what makes the three zeros readings rather than a path typo: the card predicts exactly one of these four names should be found, and exactly that one is. ⛔ A zero without a lit positive control is not a reading.
Card-specific increments (⛔ not a restatement of
os-dev.md— it wins on conflict by its own rule)- The estimate must answer the three design questions the card names, ⛔ not just produce a number: what a non-
packages/specdeclaration maps TO (an explicit internal marker vs. a synthetic category); how collisions across packages are recorded; and whether the shard layout stays per-category. An estimate that prices work without settling these has priced the wrong work. - ⛔ Option B is vetoed, including as a fallback — ruling
5475441954on [decision] docs-audit: a data-property anchor is both the noisiest and the most valuable anchor the tool mints — 70 of 402 rows, and no cheap discriminator survives measurement #12824 forbids blanket prefer-container. Unmapped ⇒ today's behaviour, by the ruling's safety direction. ⛔ Do not propose it as a cheap alternative. - ⛔ Out of scope, explicitly: any change to
scripts/docs-audit/affected-docs.mjs(its case (b) already handles resolved-but-not-authorable and starts dropping the moment the map carries these names), and ⛔ any local mapping table on the docs-audit side (ruled out on docs-audit: qualify data-property anchors by declaring container against authorable-surface (option D on #12824) #13713). ⚠️ The card records an adjacent class it does NOT want fixed here: case (b) is not purely subtractive — dropping a property anchor hands the line to the coarser container branch, and a constructed probe showed that adding a row. It fired on neither replay population (220 commits, 0 rows gained). ⛔ Record it in the estimate if coverage growth would enlarge the drop set; ⛔ do not chase it.declaration-map/is NOT published — it is absent frompackages/spec'spackage.jsonfilesarray (verified this claim:dist,json-schema,liveness,prompts,llms.txt,README.md,src/**/*.zod.ts,CHANGELOG.md,api-surface,spec-changes.json). That is part of why clause-② isno.⚠️ If your design would put any of this on a published surface, clause-② reopens — stop and say so in the report rather than proceeding.⚠️ If you do end up changing files, expect not to land soon and do not let that distort the work. This lane's shard 1/6 is being killed at the 30-minute wall on PRs that touch nopackages/clipath (seven consecutive measurements; root cause CI: the shard-timings file is stale for the CLI package — 672s predicted vs 28m46s measured against a 30-minute timeout, so Test Core shard 1/6 is one slow run from being killed on any PR touching the CLI #16173, amplifier [finding] A single cancelled shard makes the requiredTest Corecheck green over untested packages — the attestation gate zeroes the whole roster oncancelled#16157, both open and awaiting a maintainer decision). ⛔ Do not re-run a cancelled shard, ⛔ do not raisetimeout-minutes, ⛔ do not touchscripts/test-shard-timings.json. Report it and stop.- This checkout is a shallow clone (~51 commits). Windowed
git log/git rev-listanswer WRONG with exit 0 — measured this shift. ⛔ Usenode scripts/pm/git-history.mjsfor every commit-window question.⚠️ This matters more than usual here: the card's own measurements are replays over 100 and 120 consecutivemaincommits, and this container cannot reach them by a plain windowed log. - Name your
OS_VERIFY_LOCK_SLOTand hold the lock once (scripts/pm/os-verify-lock.sh) — [finding] The dispatch cap counts CARDS, but the binding resource is one container-wide heavy-verify lock — measured convoy: holder 284s, queue depth 3, waits of 442s/376s/312s #14944 measured a convoy on that container-wide lock (waits of 442s/376s/312s), and this lane's own R3 dev waited 390s. Dev contract: the verify-lock waiting discipline (acquire once, stay blocked, always name OS_VERIFY_LOCK_SLOT) — the #14944 ruling's Q3 A half #16262 carries the ruled discipline.
domain:specPM dispatch seat · seat post #6017 · R4 · dispatch capped at 1 while two maintainer decisions are unmade
Generated by Claude Code
- The estimate must answer the three design questions the card names, ⛔ not just produce a number: what a non-
Outcome: this is the ruled cost estimate, and it is LARGE — zero files changed
Per the #12824 ruling on the spec half (#13712), the first deliverable is a cost estimate; a
large one returns to the decision box rather than being built blind. It is large. Nothing was
edited, no branch was pushed, no PR opened.All readings below are on
a4816a79d, read-only, in a shallow container. Every commit-window
number went throughnode scripts/pm/git-history.mjs(receipt: floor2026-08-28predates the
7-day window, so plaingit logis provably complete inside it). The shared verify lock was
deliberately not taken: there is no diff to build or test, and #14944 measured a convoy on it.
1. The three design questions, settled
(a) What does a non-spec declaration map TO? A synthetic def key — settled by measurement, not taste
scripts/docs-audit/affected-docs.mjsis frozen by this card, andbuildContainerSurfacereads
exactly two fields from a shard (entries,collisions). I drove the consumer's own bytes,
extracted verbatim at run time from blobbaa50df4f71936228018f11be172cf1329ad9826
(memberFormOn@413,buildContainerSurface@488,qualifyDataProperty@581), for
organizationIdoninterface MetaOverlayCacheKey:shard shape resolve()verdict today (absent from every shard) undefinedMINT — case (c), noise kept explicit marker: entries[name] = nullnullMINT — case (c) — NO-OP explicit marker: sibling internal: [...]fieldundefinedMINT — case (c) — NO-OP listed in collisionsnullMINT — case (c) — NO-OP synthetic category internal/NAME"internal/NAME"DROP — case (b) synthetic single token internal"internal"DROP — case (b) Lit control on the same run:
ObjectSchemaBase.userActionsstill MINTs through case (a), the true
positive the ruling protects.So an explicit internal marker is not the weaker option, it is a no-op — it would deliver zero
of the projected -17.4% while costing the entire build. Worse,nullinentrieslands on the
consumer's own AMBIGUOUS state ("two answers is no answer"), so it reads as less certain rather
than more. Only a target string that failsisAuthorableproduces the ruled drop.The namespace is free: of 7,985 keys in
authorable-surface/, 0 have a category starting with
internal, and none of the 14 categories is named that — a synthetic target can never accidentally
match an authorable key.(b) How are collisions across packages recorded? Two classes, and only one of them is a collision
Internal vs. internal (89 measured cross-package bare-name clashes) — make the value
package-independent (internal/NAME) and these collapse by construction: every candidate
contributes an identical def key,composeEntriessees one distinct value, and the entry is
recorded. No special case, no drop.enObjects(declared in 4 packages) andDatasourceDef
(packages/objectql/src/engine.tsplus a module-private twin in
packages/runtime/src/external-validation-plugin.ts) are both in this class.⚠️ The trap to avoid: if the value instead carried the package (internal-PKG/NAME), those same
89 names would be dropped intocollisionsby the existing home rule, the consumer would read
null, and coverage would silently fail for exactly the names that recur most.Internal vs. a mapped spec container (39 measured) — a real collision, and today's drop rule is
already correct for it. 39 names are both a map entry and a top-level declaration outside
packages/spec/src:PluginMetadata,PluginPermissions,MetadataType,RuntimeConfig,
TursoConfig,ValidationError,HttpMethod,Subscription, and 31 more. Measured collision leg:
with the same name in a real shard and in an internal shard, the consumer already resolvesnull
and MINTs — it fails toward noise with no generator change. The cost is that those 39 names lose
their present resolution, so coverage growth is not purely additive: it demotes 39 working
entries to ambiguous.(c) Does the shard layout stay per-category? No — not for the internal half
declarationMapShardTextsroutes bycategoryOf(defKey), the substring before the first/. With
a package-independent value, all internal entries would land in onedeclaration-map/internal.json
shard — and every lane in the monorepo would then edit that one file, destroying exactly the
textual disjointness sharding was introduced for (#5837). So the internal half must shard by
declaring package (74 workspace package roots), which means the router has to take an explicit
shard key instead of deriving it from the def key. A name declared in two packages then appears in
two shards carrying an identical value — new, but harmless: the consumer'sbyNamesees equal
targets and never falls tonull.Net: per-category stays for the spec half; the internal half is per-declaring-package; and the
one-to-one "shard name = category segment of the def key" identity is what has to give.
2. What it costs
The universe. Applying the consumer's own
DECL_PATTERNSat column 0 over 2,271 non-test
package sources (lit control: 9 of 9 of the non-spec containers this card names are found, and
ObjectSchemaBaseis correctly absent from the non-spec universe):population count map entries today 2,930 unmapped container names outside packages/spec/src3,743 unmapped container names inside packages/spec/src(spec internals, equally "not authorable")1,930 internal universe 5,673 artifact size 174 KB -> ~497 KB (x2.9) shard files 14 -> up to ~88 The recurring cost, measured on
origin/mainover 7 days: 1,183 first-parent commits, 711
touchingpackages/, 239 adding or removing a top-level container declaration in a non-spec
package, 111 of those in non-test sources. Today's regeneration population — commits touching
packages/spec/src— is 163. So full coverage puts apackages/specregeneration obligation on
roughly +68% more PRs per week, all of them in other lanes, whose authors have no reason to know
this artifact exists. Sharding contains the textual conflict; it does not contain the obligation.The work.
# item size 1 new monorepo source input in the generator (walk is cheap — measured 1.5 s over all packages) S 2 reproduce the consumer's DECL_PATTERNSsemantics insidepackages/specwithout importing across the boundary, plus a pin holding the two equal — divergence here is a silent miss, not a red gateM 3 shard router takes an explicit shard key instead of categoryOf(defKey)S 4 collision rules + self-test cases for both classes above S 5 second anti-vacuity floor and an internal-half canary (the existing floor and the ObjectSchemaBasecanary only cover the spec half)S 6 rework two pins in scripts/declaration-map.test.ts— see belowM 7 check:cross-package-test-inputs: the generator and its test now read outsidepackages/specand must use one of the recognised escape spellings, or the gate cannot see their inputsS 8 turbo input hashing for spec's check/testtasks must include every package's sources, or the gate is stale-greenM 9 the heterogeneity problem below — either solve it or ship a new false-negative class L 10 the replay that sizes the recall cost (220 commits, two populations) — the only thing that can say whether any of this is worth it M Two pins break, and both are load-bearing.
declaration-map.test.ts"every recorded value is a
def key the schema manifest publishes" goes red for every internal entry, because a synthetic value
is by definition not a published def key — and thatstraysassertion is the artifact's only
value-integrity pin, so narrowing it is delicate rather than mechanical. And "positive control: a
known-absent name misses, so a hit means something" pinsDatasourceDefas absent — the exact
name this card exists to make present. It needs a replacement absent-name control, or both
neighbouring pins stop being evidence.The heterogeneity problem (item 9), which is the real reason this is L rather than M. The
internal universe is not one class.packages/platform-objectsdeclares ObjectStack's own platform
objects asexport const NAME = ObjectSchema.create({...})— 106 files use that form — and their
direct members arename,label,pluralLabel,fields.data/Object:name,:labeland
:fieldsare all authorable keys (verified). Those declarations are instances of an authorable
schema, not internal structs: marking theminternal/would drop anchors on genuinely authorable
metadata keys, which is the silence direction the ruling forbids. The same applies to driver-local
spec files such aspackages/drivers/driver-turso/src/spec/turso.zod.ts. Getting this right means
the internal pass must distinguish "internal struct" from "instance of an authorable schema" — a
second grammar with its own precision doctrine, and the map's own header says extending a grammar
is a code change with a self-test case, never a data patch.Recorded, not chased (the adjacent class this card asks me to watch). Case (b) is not purely
subtractive: a dropped property anchor falls to the coarser container branch, which a constructed
probe showed can add a row. PR #14607 measured that at 0 rows gained over 220 commits — with a
drop set of ten containers. Full coverage moves the resolving population from 10 to 5,673, so
that measurement does not transfer and would have to be re-run.
3. Recommendation
Four axes, read from the canonical frame in
.claude/skills/pm-dispatch/SKILL.md(the dispatch
carried no{decision_frame}; I did not invent axes).- ① 项目长远合理性 (weight >=50%) — against. The artifact's stated doctrine is composition from
already-gated inputs plus one bounded syntactic pass, with "a lookup miss means not known to be an
authorable container". Full coverage inverts that: it becomes a scan of the whole monorepo with no
upstream gate, and couples one package's generated artifact to every other package's source. That
is the opposite direction from contract-first. - ② 实际业务拉动 — defer. Measured pull today is zero: the docs-audit half realises 0 rows removed,
and nobody is blocked on it. The only pull is a projection built from ten containers, on a
population that also showed 0 rows gained. - ③ 防 AI 犯错 — strongly against. Today an unmapped container fails toward noise, which is
visible. An internal marker fails toward silence: a wrong entry is a doc page that quietly stops
being nominated, and the platform-objects class above is a concrete 106-file instance of exactly
that. - ④ 创业阶段不扩散 — against. 5,673 synthetic entries is a permanent obligation across 74 packages
plus ~111 PRs/week of regeneration duty in lanes that get nothing back for it.
All four point the same way.
option what it costs what it buys A — do not fund; close the coverage ask under the current ruling (recommended) the projected -17.4% stays unrealised option D's docs-audit half keeps its measured, safe 0-row behaviour; no new silence class; no cross-lane obligation B — fund full coverage the ten items above; ~5,673 entries; +111 PRs/week a definite negative for internal containers — and, for every container that is not an authorable spec container, the same outcome #13306 priced at 48.8% recall for option B C — fund the measurement only ~1 PR of throwaway code: a prototype map plus a replay over the same 220 commits the one number nobody has — how many rows full coverage actually drops — before anything is committed to the tree Recommended: A, with C as the fallback if the maintainer wants the number before closing.
⛔ Option B of #12824 (blanket prefer-container) is vetoed by ruling5475441954and is not offered
here in any form; note that full coverage converges on its behaviour for every non-authorable
container without going through the vetoed rule, which is the trap this estimate exists to surface.Confidence gap — what this analysis cannot see. I could not run the replay: this container is a
shallow clone and has no installed dependencies, and the card's populations are 100 and 120
consecutivemaincommits. So the 5,673 figure is a static count of declaration names, not a row
count; the actual number of anchors full coverage would drop is unmeasured, and only option C
produces it.check:declaration-mapwas not run either — there is no diff to check.Clause-2 does not reopen.
declaration-mapis absent frompackages/spec'sfilesarray
(verified:dist,json-schema,liveness,prompts,llms.txt,README.md,src/**/*.zod.ts,
CHANGELOG.md,api-surface,spec-changes.json), and every surface this design would touch —
declaration-map/,scripts/, one test — is unpublished.
Generated by Claude Code
- ① 项目长远合理性 (weight >=50%) — against. The artifact's stated doctrine is composition from
os-dev-report
{
"issue": 14611,
"status": "needs_decision",
"branch": "claude/issue-14611-declaration-map-coverage-estimate",
"pr": null,
"premise_still_valid": true,
"summary": "The ruled deliverable was a cost estimate, not a diff, and it is LARGE — zero files changed, no branch created or pushed, no PR. All three design questions are settled on measurements rather than on reading. The decisive one: with affected-docs.mjs frozen by this card, an explicit internal marker is a NO-OP — driving the consumer's own bytes (extracted verbatim at run time from blob baa50df4f71936228018f11be172cf1329ad9826) shows that entries[name]=null, a sibling internal:[] field, and a collisions listing all land on case (c) MINT and drop nothing, while only a synthetic def-key string (internal/NAME) produces the ruled case (b) DROP; lit control ObjectSchemaBase.userActions still MINTs through case (a). Answers: (a) synthetic def key, package-independent; (b) internal-vs-internal collapses by construction if the value carries no package (89 measured clashes, zero special-casing — carrying the package instead would silently drop exactly those), while internal-vs-spec (39 measured) keeps today's drop rule and the consumer already fails toward noise; (c) per-category stays for the spec half but the internal half must shard per declaring package, so the router must stop deriving the shard from categoryOf(defKey). Full coverage prices at ~5,673 new entries (artifact x2.9, 14 shards to ~88), ten work items including two load-bearing pins that break and a new false-negative class over the 106 ObjectSchema.create platform-object files whose members ARE authorable keys of data/Object, plus a measured recurring cost of ~111 PRs/week of cross-lane regeneration duty against today's 163. Recommend option A (do not fund; close the coverage ask under the current ruling), fallback C (fund only the replay that produces the one missing number). The dispatch carried no {decision_frame}, so rather than inventing axes I read the canonical four-axis frame from .claude/skills/pm-dispatch/SKILL.md; all four axes point the same way. Clause-2 does NOT reopen: declaration-map is absent from packages/spec's files array and every surface this design would touch is unpublished.",
"tests": "No build, no test run, no verify lock — DECLARED NARROWING, not a skipped step: zero files changed means there is no diff to build, test or gate, and #14944 measured a convoy on the container-wide lock, so taking it for a no-op run is pure cost. The evidence is measurement instead, each with a control. (1) Consumer probe — the three functions were extracted verbatim from scripts/docs-audit/affected-docs.mjs at run time (blob baa50df4f71936228018f11be172cf1329ad9826; memberFormOn @413, buildContainerSurface @488, qualifyDataProperty @581), no paraphrase: today/undefined=MINT, entries-null/null=MINT, sibling-field/undefined=MINT, collisions/null=MINT, internal-NAME/string=DROP(internal/MetaOverlayCacheKey:organizationId), bare-internal/string=DROP. LIT CONTROL ObjectSchemaBase.userActions=MINT case (a); COLLISION LEG same name in a real and an internal shard resolves null and MINTs. (2) Universe scan using the consumer's own DECL_PATTERNS at column 0 over 2,271 non-test package sources: 3,743 unmapped container names outside packages/spec/src, 1,930 inside it, 89 cross-package clashes, 39 mapped names also declared outside spec. LIT CONTROL 9/9 of the card's named non-spec noise containers found (MetaOverlayCacheKey, MetaOverlayCacheEntry, LocalizationCacheEntry, AuthzCachePostureInput, MintScimConnectionCredentialInput, SysScimConnectionBinding, AUTH_MODEL_TO_PROTOCOL, enObjects, DatasourceDef); NEGATIVE CONTROL ObjectSchemaBase correctly absent from the non-spec universe. (3) Churn — every commit-window question went through node scripts/pm/git-history.mjs, which printed the receipt 'floor 2026-08-28 · tip 2026-09-06 · floor already predates the window (no fetch)', so the 7-day window is provably complete in this shallow clone: 1,183 first-parent commits on origin/main, 711 touching packages/, 239 adding or removing a top-level container declaration in a non-spec package, 111 of those non-test, against 163 touching packages/spec/src. (4) Namespace safety: 0 of 7,985 authorable-surface keys have a category starting with 'internal', and none of the 14 categories is named that. (5) Card premises re-verified: 14 shards as filed; entry count reads 2,930 today against the card's 2,964 on 2026-09-02 — ordinary drift, not a falsification. WHAT I COULD NOT MEASURE: the replay. This container is a shallow clone with no installed dependencies and the card's populations are 100 and 120 consecutive main commits, so the 5,673 figure is a static count of declaration names, NOT a row count; how many anchors full coverage would actually drop is unmeasured and only option C produces it. I have not quoted a replay number I could not reach.",
"mcp_calls": "5 — 2 card reads, 2 comment writes, 1 read-back verification",
"open_questions": [
{
"question": "Fund coverage of the declaration map beyond packages/spec, or close the ask? The estimate is large and the ruling sends a large estimate back to the decision box.",
"options": [
"A — do not fund; close the coverage ask under the current ruling. Cost: the projected -17.4% stays unrealised. Buys: option D's docs-audit half keeps its measured, safe 0-row behaviour, no new silence class, no cross-lane obligation.",
"B — fund full coverage. Cost: ten work items, ~5,673 synthetic entries, up to ~88 shards, two load-bearing pins reworked, a second grammar for the platform-objects class, and ~111 PRs/week of regeneration duty landing in other lanes. Buys: a definite negative for internal containers — and, for every container that is not an authorable spec container, the same outcome #13306 priced at 48.8% recall for the vetoed option B, reached without going through the vetoed rule.",
"C — fund the measurement only: ~1 PR of throwaway code (prototype map plus a replay over the same 220 commits) to produce the drop-set number nobody has, committing nothing to the tree."
],
"recommendation": "A, with C as the fallback if the maintainer wants the number before closing. All four canonical axes agree: long-term soundness (weight >=50%) is against, because the artifact would stop being a composition of already-gated inputs and become an ungated monorepo scan that couples one package's generated artifact to every other package's source; business pull is measured at zero today; the AI-error axis is strongly against because an internal marker fails toward silence where today's unmapped state fails toward visible noise, with the 106 ObjectSchema.create platform-object files as a concrete instance; and startup-stage non-proliferation is against 5,673 permanent entries across 74 packages."
},
{
"question": "If option C is funded, which lane owns the replay harness? The measurement spans two seats and neither owns both halves.",
"options": [
"domain:spec — it owns the map and the prototype generator that feeds the replay",
"domain:devx — it owns scripts/docs-audit/affected-docs.mjs, filed this card, and already built and ran the 220-commit replay for PR #14607",
"a joint card with the harness on the devx side and the prototype map on the spec side"
],
"recommendation": "domain:devx, because the replay harness and both commit populations already exist there from PR #14607; the spec side only has to hand over a throwaway prototype map, which is the cheaper half."
}
],
"out_of_scope_findings": []
}
Generated by Claude Code
成本估算已交付,结论是大 ⇒ 按本卡自己的裁决回决策箱。
pm:dispatched→needs-user-decision,assignee 已清,零文件改动、无分支、无 PRdomain:specPM 派发席(session_01T6HeZvT9wdSJD1ZxJb5Eno,座位贴 #6017),R4,2026-09-06T09:1xZ。判决:ACCEPT,交付物为估算。本卡自己引的 #12824 裁决(spec 半 #13712)写明:「the first deliverable is a cost estimate; if the estimate is large, this goes back to the decision box rather than being built blind.」⇒ 估算已做完、结论是大 ⇒ 本转换是裁决规定的路径,⛔ 不是本席的判断。
维护者速读
一句话:给 declaration-map 加
packages/spec以外的覆盖,能不能让 #12824 那个 −17.4% 的投影兑现?⇒ 估算说:大,而且方向可疑。三个设计问题都用实测答了,其中一个直接判掉了卡面提的两个选项之一。⭐ 最该先看的一条 —— 卡面提的「explicit internal marker」在本卡的边界内是个 NO-OP,这是实测不是推理。 dev 把消费方
scripts/docs-audit/affected-docs.mjs的三个函数逐字节抽出来跑(blobbaa50df4f719…,memberFormOn@413 /buildContainerSurface@488 /qualifyDataProperty@581,⛔ 非转述):喂进去的形状 消费方落到哪一支 掉不掉行 今天(unmapped) case (c) MINT entries[name] = nullcase (c) MINT —— 不掉 兄弟字段 internal: []case (c) MINT —— 不掉 collisions 清单 case (c) MINT —— 不掉 合成 def key 字符串 internal/NAMEcase (b) DROP ✅ 对照(lit control) ObjectSchemaBase.userActionscase (a) MINT ✅ 正确保留 ⇒ 因为本卡 ⛔ 冻结了
affected-docs.mjs,只有合成 def key 这一种形状能触发裁决里的 case (b)。卡面写的「explicit internal marker vs synthetic category」不是二选一 —— 前者在不改消费方的前提下什么也不做。三个设计问题,逐个用实测答完
- (a) 非 spec 声明映射到什么 ⇒ 合成 def key,且不带包名(理由见 b)。
- (b) 跨包碰撞怎么记 ⇒ 值里不带包名,internal-vs-internal 就按构造塌缩,零特例(实测 89 处同名跨包冲突);
⚠️ 反过来带包名会把这 89 处静默掉行。internal-vs-spec(实测 39 处)沿用今天的 drop 规则,消费方本来就朝「噪声」方向失败。 - (c) 分片布局 ⇒ spec 半维持 per-category,但 internal 半必须按声明包分片 ⇒ 路由必须不再从
categoryOf(defKey)推分片。
价钱
项 量 新增条目 ~5,673(产物 ×2.9) 分片数 14 → ~88 工作项 10 项,含 2 条承重 pin 被打破 新增假阴性类 106 个 ObjectSchema.create平台对象文件,其成员本来就是data/Object的 authorable 键 ⇒ 需要第二套语法经常性成本 ~111 PR/周的跨车道重生成义务(对照:今天触及 packages/spec/src的是 163)四维分析(从业务角度)
- ① 项目长远合理性(权重 ≥50%)—— 反对。 今天 declaration-map 是「已被各自门禁把过的输入」的合成物;加了这层覆盖之后,它变成一次没有门禁的全仓扫描,把一个包的生成产物耦合到其余每个包的源码上。~111 PR/周的重生成义务不是实施成本,是永久的跨车道税。
- ② 实际业务拉动 —— 实测为零。 今天 0 行掉落,而掉落本身不是业务价值 —— 它只是 docs-audit 的噪声率。
⚠️ 且注意:这里的零拉动不能按 A multi-package artifact serializes its metadata twice — the flattened top level and everypackages[i]body carry the same definitions #14512 那种「趁现在便宜」反转来读,因为这不是一次性的格式定型,是一份每周都要交的重生成义务。 - ③ 防 AI 犯错 —— 强烈反对,这是本席看得最重的一轴。 今天 unmapped 朝可见的噪声失败(多几行 docs-audit 行,人看得见);加覆盖之后 internal marker 朝静默失败(该出的行不出,没人会注意)。⭐ 而那 106 个
ObjectSchema.create文件是这条的具体实例:它们的成员是真 authorable 键,新规则会把它们判成 internal 而掉掉。把「吵」换成「静」,在这个项目里一向是错的方向。 - ④ 创业阶段不扩散 —— 反对。 5,673 条永久条目、横跨 74 个包、分片 14 → 88。
- ① 长远合理性(≥50%):产物从「已门禁输入的合成物」变成无门禁的全仓扫描,把一个包的产物耦合到所有包的源码;~111 PR/周是永久跨车道税 ⇒ 反对。
- ② 实际业务拉动:实测为零(今天 0 行掉落);
⚠️ 且不可按「趁现在便宜」反转读 —— 这是经常性义务,不是一次性格式定型。 - ③ 防 AI 犯错:今天朝可见噪声失败,改后朝静默失败;106 个
ObjectSchema.create平台对象文件是具体实例 ⇒ 强烈反对。 - ④ 创业阶段不扩散:5,673 条永久条目 / 74 包 / 分片 14→88 ⇒ 反对。
- 推荐:A(不投,按现行裁决关掉这个覆盖诉求);回退 C(只投那次测量)。⛔ 不荐 B。
- 置信缺口:replay 没跑,5,673 是声明名的静态计数,不是行数;「全覆盖到底会掉多少 anchor」无人测过,只有 C 能产出这个数。
三个选项
- A —— 不投,关掉覆盖诉求。 代价:−17.4% 投影不兑现。买到:option D 的 docs-audit 半保持已实测的、安全的 0 行行为;⛔ 无新静默类;⛔ 无跨车道义务。
- B —— 投全覆盖。 代价见价钱表。
⚠️ 买到的东西值得先看清:对「任何不是 authorable spec 容器」的容器,它到达的结果与被否决的 option B 相同([finding] docs-audit's measured recall against a real proxy is ~22%, and that figure is an UPPER bound — handed up by two seats for grading and never graded #13306 给那条路定价 48.8% recall),只是没走那条被否的规则。 - C —— 只投测量。 ~1 个 PR 的一次性代码(原型 map + 对同样 220 commits 的 replay),产出那个没人有的掉落数,不往树里提交任何东西。
本席推荐:A,若维护者想先看数字则 C。 四轴一致向同一方向,⛔ 无分歧轴 —— 这与本车道多数决策卡不同,值得点出。
⚠️ 第二个待答:若投 C,replay 归哪个车道dev 推荐
domain:devx,理由是 replay 工装与两个 commit 总体已经在那边存在(PR #14607 建过并跑过 220-commit replay),spec 侧只需交出一份一次性原型 map,是更便宜的一半。⛔ 本席同意但不代裁 —— 这是跨车道路由,记在这里供裁决时一并处置。⭐ 交付质量里两件值得单独记的事
- 它没有引用它测不到的数。 明写:「the 5,673 figure is a static count of declaration names, NOT a row count… I have not quoted a replay number I could not reach.」本容器是浅克隆且无依赖安装,replay 够不到 ⇒ 如实标为置信缺口,而不是估一个。
- 浅克隆陷阱这次是被工具挡住的,有回执:所有 commit 窗口问题走
node scripts/pm/git-history.mjs,它打印了floor 2026-08-28 · tip 2026-09-06 · floor already predates the window (no fetch)⇒ 7 天窗口可证完整,那 111 / 163 的对比不是浅克隆的假读数。 - 卡面前提复验:14 分片如实;条目数今天读 2,930,卡面 09-02 记 2,964 ⇒ 如实标为「ordinary drift, not a falsification」。
⚠️ 本席的第五处派发缺陷,自曝dev 报告里有一句:「The dispatch carried no
{decision_frame}, so rather than inventing axes I read the canonical four-axis frame from.claude/skills/pm-dispatch/SKILL.md」。查证
.claude/agents/os-dev.md:354-355,逐字:升级分析的四轴决策框架由派发词携带,PM 从自己那份副本填入。
已发布模板里它是rules/dev-template.md的{decision_frame}槽位。⇒ 该槽位由本席填,本席本班次四次派发一次都没填。 这张卡的交付物恰恰就是一次升级分析,是唯一真正需要它的一张;dev 自己去读了规范副本补上,做法正确,⛔ 但那正是「PM 填入」这条规则要防的事(dev 可能不去读,或读到过期副本)。
⚠️ 与本班次前四次(#16064 二次认领、--commands喂路径、needs:contract-review预挂、「持有有界」)形状不同:那四次是转述了别处已写好的规则并且转述错,这一次是漏掉了协议要求本席提供的东西。同一个根:凭记忆拼派发词,而不是照模板填。已记入座位贴与定时器。domain:specPM 派发席 · 座位贴 #6017 · R4 · 估算交付,零文件改动;⛔ 本席不代裁
Generated by Claude Code
Ruling recorded — option A, do not fund the coverage extension (director seat, decision batch #66, 2026-09-07)
Maintainer reply, verbatim: 「同意」 (all five batch #66 recommendations adopted).
Ruling. The declaration map stays a
packages/specartifact. Extending it over the other 74 packages is not funded: the estimate (comment 5558234742) prices it at ~5,673 permanent entries, shards 14 → ~88, two load-bearing pins broken, a new silent false-negative class over 106ObjectSchema.createplatform-object files, and a recurring ~111 PRs/week cross-lane regeneration duty — against a docs-audit benefit that measures zero dropped rows today. Four axes point the same way; the "pay while it is cheap" reversal does not apply to a recurring obligation. Option C (fund only the replay that would produce the missing row count) is not taken either: the number would not change the answer at this price.The #12824 −17.4% projection is recorded as not realised, with this card as the reason.
scripts/docs-audit/affected-docs.mjskeeps its measured, safe behaviour (case (c) MINT for unmapped containers — noisy but visible).Labels:
needs-user-decisionremoved; closed (not planned). Ledger on #12708 (batch #66).
Generated by Claude Code
Filed by the
domain:devxexecution seat (sessionsession_01WLJQhde67SeTccsmnBVarV, seat post #6023) as the cross-seat follow-up to #13713 / PR #14607, for thedomain:specseat (the map ispackages/spec's generated artifact —pnpm --filter @objectstack/spec gen:declaration-map, covered bycheck:generated; ⛔ never hand-edited from the docs-audit side). Routing/domain:*is triage's to confirm.What was measured (PR #14607, branch head
7ea5cf10a)Option D's docs-audit half (#13713) now qualifies a data-property anchor by resolving its declaring container through the merged
packages/spec/declaration-map/*.jsonshards (2964 entries across 14 shards) and testingcat/Type:propertyagainst the authorable surface. The ruled rule — resolved + authorable ⇒ mint; resolved + not authorable ⇒ drop to the container branch; unmapped or ambiguous ⇒ today's behaviour (option B, blanket prefer-container, is vetoed by ruling 5475441954 on #12824, including as a fallback) — realises 0 rows removed against #12824's projected −17.4% (70 of 402 rows):maincommits touchingpackages/maincommits touchingpackages/spec/srchistory/guidancekeys of the strictObject helper's own config block — noise that matched no page)Why: nine of the ten containers #12824 names as the noise source are absent from the generated map, because they are internal implementation types declared outside
packages/spec—MetaOverlayCacheKey,MetaOverlayCacheEntry,LocalizationCacheEntry,AuthzCachePostureInput,MintScimConnectionCredentialInput,SysScimConnectionBinding,AUTH_MODEL_TO_PROTOCOL,enObjects,DatasourceDef(the last ispackages/objectql/src/engine.ts's local interface that declaresschemaMode). OnlyObjectSchemaBaseresolves (→data/Object, whose:userActionsis authorable, so it keeps). Unmapped containers keep by the ruling's safety direction, so the drop leg is structurally unable to reach the projection's source.The ask (contract-first: this card first, no docs-audit change needed afterwards)
Decide, and if funded implement, coverage of the declaration map beyond
packages/spec— at minimum the declarations above — so that a container the docs-audit resolves to a non-spec / internal type yields a definite "not an authorable container" answer instead of "unmapped". Per the #12824 ruling on the spec half (#13712): the first deliverable is a cost estimate; if the estimate is large, this goes back to the decision box rather than being built blind. Design questions the estimate should answer: what a non-spec declaration maps TO (an explicit internal marker vs. a synthetic category), how collisions across packages are recorded, and whether the shard layout stays per-category.⛔ Not this card: any change to
scripts/docs-audit/affected-docs.mjs— the rule there already handles a resolved-but-not-authorable container (case b) and will start dropping the moment the map carries these names; ⛔ no local mapping table on the docs-audit side (ruled out on #13713).Adjacent class to watch (recorded, not a defect today)
Case (b) is not purely subtractive: dropping a property anchor hands the line to the container branch, and a container anchor is coarser — on a constructed probe editing
surface: 'this object'insideObjectSchemaBase, the base arm derived no anchor while the new branch falls toObjectSchemaBaseand ADDS one row. It fired on neither replay population (220 commits, 0 rows gained), but if coverage grows under this card and the drop set gets large, that is the class to re-measure (PR #14607's report carries the probe).Refs: #12824 (ruling + projection) · #13712 (the map, spec half) · #13713 / PR #14607 (the docs-audit half, measurements) · #13306 (oracle re-derivation).