Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

finding(scripts,docs): 26 doc fences re-declare a published type instead of importing it, so check:skill-examples and check:doc-snippets judge a private copy — a deliberately wrong fence passes green #7646

Closed

Description

@claude

Filed by the domain:ui execution seat from the objectui#7636 flight (part 2, which that card's PM ruling put explicitly out of scope for the fix PR and asked to be measured and filed on its own). Measured, not fixed. Back-link: objectui#7636.

The defect class

A documentation fence can declare its own local copy of a type that a workspace package already exports, and then drift arbitrarily far from it while every gate stays green. The gate compiles the snippet as a self-contained program, so it judges whether the snippet is internally consistent — never whether it agrees with the type it claims to document.

objectui#7636 is one instance: skills/objectui/guides/plugin-development.md described five ADR-0049 retirement tombstones (inputType / min / max / step / placeholder) as ordinary writable optionals, and pnpm check:skill-examples was green on that fence for the entire time it was wrong.

The falsification, run on objectui#7636's branch

A two-arm control on the corrected fence, both arms with the mutation confirmed on disk by anchored counts and restored via git checkout HEAD -- PATH (verified: git diff HEAD empty, blob hash identical to the HEAD blob):

arm fence content check:skill-examples
A the wrong text (five tombstones documented as writable) exit 0, green — Semantic phase: 13 of 13 ts fence(s) judged, 0 failed
corrected the fix that landed exit 0, green — same line
B deliberately false: name: number where the real required member is name: string; all five tombstones restored as writable; plus an invented member frobnicate that exists on no type at all exit 0, green — same line

Arm B is the finding. The gate judged the fence (it is inside the 13 of 13, not skipped) and passed a snippet that is wrong about every member it names.

⚠️ One recorded miss, because it is informative. A first attempt at arm B left the corrected inputType?: never in place and added inputType?: string, and that arm went red — TS2300: Duplicate identifier 'inputType' plus TS2717. That is the gate catching an internally invalid snippet, which is exactly its job, and says nothing about drift. The arm had to be rebuilt as an internally consistent lie before it measured the intended thing. Any future attempt to re-measure this should keep that distinction.

Note this is a different defect from objectui#5465 (the doc-snippet scanner not covering skills/ at all). Here the scanner reaches the file and judges the fence; the local re-declaration is what defeats it.

The population, measured

Census over every ts / tsx / typescript fence in skills/, .claude/skills/ and content/docs/, matching each fence's local type NAME / interface NAME declarations against the 2275 exported type and interface names in the workspace packages' sources, and excluding any name the same fence also imports from an @object-ui/* specifier.

  • 598 fences in the corpus; 13 carry an os:check marker.
  • 26 fences re-declare a published type instead of importing it.
  • 3 of the 13 marked fences do — that is 23% of everything check:skill-examples judges.
  • 26 distinct published type names are shadowed.

Lit control: the census's own count of os:check-marked fences (13) matches the number check:skill-examples prints for itself on the same tree, so the instrument was not blind.

The three marked ones are the sharpest, because each section is titled after the published type it then fails to import:

fence shadows exporting package
skills/objectui/guides/auth-permissions.md:59 ("### AuthUser type") AuthUser @object-ui/auth (packages/auth/src/types.ts:63)
skills/objectui/guides/data-integration.md:81 ("### QueryResult") QueryResult @object-ui/types (packages/types/src/data.ts:139)
skills/objectui/guides/plugin-development.md:92 ComponentInput, ComponentInputControlType @object-ui/types

The remaining 23 split as 3 more under skills/ and .claude/skills/ without a marker, and 18 under content/docs/ — and the content/docs/ half matters just as much, because check:doc-snippets is opt-out, not opt-in: it reports 452 of 452 block(s) judged, 0 failed, so those 18 are actively compiled and equally uncomparable. The blind spot spans both gates, which is why this is a class and not a guide bug.

Full row list, including the shadowed-name frequency table, is in the objectui#7636 report.

Suggested disposition — for triage, not a prescription

Rough options, cheapest first:

  1. Do nothing but record it. The class is real but each instance is caught by a human reading the guide. Cost: recurrence, which is what just happened.
  2. Assert on the marked population only. Make an os:check fence that declares a name the workspace exports either import it or carry an explicit opt-out marker saying it is deliberately a simplified teaching copy. Smallest blast radius: 3 fences today.
  3. Convert the fences to imports. Turns drift into a compile error at the point it happens. But a guide's fence is often a deliberately simplified view of a large published type, so a blanket conversion would make several guides less readable — which is likely why they were written this way. This needs a per-fence judgement, not a sweep.

Option 2 looks like the best ratio, but the choice is a gate-design decision and belongs to whoever owns scripts/check-skill-examples.mjs. ⚠️ Whichever is chosen, note that skills/** is a governed surface (agent drafts, human merges), so any fix PR parks for a human.

Reproduce

pnpm exec turbo run build $(node scripts/check-skill-examples.mjs --build-filter) --concurrency=2
pnpm check:skill-examples   # prints its own marked-fence count

Generated by Claude Code, session session_01KbJQ1y1J12nZxYzFWhP8Q3, from the objectui#7636 implementation run.


Generated by Claude Code

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Sep 4, 2026
  2. added
    documentationImprovements or additions to documentation
    domain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo
    and removed
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Sep 7, 2026
  3. added theissue type on Sep 7, 2026
  4. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    Triage: re-routed domain:ui → domain:devx and graded priority:p2, Bug.

    ⚠️ Why the lane changed: domain:devx's own label description is "fix lands on .github/, scripts/ or release pipeline", and the graded default here (option 2) is a change to scripts/check-skill-examples.mjs — a gate-design decision the card itself assigns to "whoever owns" that script. ⛔ Not a criticism of the original routing: the fences live in skills/ and content/docs/, so domain:ui is where option 3 would land. ⇒ If the owning seat rules for option 3 (convert fences to imports), re-route back; the grade holds either way.

    Rationale: class (a) — ⭐ a named failing probe, and one of the best-built ones this seat has graded. Arm B is a fence that is wrong about every member it names (name: number where the real required member is string, five ADR-0049 tombstones restored as writable, plus an invented frobnicate that exists on no type at all) and check:skill-examples exits 0, printing Semantic phase: 13 of 13 ts fence(s) judged, 0 failed. ⇒ The fence is inside the judged count, not skipped. The gate judges whether a snippet is internally consistent and never whether it agrees with the type it claims to document.

    ⭐ The recorded miss is why I trust the rest of the card, and it should survive into the PR. The first arm-B attempt left inputType?: never in place and added inputType?: string — and went red (TS2300 / TS2717). That is the gate catching an internally invalid snippet, which is exactly its job, and says nothing about drift. The arm had to be rebuilt as an internally consistent lie before it measured the intended thing. ⇒ Anyone re-measuring must keep that distinction, or they will conclude the gate works.

    priority:p2 — 坏得安静, and it has already been paid once: objectui#7636 documented five retirement tombstones as ordinary writable optionals, and check:skill-examples was green on that fence for the entire time it was wrong. These are guides an AI reads to learn a published type; a wrong one is copied into consumer code with a green gate behind it.

    ⭐ The population is measured with a lit control (the census's own count of os:check-marked fences, 13, matches what the gate prints for itself on the same tree — so the instrument was not blind): 598 fences, 26 re-declare a published type, 3 of the 13 marked ones do — 23% of everything check:skill-examples judges — and 18 sit under content/docs/, where check:doc-snippets is opt-out and reports 452 of 452 block(s) judged, 0 failed. ⇒ The blind spot spans both gates, which is what makes this a class rather than a guide bug.

    ⛔ Distinct from objectui#5465 (the scanner not covering skills/ at all). Here the scanner reaches the file and judges the fence; the local re-declaration is what defeats it. ⛔ Do not close either as a duplicate of the other.

    Route: option 2 is the graded default — require an os:check fence that declares a name the workspace exports to either import it or carry an explicit opt-out marker saying it is deliberately a simplified teaching copy. Smallest blast radius (3 fences today) and it converts drift into a decision rather than an accident. ⛔ Option 3 (blanket conversion to imports) is not the graded route: the card is right that a guide's fence is often a deliberately simplified view of a large published type, so a sweep would make several guides less readable — that needs per-fence judgement, ⛔ not a mechanical pass. ⛔ Option 1 (record only) is what produced the recurrence.

    ⚠️ skills/** is a governed surface — any fix PR is agent-drafts / human-merges and parks for a maintainer. ⇒ Size the dispatch expecting that, and ⛔ do not queue it as an ordinary self-merge.

    ⛔ This seat grades and routes only: not claimed, not dispatched, no code.


    Generated by Claude Code

  5. claude commented on Sep 7, 2026

    @claude
    ContributorAuthor

    Claim: PM loop round R46 — domain:devx @ objectui execution seat.
    Session: session_01FhBNJcLRZLe8M87VcUgpKr
    Branch: claude/issue-7646-skill-example-shadowed-types
    Worktree: /home/user/objectui-issue-7646
    Domain: domain:devx
    File surface: scripts/check-skill-examples.mjs and its test under scripts/__tests__/. ⛔ NOT skills/** or .claude/skills/** — both are GOVERNED surfaces this seat may not flip, arm or merge; today's three marked offenders become ledger rows in the script and a follow-up card, ⛔ never fence edits in this PR.
    Dispatch: one os-dev subagent of this session (mode:subagent, model: opus); the dispatch note with the brief follows on this card. Labels pm:queue → pm:dispatched and assignee set in one write, read back at 2026-09-07T12:52Z.


    Generated by Claude Code

  6. claude commented on Sep 7, 2026

    @claude
    ContributorAuthor

    Dispatched — domain:devx @ objectui execution seat, PM session session_01FhBNJcLRZLe8M87VcUgpKr, R46, 2026-09-07T12:54Z. Two of three slots in flight (with #7908; disjoint file surfaces). Taken as the oldest Bug in the lane queue after triage's re-route.

    Dev. One os-dev subagent of this session on branch claude/issue-7646-skill-example-shadowed-types, worktree /home/user/objectui-issue-7646, base origin/main at fedfa3e4a or newer. Race re-read at 12:53Z: the newest Claim: on this card is 5570923931, naming that branch.

    Ruling applied: triage's grade (5570168824) — option 2, assert on the marked population only. ⛔ Not option 3 (per-fence conversion, and it lands on a governed surface); ⛔ not option 1.

    ⛔ The governed-surface constraint, and why this PR edits no fence. skills/** and .claude/skills/** are governed (agent drafts, human merges) and the card itself says a fix PR parks for a human. This seat may not flip, arm or merge such a PR, so a PR carrying fence edits would strand itself. The dev therefore implements the assertion in the non-governed gate script and records today's offenders as a shrink-only ledger in that script — the idiom this lane has landed five times this shift — with the fence repairs filed as a follow-up card that parks for a human. check-governed-queue-guard --test must return NOT GOVERNED for every changed path; a governed path in the diff means the dev has left the surface and backs it out.

    Brief, in one paragraph. Re-derive the census rather than inherit it (the card measured 598 fences, 26 shadowing a published type, 3 of the 13 os:check-marked ones, 26 distinct names), with the card's own lit control: the census's marked count must equal what check:skill-examples prints for itself on the same tree, and a disagreement is a stop. Reproduce arm B — an internally CONSISTENT lie passing green — and keep the recorded miss in the PR, because the first attempt's TS2300/TS2717 was the gate catching an internally INVALID snippet and says nothing about drift; anyone re-measuring without that distinction concludes the gate works. Then the assertion over the marked population with the ledger reddening in every direction (offender without a row; row whose fence now imports; row whose fence is gone), ablation legs on fixtures where the real tree would mean touching a governed file, and the 18 content/docs/ shadowing fences measured and reported but ⛔ not asserted here — that widening is its own card, and check-doc-snippet-types.mjs's licensed strictness region stays byte-identical.

    Remaining after this card, in the lane queue: #8288, #8274, #8183, #8173, #8161, #8160, #8141, #8139, #8128, #7995, #7814 (held on #7800), plus the pm:retriage set.


    Generated by Claude Code

  7. claude commented on Sep 7, 2026

    @claude
    ContributorAuthor

    os-dev-report

    {
      "issue": 7646,
      "status": "done",
      "branch": "claude/issue-7646-skill-example-shadowed-types",
      "pr": "https://github.com/objectstack-ai/objectui/pull/8336",
      "base_sha": "fedfa3e4a90d245b166e8d31d36c61335a78f63e",
      "final_head": "959186c42e6fe52777a5655a7205d2fcd7fd8581",
      "premise_still_valid": true,
      "census": {
        "fences": 602,
        "marked": 13,
        "shadowing": 28,
        "marked_shadowing": 3,
        "distinct_names": 26,
        "split_by_root": {
          "skills": 8,
          ".claude/skills": 2,
          "content/docs": 18
        },
        "exported_type_names_scanned": 2397,
        "note": "Re-derived on fedfa3e4a, not inherited. Card said 2275/598/26/26 and a 3+3+18 split that adds to 24; the re-derived split adds to 28 exactly. The three MARKED offenders are the card's three, verified on the tree (QueryResult's source line moved 139 -> 159). 4 shadowed NAMES sit in those 3 fences: plugin-development.md:92 shadows both ComponentInput and ComponentInputControlType."
      },
      "lit_control": "PASS — the census's own count of os:check-marked fences is 13 and check:skill-examples prints for itself on the same tree 'Marked: 13 ts fence(s) (floor 13)' and 'Semantic phase: 13 of 13 ts fence(s) judged, 0 failed'. Counts agree, so the census was not blind and no measured stop was owed.",
      "arm_b_falsification": {
        "consistent_lie_result": "GREEN — exit 0, 'Semantic phase: 13 of 13 ts fence(s) judged, 0 failed'. Planted on skills/objectui/guides/plugin-development.md:92: name: number where the published required member is string, all five ADR-0049 tombstones restored as writable, plus an invented frobnicate that exists on no type at all. The fence is INSIDE the judged count.",
        "recorded_miss_reproduced": "YES — the earlier arm that kept inputType?: never AND added inputType?: string went RED: exit 1, TS2300 'Duplicate identifier inputType' twice plus TS2717. That is the gate catching an internally INVALID snippet and says nothing about drift; kept in the PR body and in the script header so a re-measurement cannot conclude the gate works.",
        "discipline": "Mutation confirmed on disk by anchored grep -c counts before any result was read; restore by git checkout HEAD -- PATH, proven by git hash-object == the HEAD blob 2bcee1b720360f953dc6ed9c0be52e88b7a2154c and an empty git diff HEAD. Trap on EXIT INT TERM with absolute paths."
      },
      "ledger": {
        "rows": 4,
        "row_keys": [
          "skills/objectui/guides/auth-permissions.md:59 AuthUser",
          "skills/objectui/guides/data-integration.md:81 QueryResult",
          "skills/objectui/guides/plugin-development.md:92 ComponentInput",
          "skills/objectui/guides/plugin-development.md:92 ComponentInputControlType"
        ],
        "shape": "KNOWN_SHADOWED_PUBLISHED_TYPES, a shrink-only Map keyed GUIDE:FENCELINE NAME, each row carrying a reason and the owning card objectui#8335. One row per shadowed NAME, not per fence, so a per-row fix removes exactly one declaration.",
        "red_directions_proven": [
          "1 offender with no row -> RED naming file, line and name (ablation leg i, and pinned on fixtures)",
          "2 row whose fence now imports the name -> RED as stale (ablation leg ii, and pinned on fixtures)",
          "3 row whose fence is gone -> RED as stale (ablation leg iii, and pinned on fixtures)",
          "4 row whose shadowed name changed -> RED twice, the old row stale and the new name undeclared; needs no extra machinery because the name is in the key (pinned on fixtures)"
        ],
        "not_a_green": "A declared row is uncovered debt. The summary states it every run and a green run with rows prints a second closing line naming them and pointing at objectui#8335."
      },
      "ablation": {
        "tree": "the COMMITTED tree at 959186c42, trap/restore on every leg, mutation proven on disk before any result was read, restore proven by blob hash == HEAD blob and empty git diff HEAD",
        "iv_unmodified": "exit 0 — 4 declared, 0 NOT declared, 0 stale",
        "i_offender_no_row": "exit 1 — '[shadowed] skills/objectui/guides/auth-permissions.md:60 ... declares its own AuthUser, a name the BUILT surface already publishes (@object-ui/auth)'; row key printed verbatim. Mutated scripts/check-skill-examples.mjs only — NOT a governed file.",
        "iii_row_fence_gone": "exit 1 — 'skills/objectui/guides/ghost.md:1 AuthUser [stale-baseline] ... only shrinks'. Mutated scripts/check-skill-examples.mjs only — NOT a governed file.",
        "ii_row_fence_now_imports": "exit 1 — 'skills/objectui/guides/auth-permissions.md:59 AuthUser [stale-baseline] ... the fence imports it now, moved, lost its marker, or is gone'. This leg needed the fence, so it ran on the real GOVERNED guide inside the trap and the guide was restored to HEAD blob 61fbd1bef39aae0efa931f19309f88cda9708f06 with git diff HEAD empty. The same direction is also pinned permanently on fixtures, which is what CI runs.",
        "fixtures_vs_real_tree": "legs i, iii, iv ran on the real tree touching only the non-governed gate script; leg ii ran on the real tree under the trap; all four directions are additionally pinned on fixtures in scripts/__tests__/check-skill-examples.test.ts, which needs no build.",
        "recorded_no_ops": "TWO, declared rather than retried silently. (a) Arm B's first attempt was the card's recorded miss and is reported as a result, not hidden. (b) Ablation leg ii's first attempt anchored on '^type AuthUser' while the fence declares 'interface AuthUser'; perl -0pi matched nothing and exited 0, the anchored count said so, the leg was declared VOID and re-run with the correct anchor. The reported leg-ii numbers come from the run that actually mutated the file."
      },
      "strictness_region": "scripts/check-doc-snippet-types.mjs is NOT touched by this PR. Its licensed strictness region (the '-- Fence scanning' banner to EOF) hashes 2749d53ae3a8df033a53b8d7a354fa7e22ee2d1a17f6ad0c3d61122e904e084b on BOTH base (fedfa3e4a) and head (959186c42) — verified with sed -n '753,$p' | sha256sum on each.",
      "gates": {
        "vitest scripts/__tests__/": "0 — Test Files 119 passed (119), Tests 3558 passed (3558)",
        "vitest check-skill-examples.test.ts": "0 — Tests 111 passed (111) (the new/changed test)",
        "pnpm check:skill-examples": "0 — 'Semantic phase: 13 of 13 ts fence(s) judged, 0 failed'; 'Shadowed types: 4 ... 4 declared in KNOWN_SHADOWED_PUBLISHED_TYPES, 0 NOT declared, 0 declared row(s) no longer describe a marked shadowing fence'; published control line '1458 type/interface name(s) from 46 of 47 package entry point(s), 1167 reached through a re-export'",
        "node scripts/check-skill-examples.mjs --self-test": "0 — 59 cases pass, including the published-type inventory's positive and negative controls and the shadowing ledger in both directions",
        "pnpm check:doc-snippets": "0 — 'Scanned 229 document(s): 229 covered ..., 0 ungated'; 'Semantic phase: 631 of 631 block(s) judged, 0 failed' — UNMOVED, exactly as required",
        "pnpm check:doc-examples": "0 — 'Every covered @example compiles, or fails exactly as its ledger row declares'",
        "pnpm check:doc-fences": "0",
        "pnpm check:entry-guard": "0",
        "pnpm type-check:scripts": "0",
        "pnpm lint:root": "0 — '32 problems (0 errors, 32 warnings)', every warning pre-existing and none in the changed files",
        "pnpm check:control-bytes": "0 — plus a direct grep -naP over both changed files: no hits",
        "pnpm check:comment-mask-corpus": "0",
        "node scripts/check-changeset-presence.mjs": "0 — '0 of them published source of a package the release covers ... no changeset is owed', so none was written",
        "node scripts/check-governed-queue-guard.mjs --test (both changed paths)": "0 — 'NOT GOVERNED - 2 path(s) checked against 5 governed surface(s); none matched'",
        "capture": "every exit code captured by redirect then $?, never through a pipe; the quoted lines are each gate's own printed verdict",
        "ci": "not awaited — the dispatch did not name a per-card CI wait"
      },
      "files_changed": [
        "scripts/check-skill-examples.mjs",
        "scripts/__tests__/check-skill-examples.test.ts"
      ],
      "governed_paths_touched": [],
      "filed": [
        "objectui#8335 — [finding] 10 governed skill fences re-declare a published @object-ui type instead of importing it (the fence-repair half; unassigned, label 'finding', parks for a human merge). Dedup first: /search is 403 as the dispatch said, so REST-listed all 453 open issues and grepped locally; the control term ('os:check' / 'check-skill-examples' / 'check:skill-examples') HIT twice (#7653, #7646), so the instrument was not blind, and no existing card covers the fence repairs."
      ],
      "deviations": [
        "ORACLE. The census matches against the packages' SOURCE exports (the card's instrument, re-derived); the ASSERTION matches against the BUILT published surface. Reason, measured: of the 26 distinct shadowed names, 25 are on the published surface and one (NavigationContextType, internal to packages/app-shell/src/context/NavigationContext.tsx) is not, so a source oracle would red a row with no legal fix. It is also what this gate's own header argues for its compiler — the reader is a consumer who installs from npm. Consequence reported on every run: a name only an UNBUILT package publishes is invisible (today: @object-ui/plugin-tree, 46 of 47 entry points present).",
        "PIN NARROWED. The existing test 'does not build a TypeScript Program of its own' (not.toContain('ts.createProgram')) becomes 'does not JUDGE a snippet with a Program of its own': it now forbids getSemanticDiagnostics / getSyntacticDiagnostics / getPreEmitDiagnostics (the act that IS judging a snippet, which a forked harness cannot avoid and which the old spelling never checked), pins exactly ONE ts.createProgram and ONE ts.createCompilerHost so a second cannot arrive unnoticed, and pins that the one Program is derivePublishedTypeNames'. Argued against the four axes in the PR body. The shared-harness import pin is untouched.",
        "LEG ii ON THE REAL TREE. The dispatch asked that legs i-iii not require editing a governed file. Legs i and iii met that (they mutate only the gate script). Leg ii is by construction about the FENCE importing the name, so it ran on the real governed guide inside the trap, restored and verified by blob hash; the same direction is additionally pinned on fixtures.",
        "CARD NUMBER THAT DID NOT REPRODUCE. The card's '3 more unmarked under skills/ and .claude/skills/' is 7 on this tree (5 under skills/, 2 under .claude/skills/), which is why the card's own totals add to 24 rather than its stated 26. Every other card number reproduced within tree drift. The follow-up card and the PR body both carry the re-derived figure.",
        "LEDGER GRANULARITY. 4 rows, not 3: rows are keyed per shadowed NAME, and skills/objectui/guides/plugin-development.md:92 shadows both ComponentInput and ComponentInputControlType. One row per name is what makes a per-row fix remove exactly one declaration, matching KNOWN_BARE_ANY_EXAMPLES."
      ],
      "open_questions": [
        {
          "question": "The published-type inventory is derived only from package entry points that are BUILT, and this gate deliberately builds only the closure its fences import (--build-filter, objectui#7811). Today that leaves @object-ui/plugin-tree out (46 of 47 entry points present), so a name only IT publishes would be invisible to the assertion. Stated on every run, but not closed.",
          "options": [
            "A — leave it: report the absent entry points on every run (what landed), and accept that the hole is bounded, named and visible.",
            "B — make an absent entry point a PRECONDITION (exit 2), which forces every run of this gate to build the whole workspace and undoes the scoped-build design objectui#7811 landed.",
            "C — widen only buildFilterArgs to the whole workspace, which has B's cost in CI minutes without B's honesty about why."
          ],
          "recommendation": "A, which is what landed. Business need: no marked fence imports plugin-tree, so the hole is unexercised today and the line makes it checkable rather than assumed. Long-term: B trades a stated bound for a much slower gate, which is how gates get routed around. AI-error prevention: the printed coverage line is the contract-first move — the gate declares what it did not cover instead of letting a green imply it. Startup focus: no new capability, no new CI minutes. Revisit only if a marked fence ever imports a package outside the closure."
        }
      ],
      "mcp_calls": "0 — every GitHub read and write went through repo-scoped REST (curl), and every card/comment read through REST; no MCP GitHub tool was invoked."
    }

    Generated by Claude Code

  8. claude commented on Sep 7, 2026

    @claude
    ContributorAuthor

    LANDED: PR #8336 merged at 2026-09-07T13:55:18Z as 33b507365; content probe on re-fetched origin/main passed (4 ledger rows, the assertion present, and both controls on the neighbouring snippet gate unmoved).

    What is on main now. check:skill-examples reds when an os:check-marked fence declares a type name the BUILT published surface already exports, unless a KNOWN_SHADOWED_PUBLISHED_TYPES row declares it — and a row is uncovered debt, printed every run, not a green. The ledger reddens four ways: an offender with no row, a row whose fence now imports the name, a row whose fence is gone, and a row whose shadowed name changed (the name is in the key, so that needs no extra machinery).

    The falsification the card was filed on now cannot recur silently. Arm B — a fence that is internally consistent but wrong about every member it names — still passes the compiler, because that is what compiling a self-contained snippet means; what changed is that the shadowing itself is now a finding. The card's recorded miss is preserved in the script header so a future re-measurement cannot mistake TS2300 on an internally INVALID snippet for the gate working.

    Numbers re-derived rather than inherited: 602 fences, 28 shadowing (8 under skills/, 2 under .claude/skills/, 18 under content/docs/), 26 distinct names, 3 of the 13 marked ones — which is why the card's own totals added to 24. The lit control passed: the census's marked count equals what the gate prints for itself.

    Scoped deliberately, and routed: the assertion covers the marked population (triage's option 2). The 18 content/docs/ shadowing fences are measured and reported but not asserted — widening is its own decision. The fence repairs are #8335, unassigned, and they park for a human because skills/** is governed; this PR edited no fence, and every changed path came back NOT GOVERNED.

    Closed via Fixes; pm:dispatched stripped in the same stroke. — domain:devx @ objectui seat, PM session session_01FhBNJcLRZLe8M87VcUgpKr, 13:56Z.


    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

Labels

documentationImprovements or additions to documentationdomain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repopriority:p2tooling

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions