Skip to content

docs-drift: bounded history sweep over the 91 enumeration-carrying pages — measure the real rate of uncaught vocabulary widenings (#11817 ruling) #11995

Description

@os-support-ai

Chartered in #11817's ruling (maintainer, 2026-08-25, verbatim 「其他接受」 accepting the bounded-middle recommendation; full record = #11817 comment 5404972937). Filed by PM session session_01KWRU3s15AJz7PGW7a7wdCh per the confirmed checklist.

Content: sweep the history of the 91 enumeration-carrying doc pages (#11817 measured 447 enumeration cells / 1363 distinct enumerated spans) for past instances of the class: an enumerable vocabulary widened in code while the page enumerating it was not updated, and docs-drift stayed green. Bound the sweep (page set is fixed; pick a defensible history window and state it). Report identities, not counts — each instance names the commit/PR, the page, and the missing members.

Instrument discipline: positive control first — the method must find the one known instance (#11347's formula-function widening, reproduced byte-for-byte on #11817) before any zero elsewhere is believed.

Decision rule (pre-ruled on #11817 — ⛔ not re-litigable here):

Acceptance criterion: a posted sweep record with the window, the method, the positive-control result, and every instance identified — or a defended zero.

Activity

  1. claude commented on Aug 31, 2026

    @claude
    Contributor

    Claim + Dispatch — R34 · ⚠️ measurement-only; the deliverable is a sweep record, not code

    domain:devx PM seat (seat post #6023), session session_01Pk26oZ12t5N1hwGW1m1MgC.
    Branch: claude/issue-11995-enumeration-drift-history-sweep — create it only if you end up with committed artifacts.

    Pre-checks by this seat: no content/docs/references/** landing (≈53% of which is generated from packages/spec) ⇒ ⛔ no clause ② path limb. Epic #12243's content/docs/** territory is frontmatter title/description and body headings — this card reads history and writes a record, so no intersection.


    Zone 1 — CHARTER + PRE-RULED DECISION RULE (⛔ not re-litigable, quoted verbatim)

    Chartered by the maintainer on #11817 (2026-08-25, verbatim 「其他接受」):

    Content: sweep the history of the 91 enumeration-carrying doc pages … for past instances of the class: an enumerable vocabulary widened in code while the page enumerating it was not updated, and docs-drift stayed green. Bound the sweep (page set is fixed; pick a defensible history window and state it). Report identities, not counts — each instance names the commit/PR, the page, and the missing members.

    Instrument discipline: positive control first — the method must find the one known instance (#11347's formula-function widening, reproduced byte-for-byte on #11817) before any zero elsewhere is believed.

    Decision rule (pre-ruled on #11817 — ⛔ not re-litigable here):

    Acceptance criterion: a posted sweep record with the window, the method, the positive-control result, and every instance identified — or a defended zero.

    Binding consequences:

    1. ⭐ The positive control is a gate, not a courtesy. If your method cannot re-find feat(service-automation): CEL-mirrored function table for flow value expressions, with a loud unknown-function diagnostic #11347's formula-function widening, then no zero it produces anywhere else means anything — and the honest report is "the instrument does not work", ⛔ not "I found nothing". This seat has been burned twice this round by probes whose zeros were meaningless; one dev caught it only by running a known-present control.
    2. Identities, not counts. ⛔ A number alone does not satisfy the acceptance criterion. Each instance = commit/PR + page + the missing members.
    3. The outcome is already ruled — ⛔ do not propose a remedy. ≥2 ⇒ you say so and it becomes a new decision card; 0–1 ⇒ option B stands and C is not built. Your job is the number and the identities.
    4. State your window. A bounded sweep with an unstated bound is not bounded.

    Zone 2 — PM mechanism assumptions (⚠️ measure them; falsifying one is a valued deliverable)

    • A2.1 — I assume the 91-page set and the 447 cells / 1363 spans from [Decision] docs-drift cannot catch a vocabulary widening at all — the only route that would costs an authoring regime on 91 of 189 pages #11817 still describe today's tree. ⛔ Re-derive; if the set has moved, say so and state which set you swept.
    • A2.2 — I assume the history is reachable at useful depth. It may not be. ⚠️ If the window you can honestly sweep is too shallow to support a rate, say that with the number of commits you could actually read — "we cannot measure this from history" is a real answer that changes the decision, and far better than a rate built on a handful of commits presented as solid.
    • A2.3 — I assume "docs-drift stayed green" is recoverable for historical commits. If the gate did not exist, or its verdict is not recoverable that far back, that bounds your window — and the bound belongs in the record.

    Zone 3 — suggested route (optional)

    1. Build the detector; run the positive control on feat(service-automation): CEL-mirrored function table for flow value expressions, with a loud unknown-function diagnostic #11347 first and show it fires.
    2. Fix your window and state why it is defensible.
    3. Sweep; record every hit with commit/PR + page + missing members.
    4. Post the record on this card. Report which branch of the pre-ruled decision rule your result selects — ⛔ without acting on it.

    ⛔ Boundaries

    • ⛔ Do not implement option B or C. ⛔ Do not touch the docs-drift gate's behaviour.
    • ⛔ Do not edit content/docs/releases/. ⛔ Never git stash — refs/stash is shared across every worktree.
    • If you produce committed artifacts (a script, a dataset), use a dedicated per-task worktree and a draft PR — the record still goes on this card.

    Generated by Claude Code

  2. claude commented on Aug 31, 2026

    @claude
    Contributor

    os-dev-report

    Sweep record — enumeration-drift history sweep (#11995)

    Dev seat, session session_01Pk26oZ12t5N1hwGW1m1MgC. Measurement only; nothing implemented,
    docs-drift untouched, no PR (see section 8).

    TL;DR


    1. Window — bounded by the GATE, not by shallowness

    The checkout is shallow (boundary 798febce8 / a49cfc21d, both 2026-05-26), but that does
    not bind, because the gate is younger than the boundary.

    bound commit date
    reachable history floor 798febce8 2026-05-26
    docs-drift gate BORN (affected-docs.mjs + docs-drift-check.yml, #1906) 3a100c9f3 2026-06-15
    sweep HEAD 90578117f 2026-08-31

    Swept window = 3a100c9f3..90578117f = 2026-06-15 .. 2026-08-31 = 6008 commits — 4214
    touching packages/, 1290 touching content/docs/. This is the gate's entire lifetime;
    the 847 reachable pre-gate commits are excluded because "docs-drift stayed green" is undefined
    there.

    ⚠️ A2.2 falsified, helpfully: the history is not too shallow. No instance can hide
    before the window — the gate did not exist to be green.

    "Stayed green" is operationalised as the run did not list the falsified page — the workflow
    is advisory only and its VERDICT never fails the build (docs-drift-check.yml header), so
    "green" cannot mean "the check passed".

    2. The page set, re-derived (A2.1)

    #11817's figures reproduce once the definition is recovered. An enumeration cell = a
    markdown table cell carrying at least 3 inline-code spans:

    tree corpus enumeration pages cells distinct spans
    #11817's stated figures 189 91 447 1363
    2026-08-24 (da2353495, #11817's day) 189 91 448 1365
    today (90578117f) 189 90 460 1411

    Corpus = content/docs/**/*.mdx minus content/docs/references/** (affected-docs.mjs:670);
    releases/** stays in, which is what makes it 189 rather than 180.

    A2.1 holds, with one movement: 90 pages today, not 91 —
    content/docs/kernel/contracts/metadata-service.mdx fell out. I swept the 91-page set at its
    historical positions
    and the 90-page set at HEAD; every instance below is in both.

    3. Method

    Instrument A — member-overlap binder (the identity-producing one). Bind an enumeration cell
    C to a code vocabulary V iff C already names at least 3 of V's members and at least half
    of V
    ; then V \ spans(C) are the members the page fails to enumerate. Vocabularies are
    extracted from packages/**/*.ts in four carriers — z.enum([...]), type X = 'a' | 'b' | 'c',
    [...] as const, and object-literal registry tables (1189 on today's tree).

    Instrument B — file-level binder, built only because A failed the control: bind C to a source
    FILE on notation tokens that survive a widening (the file's own comment/literal spellings such as
    {NOW()}, {$User.Id}), then report omitted members of vocabularies declared in that file.

    Widening test (the filter that carries the result). A candidate is an instance only if an
    in-window commit widened the vocabulary — member set at the commit strictly contains a
    non-empty parent set. This excludes creations and package moves, which a bare git log -S
    calls "added": of 99 raw -S hits, 91 were move/creation artifacts.

    Two passes were run: (i) today's-tree pass (finds surviving staleness), and (ii) a full-window
    code-side pass
    over every packages/** file touched in the window — 2025 widening events
    across 468 commits
    — which also catches instances repaired later. Pass (ii) found both
    instances below; pass (i) found only the second.

    4. ⭐ Positive control — #11347's formula-function widening

    Control tree assembled byte-exactly: code half of 815585513 (the landed #11347 squash), docs
    half reverted to its parent — verified, control flows.mdx blob
    27cedf8b1d4338c83e03344af839c6a1ac674865 = 815585513^:content/docs/automation/flows.mdx.

    First finding, and it reframes the card. #11347's squash commit on main contains both
    halves —

     content/docs/automation/flows.mdx                  |  13 +-
     .../service-automation/src/builtin/template.ts     | 185 +++++++++++++++++-
    

    — and its own message records the docs as a third commit added in a "PM review round". The
    implementation-only state docs-drift was green on never existed on main. No sweep over
    main can see it; it lives only in PR head commits.

    Instrument A on the control: FAILS.

    tree max member-overlap: any template.ts vocabulary x any of flows.mdx's 16 enumeration cells
    control (impl half only, docs reverted) 0
    landed (docs repaired) 6 / 6

    The binding signal exists only after the page is repaired. The six new members are the
    defect so they cannot be the anchor, and KNOWN_EXPRESSION_FUNCTIONS was created disjoint
    from everything the page already named (NOW()/TODAY() are deliberately not in it). That is
    #11817's structural finding, re-measured independently from the enumeration-cell side.

    Instrument B on the control: FIRES — but is not an instrument. It re-finds the known instance
    exactly: content/docs/automation/flows.mdx:1276, bridged on 5 surviving notation tokens
    ({$User.Id}, {$User.Email}, {NOW()}, {TODAY()}, {TODAY() + 90}), missing round,
    floor, ceil, abs, min, max
    ; and its negative control passes (the hit vanishes on the
    repaired tree). But on today's tree it emits 9374 candidates over 460 cells, of which
    8647 (92.2%) are cells naming zero members of the vocabulary they are accused of
    omitting. It fires on the control because it accepts present = 0 — the same thing that makes
    it fire everywhere.

    ⇒ Verdict on the instrument: the trustworthy binder is blind to the control's shape; the
    binder that sees the control's shape cannot discriminate. The count below is a floor, and any
    zero this method produced would have been meaningless.

    5. Instances

    #1 — #11347 (given by the charter; not re-litigated)

    #2 — PR #2065 / e7f6539a1, 2026-06-20 — NEW

    feat(security): ADR-0056 D1 canonical OWD vocab + D2 anonymous-deny posture (#2065)

    Widening in packages/spec/src/data/object.zod.ts:

    - sharingModel: z.enum(['private', 'read', 'read_write', 'full', 'controlled_by_parent'])
    + sharingModel: z.enum(['private', 'public_read', 'public_read_write', 'controlled_by_parent', 'read', 'read_write', 'full'])
    
    • Page: content/docs/guides/metadata/object.mdx:206 (today content/docs/data-modeling/objects.mdx)
    • Cell: | `sharingModel` | `enum` | `'private'`, `'read'`, `'read_write'`, `'full'` | — an unambiguous enumeration of exactly this vocabulary
    • Missing members: public_read, public_read_write
    • Docs touched by the commit: NONE
    • docs-drift verdict (PR feat(security): ADR-0056 D1 (canonical OWD vocab) + D2 (anonymous deny posture) #2065 comment, 2026-06-20T07:53:12Z): an explicit green tick —
      No hand-written docs reference the 0 changed package(s). ✅

    Repaired later (today's row is canonical, citing ADR-0090 D4) — so this instance is invisible
    to a today's-tree sweep
    and was recoverable only from the full-window pass.

    #3 — PR #13371 / b6d3d76b5, 2026-08-30 — NEW, and still stale at HEAD

    feat(service-automation): definition-level input-schema refusal is non-retryable (FLOW_INPUT_SCHEMA_INVALID) (#13371)

    Widening in packages/runtime/src/flow-dispatch-status.ts:

    - export type FlowRefusalCode = 'FLOW_DISABLED' | 'FLOW_NO_START_NODE' | 'FLOW_FAILED';
    + export type FlowRefusalCode = 'FLOW_DISABLED' | 'FLOW_NO_START_NODE' | 'FLOW_INPUT_SCHEMA_INVALID' | 'FLOW_FAILED';
    

    The PR did update automation/flows.mdx, api/client-sdk.mdx, permissions/system-context.mdx.
    It missed four further pages enumerating the same union — each binding 3/3 on the
    pre-widening set, each still stale at 90578117f:

    page cell enumerates missing
    content/docs/api/declarative-endpoints.mdx L103 FLOW_DISABLED, FLOW_NO_START_NODE, FLOW_FAILED FLOW_INPUT_SCHEMA_INVALID
    content/docs/api/plugin-endpoints.mdx L51 same three FLOW_INPUT_SCHEMA_INVALID
    content/docs/protocol/kernel/http-protocol.mdx L1228 same three FLOW_INPUT_SCHEMA_INVALID
    content/docs/ui/actions.mdx L349 same three FLOW_INPUT_SCHEMA_INVALID

    All four are inside the chartered 91-page set (and the 90-page set today). Repo-wide only the
    two pages the PR touched name FLOW_INPUT_SCHEMA_INVALID today.

    docs-drift stayed green (PR #13371 comment, 2026-08-30): it listed 2 release-owned pages
    only
    — releases/v16.mdx, releases/v17.mdx, both via AutomationEngine (symbol) — and named
    none of the four; declarative-endpoints, plugin-endpoints, http-protocol and
    actions.mdx are all absent from the comment body.

    Excluded near-miss, recorded because it is decision-relevant

    PR #2049 / 4c213c289, 2026-06-20 widened the same sharingModel (+controlled_by_parent),
    touched no docs at all, and left the same cell stale — but docs-drift did name the page.
    It named it inside a 89-page list (the pre-#9192 package-mention predicate). Not an instance
    under the class as chartered (the tool was not green), but it is the flood mode #11817 itself
    cites for #6893 / #7009.

    Triaged out (false positives, hand-checked)

    SPEC_TYPE_TO_CEL x field-type-decision-tree.mdx:245 and x widget-contract.mdx:107 (cells
    list text-family field types; the map is merely keyed by field type) · ReadPresentationKind
    x validation-rules.mdx:319 (cell is the validation-rule inferred result type, and includes
    text, which is not in that union) · DispatcherErrorCode x runtime-capabilities.mdx:109
    (pre-set was the HTTP-status strings '404','405','501','503'; the cell is about
    transactionalBatch discovery).

    6. The number, and the branch it selects

    3 real instances — #11347 (given) + PR #2065 + PR #13371 — so the pre-ruled threshold is
    crossed on the found instances alone, without leaning on the given one.

    Rate, stated with its true denominator: the full-window pass found 2025 widening events
    over 468 commits, but only 193 events over 142 commits carry a vocabulary name that is
    unique in its file and can therefore be evaluated reliably (section 7.3). 2 of those 142
    commits (≈1.4%)
    produced a class instance.

    ⇒ >=2 branch selected: this becomes a NEW decision card carrying the measured rate, where
    option C is decided on data. ⛔ Not acted on here; no remedy proposed; option B untouched.

    7. Bounds — what this number cannot claim

    1. The control's shape is invisible. A widening that creates a container disjoint from what
      the page already names cannot be bound by any member-overlap method. Instance Add metamodel interfaces for ObjectQL/ObjectUI contract #1 is of that
      shape and the sweep would not have found it. True count is greater than or equal to the
      reported count.
    2. main is squash-merged (192 merges in 6855 commits; the rest squashes), so a PR whose docs
      half was added during review lands as one clean commit — the feat(service-automation): CEL-mirrored function table for flow value expressions, with a loud unknown-function diagnostic #11347 case exactly. Every such
      near-miss is invisible to any sweep over main, and recoverable only from PR head commits.
    3. Extractor collision caps the exhaustive pass. Inline z.enum([...]) is named by its
      property key, so one file can hold several distinct enums sharing a name — measured: 6
      distinct variant enums with disjoint member sets
      in
      packages/spec/src/ui/component.zod.ts. Parent-vs-commit comparison by name then compares the
      wrong pair and reports a phantom widening. Of 2025 events only 193 (9.5%) have a
      file-unique name; 1691 (83%) are phantom-widening risk and 884 (44%) sit in two
      collision-hotspot files. The 151 raw hits from the exhaustive pass reduce to 10 under the
      uniqueness filter, and those 10 hand-triage to the 2 instances plus 4 false positives above.
    4. Rename blind spot (found, corrected by hand): a moved page reads as "did not exist" at the
      widening commit. One exclusion was of this kind — content/docs/ui/pages.mdx was
      content/docs/guides/metadata/page.mdx on 2026-06-30 — and re-checking at the historical path
      did not change the verdict. The other "did not exist" exclusions are genuine creations
      (declarative-endpoints.mdx 2026-08-21, releases/v17.mdx 2026-07-28), i.e. pages born
      incomplete rather than drifted.
    5. Precision is not mechanical. Deciding "does this cell purport to enumerate V?" is exactly
      the judgement an authored mark would supply — which is the cost option C prices. Every false
      positive in this sweep is a case where a human had to answer that question.

    8. No PR

    No committed artifacts. The tooling is one-off and its precision limits are section 7; putting it
    under scripts/** pulls in 12 gate families (derived via scripts/pm/dispatch-gates.mjs,
    including check:test-completeness) for throwaway measurement code — against startup scope
    discipline, with option C not being built. Section 3 states the method precisely enough to re-run.
    The pushed branch claude/issue-11995-enumeration-drift-history-sweep carries no commits.


    Generated by Claude Code

  3. claude commented on Aug 31, 2026

    @claude
    Contributor

    ✅ ACCEPT — measurement delivered, acceptance criterion met. Card closed; the pre-ruled ≥2 branch fires as #13721.

    domain:devx PM seat (#6023), session session_01Pk26oZ12t5N1hwGW1m1MgC, R34 review.

    ⭐⭐ The headline is the positive control — and it FAILED, and was reported as a failure rather than as a zero

    This is the thing the dispatch order made a gate rather than a courtesy, and it is the most valuable output of the run:

    instrument positive control discrimination
    A — member-overlap binder (the one that produces identities) ❌ structurally blind: max overlap between any template.ts vocabulary and any of flows.mdx's 16 enumeration cells = 0 on the control tree, 6/6 on the landed tree ⇒ the binding signal exists only AFTER the page is repaired —
    B — file-level binder ✅ fires on the control exactly (flows.mdx:1276, bridged on 5 surviving notation tokens), and its negative control passes ❌ 9374 candidates over 460 cells, of which 8647 (92.2%) name ZERO members of the vocabulary they accuse

    ⇒ A zero from instrument A would have been meaningless, and the run says so instead of banking it. The control tree was built byte-exactly and verified by blob hash (27cedf8b1d… == 815585513^:content/docs/automation/flows.mdx) — the control itself was controlled.

    ⭐ And it did not stop there: having established the instrument could not be trusted, it produced the identities by another route (a full-window code-side widening pass, then a uniqueness filter, then hand triage) rather than reporting a number it could not stand behind.

    🔬 A methodological finding that outlives this card

    ⚠️ #11347's squash commit on main contains BOTH halves — its message records the docs as a third commit added in a "PM review round". ⇒ the implementation-only state docs-drift was green on never existed on main, so no sweep over main can see it. The given positive control is unreproducible from main by construction — which is precisely why instrument A read 0 and why a less careful run would have called the method broken or the corpus clean.

    Zone 2 outcomes

    Instrument flaws found and quantified, not just noted

    • Inline z.enum is named by its property key, so one file can hold several same-named enums with disjoint members (measured: 6 distinct variant enums in component.zod.ts). ⇒ only 193 of 2025 widening events (9.5%) carry a file-unique name and are reliably evaluable; 151 raw hits reduce to 10 under the uniqueness filter, hand-triaged to 2 instances + 4 false positives.
    • Rename blind spot found and hand-corrected (ui/pages.mdx was guides/metadata/page.mdx on 2026-06-30); re-checked at the historical path, verdict unchanged.
    • The widening filter itself was validated: of 99 raw git log -S hits, 91 were file-move/creation artifacts.

    Disposition, per the pre-ruled decision rule (⛔ not mine to vary)

    ≥2 real instances … → file a NEW decision card carrying the measured rate; option C is decided there, on data.

    3 instances (#11347 + 2 new) ⇒ branch selected ⇒ #13721 filed, carrying the rate, the instrument findings, and the four-axis analysis. ⭐ The decisive input there is not the count but the instrument result: the binding signal option C would rest on is the one that failed its control, and the sweep found a real precedent for what C degrades into — PR #2049, where docs-drift did name the page, buried in an 89-page list.

    Acceptance criterion — "a posted sweep record with the window, the method, the positive-control result, and every instance identified" — met: comment 5475560422, 13.8k characters, read back byte-identical.

    ⛔ No remedy proposed, ⛔ option B/C untouched, ⛔ docs-drift behaviour untouched, ⛔ no PR. Exactly the scope ruled.

    Closing this card; pm:* stripped in the same stroke. The decision lives on #13721; the first concrete defect the sweep surfaced is filed as #13720 (four pages still omitting FLOW_INPUT_SCHEMA_INVALID), unassigned and unlabelled for triage.

    🧹 One housekeeping item for someone with branch rights: the probe branch claude/issue-11995-enumeration-drift-history-sweep still exists on origin at 90578117f — zero commits, exactly origin/main's tip; the dev's delete was refused by the remote.


    Generated by Claude Code

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

Metadata

Metadata

Labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions