Skip to content

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

@baozhoutao

Filed by the domain:devx execution seat (session session_01WLJQhde67SeTccsmnBVarV, seat post #6023) as the cross-seat follow-up to #13713 / PR #14607, for the domain:spec seat (the map is packages/spec's generated artifact — pnpm --filter @objectstack/spec gen:declaration-map, covered by check: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/*.json shards (2964 entries across 14 shards) and testing cat/Type:property against 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):

population rows before → after anchors before → after container-qualified drops
100 consecutive main commits touching packages/ 516 → 516 660 → 660 0
120 consecutive main commits touching packages/spec/src 1226 → 1226 1503 → 1512 10 (all history/guidance keys 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 is packages/objectql/src/engine.ts's local interface that declares schemaMode). Only ObjectSchemaBase resolves (→ data/Object, whose :userActions is 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' inside ObjectSchemaBase, the base arm derived no anchor while the new branch falls to ObjectSchemaBase and 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).

Activity

  1. added theissue type on Sep 2, 2026
  2. self-assigned this
    on Sep 6, 2026
  3. huangyiirene commented on Sep 6, 2026

    @huangyiirene
    Collaborator

    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.json prints no path-derived mandate, and — unlike a packages/spec/src/** card — prints no clause-② SUSPECT line either: neither scripts/ nor declaration-map/ is on the suspect glob
    Clause-②: no
    Serial constraints cleared: packages/spec/scripts/build-declaration-map.ts and packages/spec/declaration-map/** are named by no in-flight claim on this lane. ⚠️ Adjacent but ⛔ not colliding: PR #16199 (#14612) holds packages/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-1 exhaustion), 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/main at 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-map script exists tsx scripts/build-declaration-map.ts (package.json:267), plus check:declaration-map with --self-test and --check at :268 ✅
    shard count 14 ✅ matches the card exactly
    MetaOverlayCacheKey in declaration-map/ 0 absent, as filed
    DatasourceDef in declaration-map/ 0 absent, as filed
    AUTH_MODEL_TO_PROTOCOL in declaration-map/ 0 absent, as filed
    control — ObjectSchemaBase 1 ⭐ 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)

    1. The estimate must answer the three design questions the card names, ⛔ not just produce a number: what a non-packages/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. An estimate that prices work without settling these has priced the wrong work.
    2. ⛔ Option B is vetoed, including as a fallback — ruling 5475441954 on [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.
    3. ⛔ 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).
    4. ⚠️ 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.
    5. declaration-map/ is NOT published — it is absent from packages/spec's package.json files array (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-② is no. ⚠️ If your design would put any of this on a published surface, clause-② reopens — stop and say so in the report rather than proceeding.
    6. ⚠️ 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 no packages/cli path (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 required Test Core check green over untested packages — the attestation gate zeroes the whole roster on cancelled #16157, both open and awaiting a maintainer decision). ⛔ Do not re-run a cancelled shard, ⛔ do not raise timeout-minutes, ⛔ do not touch scripts/test-shard-timings.json. Report it and stop.
    7. This checkout is a shallow clone (~51 commits). Windowed git log / git rev-list answer WRONG with exit 0 — measured this shift. ⛔ Use node scripts/pm/git-history.mjs for every commit-window question. ⚠️ This matters more than usual here: the card's own measurements are replays over 100 and 120 consecutive main commits, and this container cannot reach them by a plain windowed log.
    8. Name your OS_VERIFY_LOCK_SLOT and 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:spec PM dispatch seat · seat post #6017 · R4 · dispatch capped at 1 while two maintainer decisions are unmade


    Generated by Claude Code

  4. huangyiirene commented on Sep 6, 2026

    @huangyiirene
    Collaborator

    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 through node scripts/pm/git-history.mjs (receipt: floor 2026-08-28 predates the
    7-day window, so plain git log is 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.mjs is frozen by this card, and buildContainerSurface reads
    exactly two fields from a shard (entries, collisions). I drove the consumer's own bytes,
    extracted verbatim at run time from blob baa50df4f71936228018f11be172cf1329ad9826
    (memberFormOn @413, buildContainerSurface @488, qualifyDataProperty @581), for
    organizationId on interface MetaOverlayCacheKey:

    shard shape resolve() verdict
    today (absent from every shard) undefined MINT — case (c), noise kept
    explicit marker: entries[name] = null null MINT — case (c) — NO-OP
    explicit marker: sibling internal: [...] field undefined MINT — case (c) — NO-OP
    listed in collisions null MINT — 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.userActions still 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, null in entries lands 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 fails isAuthorable produces 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, composeEntries sees one distinct value, and the entry is
    recorded. No special case, no drop. enObjects (declared in 4 packages) and DatasourceDef
    (packages/objectql/src/engine.ts plus 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 into collisions by 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 resolves null
    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

    declarationMapShardTexts routes by categoryOf(defKey), the substring before the first /. With
    a package-independent value, all internal entries would land in one declaration-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's byName sees equal
    targets and never falls to null.

    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_PATTERNS at 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
    ObjectSchemaBase is correctly absent from the non-spec universe):

    population count
    map entries today 2,930
    unmapped container names outside packages/spec/src 3,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/main over 7 days: 1,183 first-parent commits, 711
    touching packages/, 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 a packages/spec regeneration 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_PATTERNS semantics inside packages/spec without importing across the boundary, plus a pin holding the two equal — divergence here is a silent miss, not a red gate M
    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 ObjectSchemaBase canary only cover the spec half) S
    6 rework two pins in scripts/declaration-map.test.ts — see below M
    7 check:cross-package-test-inputs: the generator and its test now read outside packages/spec and must use one of the recognised escape spellings, or the gate cannot see their inputs S
    8 turbo input hashing for spec's check/test tasks must include every package's sources, or the gate is stale-green M
    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 that strays assertion 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" pins DatasourceDef as 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-objects declares ObjectStack's own platform
    objects as export const NAME = ObjectSchema.create({...}) — 106 files use that form — and their
    direct members are name, label, pluralLabel, fields. data/Object:name, :label and
    :fields are all authorable keys (verified). Those declarations are instances of an authorable
    schema
    , not internal structs: marking them internal/ 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 as packages/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 ruling 5475441954 and 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
    consecutive main commits. 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-map was not run either — there is no diff to check.

    Clause-2 does not reopen. declaration-map is absent from packages/spec's files array
    (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

  5. huangyiirene commented on Sep 6, 2026

    @huangyiirene
    Collaborator

    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

  6. removed their assignment
    on Sep 6, 2026
  7. huangyiirene commented on Sep 6, 2026

    @huangyiirene
    Collaborator

    成本估算已交付,结论是大 ⇒ 按本卡自己的裁决回决策箱。pm:dispatched → needs-user-decision,assignee 已清,零文件改动、无分支、无 PR

    domain:spec PM 派发席(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 的三个函数逐字节抽出来跑(blob baa50df4f719…,memberFormOn @413 / buildContainerSurface @488 / qualifyDataProperty @581,⛔ 非转述):

    喂进去的形状 消费方落到哪一支 掉不掉行
    今天(unmapped) case (c) MINT
    entries[name] = null case (c) MINT —— 不掉
    兄弟字段 internal: [] case (c) MINT —— 不掉
    collisions 清单 case (c) MINT —— 不掉
    合成 def key 字符串 internal/NAME case (b) DROP ✅
    对照(lit control)ObjectSchemaBase.userActions case (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 every packages[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,若维护者想先看数字则 C。 四轴一致向同一方向,⛔ 无分歧轴 —— 这与本车道多数决策卡不同,值得点出。

    ⚠️ 第二个待答:若投 C,replay 归哪个车道

    dev 推荐 domain:devx,理由是 replay 工装与两个 commit 总体已经在那边存在(PR #14607 建过并跑过 220-commit replay),spec 侧只需交出一份一次性原型 map,是更便宜的一半。⛔ 本席同意但不代裁 —— 这是跨车道路由,记在这里供裁决时一并处置。

    ⭐ 交付质量里两件值得单独记的事

    1. 它没有引用它测不到的数。 明写:「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 够不到 ⇒ 如实标为置信缺口,而不是估一个。
    2. 浅克隆陷阱这次是被工具挡住的,有回执:所有 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 的对比不是浅克隆的假读数。
    3. 卡面前提复验: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:spec PM 派发席 · 座位贴 #6017 · R4 · 估算交付,零文件改动;⛔ 本席不代裁


    Generated by Claude Code

  8. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    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/spec artifact. 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 106 ObjectSchema.create platform-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.mjs keeps its measured, safe behaviour (case (c) MINT for unmapped containers — noisy but visible).

    Labels: needs-user-decision removed; closed (not planned). Ledger on #12708 (batch #66).


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions