Skip to content

finding(tests): the comment projection at three packages/types readers is inert on every subject the tree has — removing it entirely changes nothing, so nothing would notice it being lost #9768

Description

@os-try-charles

The comment projection at three packages/types readers is inert on every subject the tree has today. Measured during objectui#9751: over 16 interface bodies, the member map produced with the projection and with no projection at all are identical, and the test file still passes with the projection removed.

⇒ these readers carry a guard that nothing exercises, so nothing would notice if it were deleted, weakened, or quietly reverted to a hand-rolled regex. ⛔ That is not a claim the guard is wrong — it is correct, and objectui#9761 just moved it onto scripts/js-comment-mask.mjs with zero behavioural risk precisely because it is inert. The finding is that its correctness currently rests on a classification argument and not on anything that reddens.

The carriers

  • packages/types/src/__tests__/overlay-node-slot-doc-types-7082.test.ts
  • packages/types/src/__tests__/alert-dialog-read-dialect-7104.test.ts
  • packages/types/src/__tests__/overlay-trigger-union-7081.test.ts

Each strips comments out of a .ts source before counting interface members. The hazard the original docblock named is real — prose inside a block comment that looks like a member row would be counted as one — but no subject in the tree spells it.

Why this is its own card and was not folded into objectui#9761

⛔ Adding a forcing fixture inside that pull request would have mixed a behaviour-preserving conversion with a new assertion, and afterwards a reviewer could not tell which of the two any test result was about. The seat ruled option A (land the conversion as is, state the inertness as measured) with this as the follow-up. Record: objectui#9751's ACCEPT and landing comments.

Sketched direction (⛔ not chosen — a triage call)

Give the projection something to defend: a fixture interface body carrying a member-shaped line inside a block comment, pinned so the member count is wrong when the projection is removed. ⚠️ The fixture has to be a subject, not a synthetic string handed to the reader — the distinction objectui#9748 drew between "the file's measured behaviour" and "the shape the file does not have today" applies here too, and a pin that blurs it teaches the wrong thing.

⛔ Not a request to convert anything: objectui#9761 already did the conversion. ⛔ Not objectui#9751 (that was residue plus the recurrence channel, and it is closed).

Provenance

Surfaced by objectui#9751's dev as an open question after its reverse ablation came back green, ruled by the domain:devx @ objectui execution seat, session_015h79niBMyoB1xcaQje3uiz, R73, 2026-09-18. The measurement is the dev's; the ruling to card it rather than fold it in is the seat's. ⛔ This seat does not grade, route or prioritise.

Dedup words: inert guard · comment projection · overlay-node-slot-doc-types-7082 · member count fixture · 9761 follow-up


Generated by Claude Code

Activity

  1. os-try-charles commented on Sep 18, 2026

    @os-try-charles
    CollaboratorAuthor

    Claim: PM loop round R74
    Session: session_015h79niBMyoB1xcaQje3uiz
    Branch: claude/issue-9768-inert-comment-projection
    Worktree: objectui-issue-9768
    Domain: domain:devx
    File surface: packages/types/src/__tests__/ and packages/types/src/ — declared at AREA level per SKILL.md:481. The second area only if a forcing subject has to live beside the readers rather than inside a test. ⛔ Not a licence to widen: anything outside these stops and is explained in the report.
    Container & model: M, mode:subagent, model: the seat's default judgement tier — objectui has no scripts/pm/dispatch-gates.mjs, so ⛔ there is no --tier output to quote and the tier is this seat's per-card call.
    Clause-②: no
    Thread-read: 5725896062
    Serial constraints cleared: measured this tick over all 13 open pull requests, GET /pulls/{n}/files fully paginated, 1843 filenames; ⭐ positive control .github/workflows/ci.yml -> PR #9584 fired. The three reader files, packages/types/src/overlay.ts and scripts/js-comment-mask.mjs are held by 0 of them. Adjacent, ⛔ not colliding: #9540 and #8941 touch packages/types/src/objectql.ts and its zod twin, #9540 also object-gallery-filter-9309.test.ts, #9797 touches packages/types/src/data-display.ts — none on this card's files. ⚠️ Four PRs currently fence the rest of this lane's queue (#9584, #5400, #9592, #9391); this card is the one that is clear of all four.


    Generated by Claude Code

  2. os-try-charles commented on Sep 18, 2026

    @os-try-charles
    CollaboratorAuthor

    os-dev-report

    {
      "issue": 9768,
      "status": "done",
      "branch": "claude/issue-9768-inert-comment-projection",
      "pr": "https://github.com/objectstack-ai/objectui/pull/9814",
      "session": "session_015h79niBMyoB1xcaQje3uiz",
      "premise_still_valid": true,
      "summary": "Population established mechanically first, not inherited: instrumenting `stripComments` in scripts/js-comment-mask.mjs and running the three readers records 67 calls, 63 of them bodies located in a tracked non-test file and 4 synthetic string literals, over 20 DISTINCT (file, interface) bodies -- 10 declarations (the nine overlay interfaces plus EmptySchema in feedback.ts) and 10 docs fences. The card's '16 interface bodies' is NOT reproducible; 20 is the measured number. Triage's escalation condition is NOT met: replaying every captured body through the readers' own member regex with and without the projection gives an identical member map on 0/20 -- no live defect, no p2, the fixture stays the right deliverable. The projection is nevertheless exercised (it deletes prose in 17/20 bodies, 11754 bytes in the AlertDialogSchema body alone); it just never changed an answer. Each of the three readers now declares `CommentProjectionForcingSubject`, a subject on disk whose body carries a member-shaped row inside an ORDINARY block comment (no star gutter, so the row sits on the two-space anchor `members()` matches), read off disk and extracted by the reader's own interfaceBody + members -- a subject, not a synthetic string. Per file deliberately, because each reader carries its own copy of members(). No reader behaviour, regex or subject list moved, and scripts/js-comment-mask.mjs is untouched.",
      "tests": "THROUGH THE LOCK (../objectstack/scripts/pm/os-verify-lock.sh, OS_VERIFY_LOCK_SLOT=objectui-9768): `pnpm --filter @object-ui/types type-check` -> 'os-verify-lock: VERDICT command-exit 0 - held the lock 33s - waited 0s' (tsc --noEmit, tsconfig.examples.json, tsconfig.test.json); `pnpm --filter @object-ui/types test` -> 'os-verify-lock: VERDICT command-exit 0 - held the lock 26s - waited 0s', 'Test Files 204 passed (204)', 'Tests 4777 passed (4777)'. THE THREE READERS: 'Tests 161 passed (161)' (155 before this change). ABLATION, both legs, same mutation ('const bare = stripComments(body);' -> 'const bare = body;' in all three readers), proven ON DISK before reading anything (3 ABLATION markers injected, 0 surviving stripComments(body) calls) and restored under a trap with 'git checkout HEAD --' verified by blob hash per file plus an empty 'git diff HEAD': LEG A, the PRE-FIX state 6a0d1a435 with the projection removed -> 'Test Files 3 passed (3)', 'Tests 155 passed (155)', exit 0 (the guard was inert). LEG B, with the forcing subject and the projection removed -> 'Test Files 3 failed (3)', 'Tests 3 failed | 158 passed (161)', exit 1, one failure per reader, all on the same assertion: '`members()` reads the two DECLARED rows and not the row in the comment', AssertionError expected [ 'phantom', 'real', 'label' ] to deeply equal [ 'real', 'label' ] -- the member LIST moved, not a grep count. The census instrumentation of js-comment-mask.mjs was restored the same way (blob fefd98191925d0ace305a89f5713df1506a5a59d == HEAD). GATES BY POPULATION: check:comment-mask-corpus exit 0 ('5078 files, 1 disagree (0 comment bytes read as code, 1517 code bytes read as comment)' -- the objectui#7882 residue unchanged, inside its ceiling); scripts/check-hand-rolled-comment-mask.mjs exit 0 ('6 private comment projection(s) in 5 file(s); DEBT names 5') -- the DEBT ratchet does not move, the one regex added is a LOOKUP not a removal position; check:pending-changeset-literals exit 0; markdown-test-inputs --audit exit 0; check:control-bytes exit 0; check:test-path-roots exit 0 (the new read is rooted at the test file, never the cwd); check:new-line-citations exit 0 ('0 new citation(s)'); check:changeset-claims exit 0; check-changeset-presence exit 0 (empty-frontmatter changeset = the declared exemption); check-lint-coverage exit 0 ('46/46 packages linted, 0 with outstanding errors'); `pnpm --filter @object-ui/types lint` 0 errors (the two warnings on overlay-trigger-union-7081.test.ts are pre-existing 'data?: any' rows, absent from this diff). NOT MEASURED: check:node-esm-load -- not coupled by population, nothing under any package's published files[] moves (tsconfig.json excludes **/__tests__/**), so no dist artefact changes; and remote CI, which is the PM's read, not mine.",
      "mcp_calls": "0 - no MCP GitHub tool was called, read or write; every GitHub call went through the REST proxy with curl",
      "api_writes": "3 - POST /repos/objectstack-ai/objectui/pulls (draft, #9814); POST /repos/objectstack-ai/objectui/issues/9768/comments (this report); plus 2 git pushes (empty-branch routing probe, then the commit). No label write: in objectui the skip-changeset label is read by nothing and is banned for this seat, and the empty-frontmatter changeset is the gate-authoritative declaration; needs:contract-review belongs to the seat.",
      "open_questions": [],
      "out_of_scope_findings": [
        "noted, not filed: all 4 synthetic string literals these readers hand members() are inert too, including the 'JSDoc stripping does not eat real rows' counter-probe in overlay-node-slot-doc-types-7082.test.ts, which reads as though it exercised the projection -- its member-shaped line sits behind a docblock gutter (three spaces and a star) while members() anchors on exactly two spaces plus an identifier, so it passes identically with the projection removed. Not filed: the probes are honest as tests of the member regex, and this PR supplies the thing they were mistaken for. Carrier: whoever next edits those probes.",
        "noted, not filed: the card's '16 interface bodies' is not reproducible against the readers' actual subject lists (measured 20). It is consistent with a count of one reader's six docs pages plus the ten declarations, but that is a reconstruction, not a reading. No card: the verdict the figure supported is unchanged, and the correction is recorded on the PR and in this report where the next reader of the card will meet it."
      ]
    }

    Generated by Claude Code

  3. os-try-charles commented on Sep 18, 2026

    @os-try-charles
    CollaboratorAuthor

    ACCEPT — PR #9814, head 04d2dce19, no patch round. Readings below are this seat's own.

    Checklist

    reading
    CI 36 of 36 green, 36 distinct names — waited for every check to complete.
    Path surface 4 files. The three readers are inside the declared area; .changeset/9768-…md is outside it (see deviations). Fence re-measured over 18 open pull requests / 1857 filenames, fully paginated; positive control .github/workflows/ci.yml -> #9584 fired; the three readers are held by #9814 alone and scripts/js-comment-mask.mjs and packages/types/src/overlay.ts by nobody.
    ⭐ Shape Purely additive — 0 deletions in all four files. That turns "no reader behaviour, regex or subject list moved" from a claim into a structural fact, which is the strongest form the deliverable's ⛔ do not change its behaviour could take.
    New CI context none; no workflow file touched.
    Governed surfaces none.
    Clause-② no and true: this adds a subject and two assertions, relaxes nothing.
    Pushed artefact commit trailer Co-Authored-By: Claude + Claude-Session:, no model identifier.
    The lock the turbo-build verifications went through os-verify-lock.sh with their verdict lines quoted.

    The three things this dispatch demanded, checked here rather than taken on report

    1. The population was established mechanically, not inherited — stripComments instrumented, the readers run, 67 calls captured over 20 distinct (file, interface) bodies. ⇒ ⛔ the card's "16" is not reproducible, and the card is this seat's. Recorded as a correction to the card, not a footnote.
    2. Triage's escalation question was answered against that population: every captured body replayed through the readers' own member regex with and without the projection ⇒ identical member map on 0 of 20. No live defect, no p2, and the fixture remains the right deliverable. ⭐ With the sharper half stated rather than smoothed over: the projection is doing work — it removes prose from 17 of 20 bodies, 11,754 bytes in the AlertDialogSchema body alone — it has simply never changed an answer.
    3. The fixture is a subject, ⛔ not a synthetic string: interfaceBody(readFileSync(OWN, 'utf8'), OPENER, OWN) — read off disk and extracted exactly as a declaration is. And the pin asserts the member list (['real','label'], becoming ['phantom','real','label'] when the projection is dropped), ⛔ not a count.

    ⭐ What it added that was not asked for, and is the best part

    A second leg on the new pin:

    it('the subject really carries a member-shaped row inside a block comment — read off the UNPROJECTED text')
    "Without this leg the pin below passes just as well against a subject that lost the row, and an empty guard reads exactly like a live one."

    ⇒ a fixture that silently lost its forcing row would leave the new pin green — the new guard would become the inert guard it exists to cure. That is this card's own thesis applied one level down, unprompted. The subject also carries a ⛔ warning against adding a * gutter or "tidying" the row, because either would un-force it without any test noticing.

    Landing probe, pre-validated against main

    token reading why it is that token
    fire export interface CommentProjectionForcingSubject { 0 → 2 per reader the declaration and the OPENER the pin must name to find the body
    fire expect([...rows.keys()]).toEqual(['real', 'label']) 0 → 1 per reader the leg that reds, asserting the member list
    fire read off the UNPROJECTED text 0 → 1 per reader the second leg above
    control const bare = stripComments(body); 1 → 1 per reader reasoned first: the deliverable forbids changing the reader, so if members() moved the fix exceeded its mandate
    control the counter-probes describe block 1 → 1, 0 → 0, 1 → 1 reasoned first: the dev measured those probes as themselves inert and correctly left them alone — movement either way is widening. Present in 2 of 3 readers, measured per file rather than assumed

    ⚠️ This probe has no clear leg, because the change deletes nothing. That is a property of the change, ⛔ not a gap in the probe.

    ⚠️ And the probe first printed a disagreement that was mine, not the change's — I had expected the forcing subject once per reader and the counter-probe block in all three. Both expectations were wrong; the readings are right. Recorded because it is the third time this shift that the faulty instrument was this seat's own.

    Deviations

    1. .changeset/9768-comment-projection-forcing-subject.md sits outside the declared areas — a required artefact of the changeset gate, ⛔ not a widening.
    2. Reported and correctly not filed: the pre-existing "JSDoc stripping does not eat real rows" counter-probe reads as though it exercised the projection but does not — its member-shaped line sits behind a docblock gutter while members() anchors on exactly two spaces, so it passes identically with the projection removed. ⭐ A probe mistaken for a guard, in the same file, of the same class as this card — and this pull request supplies the thing it was mistaken for.

    Releasing to the merge queue.


    Generated by Claude Code

  4. removed their assignment
    on Sep 18, 2026
  5. os-try-charles commented on Sep 18, 2026

    @os-try-charles
    CollaboratorAuthor

    Landed. PR #9814 merged at 2026-09-18T07:25:06Z, squash 30a170e51, through the merge queue (enqueued 07:04:45Z, receipt added_to_merge_queue, ⛔ not the enable call's 200). No patch round.

    Landing probe, pre-validated against main before release and re-read on main after — per reader, all three:

    token reading why it is that token
    fire export interface CommentProjectionForcingSubject { 0 → 2 the declaration and the OPENER the pin must name to find the body
    fire expect([...rows.keys()]).toEqual(['real', 'label']) 0 → 1 the leg that reds, asserting the member list
    fire read off the UNPROJECTED text 0 → 1 the second leg — the fixture cannot silently lose its forcing row
    control const bare = stripComments(body); 1 → 1 reasoned first: the deliverable forbids changing the reader, so movement here means the fix exceeded its mandate
    control the counter-probes describe block [1, 0, 1] unchanged reasoned first: those probes were measured inert and correctly left alone. Present in 2 of 3 readers — measured per file, ⛔ not assumed

    ⚠️ No clear leg: the change deletes nothing (0 deletions in all four files). A property of the change, ⛔ not a gap in the probe.

    Errata 62b: FIRED. By ancestry: M^ is 2daa6c001, and 2daa6c001...04d2dce19 compares diverged (ahead 1, behind 5).

    ⛔ A correction this seat owes, and it is about its own instrument

    This landing sat 20m21s in the merge queue — past the 20.2-minute figure this seat has been reporting as an ejection margin — and it merged normally.

    ⇒ the two numbers were never comparable. timeout-minutes: 20 bounds a job's own run; queue dwell is queueing plus the build. objectui#9635's ejection was a job hitting its ceiling (20.2 min of run against 13.1 min on the PR head); the 20 / 19m26s / 18m46s / 20m21s figures are dwell. Two different clocks, and this seat has been reporting them as one — including to the maintainer, as a standing open item about a "pattern in the margin".

    ⭐ That is the same error class this lane keeps cataloguing — measuring a different quantity than the claim names — committed by the seat, three times this shift now, and this is the one that reached a maintainer-facing item. The dwell figures stand as dwell; ⛔ they say nothing about the job ceiling, and the "three landings in a row inside the ejection margin" framing is withdrawn.

    What the card produced. The population the card asserted (16 interface bodies) is not reproducible — 20 is the measured number, established by instrumenting stripComments rather than inherited. Triage's escalation condition was answered against that population: identical member maps on 0 of 20 ⇒ no live defect, p3 stands. ⭐ And the sharper half: the projection is doing work — it removes prose from 17 of 20 bodies, 11,754 bytes in the AlertDialogSchema body alone — it had simply never changed an answer. It now has a subject that makes it change one.


    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

    Labels

    domain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repopriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions