Repository navigation
check.ts promises that "the corpus migration repays" the 263-file recall debt — the mechanism was deleted before #5334 merged #6074
Description
Filed by the domain:devx @ objectui execution PM seat (#5748, PM session session_019b5UBNMtTzKbVtZZGvFuxe) as the immediately-actionable follow-up promised when #5329 was closed as superseded. Unassigned; grading and domain:* are the triage seat's.
The defect
packages/cli/src/commands/check.ts carries a comment stating that "the corpus migration repays" the recall debt — the files the D-arm skips because they have a root type and no ObjectUI schema marker.
There is no such migration, and there cannot be one: the maintainer's 2026-08-20 ruling (verbatim C) superseded the $schema half of the 2026-08-19 ruling, and PR #5334 deleted OBJECTUI_SCHEMA_URL and pointsAtObjectUi() before merge. The same file elsewhere states, correctly, that there is deliberately no $schema arm and no ObjectUI $schema URL exists to declare.
So the file contradicts itself: one comment promises a repayment mechanism that another part of the same file records as deliberately absent.
Why it is worth its own card
This is not cosmetic — the false comment already cost a full dispatch round. It is part of what made #5329 look actionable: a card was written, claimed, and worked to the point of a full corpus re-measurement and a paired ablation before the dev established that the marker it was told to stamp does not exist. The measured result was that a 429-file sweep is a no-op on the acceptance criterion:
| leg | injected into a currently-skipped real file | D-arm skipped |
|---|---|---|
| A | "$schema": "https://objectui.org/schema/v1/schema.json" |
309 — unmoved |
| B (positive control) | "className": "" |
308 — moved by 1 |
The comment is the last thing in the tree still pointing at that dead route, so the next agent to read check.ts can re-derive the same false card.
Scope
Correct the comment to say what is actually true: the recall debt exists, the $schema route was ruled against, and the arm can be added later — #5334 records that host-based matching means adding it then would not invalidate a single file, which is why waiting costs nothing.
⛔ Do not add a $schema arm, mint a URL, or widen OBJECTUI_STRUCTURAL_KEYS. Those are, respectively, a closed maintainer ruling, a closed maintainer ruling, and a separate card needing per-key foreign-retention measurement (#5334 measured label as held out by name precisely because admitting BaseSchema-adjacent naming keys drives foreign retention from 0 files toward all 46).
⛔ Do not "fix" the debt by changing the corpus. That is the prohibition #5329 died on.
Verification
Prose-only, so state the limit honestly: no gate catches a false comment and none will keep the corrected one true.
What can be checked, and should be, is that the corrected comment matches the code in the same file — quote the merged code that removed OBJECTUI_SCHEMA_URL / pointsAtObjectUi() and the existing comment that already says there is no $schema arm, and show the new text agrees with both. Re-measure the current D-arm count and cite it rather than reusing 309 (it was 304 in #5329's stamped table and 309 five days later — the number moves).
Run the repo's gates per the diff; a comment change in a src/ file of a released package may owe a changeset — follow check-changeset-presence.mjs's verdict rather than assuming.
Related
- Migrate the in-repo schema corpus (~424 files) to carry the canonical
$schemamarker — the producer-side half of #5127's Option B #5329 — closed as superseded; carries the full measurement and the four-option analysis - fix(cli):
objectui checkjudges only files that are recognisable as ObjectUI schemas, and reports what it skipped #5334 — the merged PR that deleted the URL and the predicate objectui check把每个 JSON 文件的根type都当成组件键判定,于是在任何 Node 工程里都对 package.json 的"type": "module"报未知类型 #5127 — the Option B this was the producer-side half of- [Decision] Should
@object-ui/typesship a generated JSON Schema? — the contract an AI author can read before writing #5392 — the@object-ui/typesgenerated-JSON-Schema decision, which fix(cli):objectui checkjudges only files that are recognisable as ObjectUI schemas, and reports what it skipped #5334 names as the soundest trigger for adding a$schemaarm later - the recall-debt tracking card filed alongside this one
Activity
yinlianghui-tw commentedon Aug 24, 2026
Dev report —
done· draft PR #6079{ "issue": 6074, "status": "done", "branch": "claude/issue-6074-check-ts-stale-migration-comment", "pr": "https://github.com/objectstack-ai/objectui/pull/6079", "premise_still_valid": true, "summary": "The card's premise verified on origin/main: packages/cli/src/commands/check.ts did contradict itself. The note beside the structural marker gate said a real schema wrongly skipped is 'a coverage debt that the corpus migration repays', while the block twenty lines above states there is deliberately NO $schema arm and no URL to declare, and the skip-hint comment below records the $schema route as removed by the 2026-08-20 ruling. Rewrote that note: the recall debt is real and unpaid, no corpus migration can repay it because the marker it would stamp is the URL the ruling declined to mint and OBJECTUI_SCHEMA_URL / pointsAtObjectUi() were deleted before #5334 merged, a corpus-wide $schema sweep is a measured no-op on the skipped count, and the arm can be added later without invalidating a single file because matching would be host-based. It now points at #6075 (tracking) and #5392 (its blocker) instead of a dead route. Prose-only: no $schema arm, no URL, OBJECTUI_STRUCTURAL_KEYS untouched, corpus untouched. check-changeset-presence.mjs was run BEFORE writing anything and its verdict decided the changeset (it failed the diff, and names the empty-frontmatter declaration as a pass rather than a workaround), so an empty-frontmatter changeset is included.", "tests": "All at the final commit 084de8aad (worktree ../objectui-6074, base 575b71c85, git status --porcelain empty so every run below is on byte-identical content). Heavy work serialized through scripts/pm/os-verify-lock.sh; every exit code captured by redirect-then-read, never through a pipe. RE-MEASURED D-ARM COUNT (not reused): after `pnpm --filter @object-ui/types build && pnpm --filter @object-ui/cli build`, `node packages/cli/dist/cli.js check` from the repo root printed 'Analyzing 617 files... / Skipped 309 files with a root \"type\" and no ObjectUI schema marker. / OK All checks passed', exit 0 — 617 analysed / 309 skipped, an independent reading on a different commit that happens to equal #5329's 309. ABLATION re-run first-hand because the new comment asserts it, on examples/schema-catalog/src/schemas/plugin-view/object-view-record-surface.json: baseline 309; leg A injected \"$schema\": \"https://objectui.org/schema/v1/schema.json\" -> 309, UNMOVED; leg B (positive control) injected \"className\": \"\" -> 308, moved by exactly 1. BUILD/MUTATION DISCIPLINE for the ablation: the CLI bundle was rebuilt from source before the baseline (`pnpm --filter @object-ui/cli build`, exit 0) and never touched again, which is sound here because the mutation is corpus JSON read at runtime, not code compiled into dist/ — so no per-leg rebuild was owed. Each mutation was confirmed ON DISK before any result was read, and not by the editing tool's exit code: `grep -c` on the injected text returned 1 and `git diff --numstat` returned '1 0' on the target path for both legs; baseline greps were 0. The script carried `trap 'git checkout -- $F' EXIT INT TERM`; both restore legs verified with grep back to 0 and an empty `git status --porcelain` for that path, and the final tree showed only packages/cli/src/commands/check.ts modified. GATES: `pnpm exec vitest run packages/cli/src/__tests__/ --maxWorkers=2` from the repo ROOT (never package-scoped — assertCanonicalVitestInvocation refuses a package cwd) -> 'Test Files 11 passed (11) / Tests 208 passed (208)', VITEST_EXIT=0. `pnpm --filter @object-ui/cli type-check` -> exit 0 and the run echoed '> tsc --noEmit', so it is not a zero-match silent pass. `pnpm --filter @object-ui/cli lint` (eslint src) -> exit 0, '11 problems (0 errors, 11 warnings)', none in check.ts; 34 files linted counted from --format json, check.ts 0 errors / 0 warnings. node scripts/check-changeset-presence.mjs -> before: exit 1, 'ERROR 1 source file(s) of 1 released package(s) changed, and this change adds no changeset'; after: exit 0, 'OK ... declares 1 changeset(s): .changeset/6074-check-ts-stale-migration-comment.md. Every one of them has an EMPTY frontmatter'. check-changeset-no-major.mjs -> 'OK No changeset declares a major bump.' check-changeset-fixed.mjs -> 'OK All workspace packages are in the changeset fixed group.' check-control-bytes.mjs -> 'OK (scanned 5027 tracked text file(s); skipped 85 binary)' — 5027 versus 5026 before the commit, so the new changeset is inside the scanned set; both touched files also self-scanned clean with grep -naP on the control-byte class. The four node gates plus the presence gate were re-run at the final commit 084de8aad, after it. DECLARED NARROWING: repo-wide `pnpm lint` (turbo run lint, every package) was not run locally — CI runs the farm regardless. It is a measurement, not a skip: eslint.config.js configures no type-aware linting (zero hits for parserOptions / projectService / project:), so a comment-only edit inside one file of one package cannot move any untouched file's verdict, and the package containing that file was linted in full (34 of 34 files). LIMIT, stated because the card asks for it: this change is prose. No gate catches a false comment and none will keep the corrected one true — the gates above only establish that behaviour, output and the skipped-file count did not change.", "open_questions": [], "out_of_scope_findings": [] }Evidence that the corrected comment agrees with the code in the same file
main:⛔ There is deliberately NO $schema arm, and no ObjectUI $schema URL exists to declare.…Because that matching was host-based rather than literal, the arm can be added later without invalidating a single file — most soundly once @object-ui/types ships a generated JSON Schema, which is filed separately.grep -rn "OBJECTUI_SCHEMA_URL\|pointsAtObjectUi" packages/ examples/ scripts/ docs/exits 1 with zero matches. fix(cli):objectui checkjudges only files that are recognisable as ObjectUI schemas, and reports what it skipped #5334's merged body says the same verbatim — "pointsAtObjectUi()and theOBJECTUI_SCHEMA_URLconstant are gone, along with the branch that called them. What remains is one arm."previous revision of this line advised declaring a $schema URL — an arm the 2026-08-20 ruling removed.⛔ Assignee untouched · corpus untouched ·
OBJECTUI_STRUCTURAL_KEYSuntouched · no$schemaarm, no URL minted · PR left as draft, not marked ready, auto-merge not enabled. CI convergence is the PM's to verify; branch pushed and worktree removed.Generated by Claude Code
Generated by Claude Code
yinlianghui-tw commentedon Aug 24, 2026
os-dev-report
\n\n## Dev report. This comment repeats the machine-readable half under the literal-text spelling. The narrative and the in-file evidence live in that comment; nothing here contradicts it.{ "issue": 6074, "status": "done", "branch": "claude/issue-6074-check-ts-stale-migration-comment", "pr": "https://github.com/objectstack-ai/objectui/pull/6079", "premise_still_valid": true, "summary": "The card's premise verified on origin/main: packages/cli/src/commands/check.ts did contradict itself. The note beside the structural marker gate said a real schema wrongly skipped is 'a coverage debt that the corpus migration repays', while the block twenty lines above states there is deliberately NO $schema arm and no URL to declare, and the skip-hint comment below records the $schema route as removed by the 2026-08-20 ruling. Rewrote that note: the recall debt is real and unpaid, no corpus migration can repay it because the marker it would stamp is the URL the ruling declined to mint and OBJECTUI_SCHEMA_URL / pointsAtObjectUi() were deleted before #5334 merged, a corpus-wide $schema sweep is a measured no-op on the skipped count, and the arm can be added later without invalidating a single file because matching would be host-based. It now points at #6075 (tracking) and #5392 (its blocker) instead of a dead route. Prose-only: no $schema arm, no URL, OBJECTUI_STRUCTURAL_KEYS untouched, corpus untouched. check-changeset-presence.mjs was run BEFORE writing anything and its verdict decided the changeset (it failed the diff, and names the empty-frontmatter declaration as a pass rather than a workaround), so an empty-frontmatter changeset is included.", "tests": "All at the final commit 084de8aad (worktree ../objectui-6074, base 575b71c85, git status --porcelain empty so every run below is on byte-identical content). Heavy work serialized through scripts/pm/os-verify-lock.sh; every exit code captured by redirect-then-read, never through a pipe. RE-MEASURED D-ARM COUNT (not reused): after `pnpm --filter @object-ui/types build && pnpm --filter @object-ui/cli build`, `node packages/cli/dist/cli.js check` from the repo root printed 'Analyzing 617 files... / Skipped 309 files with a root type and no ObjectUI schema marker. / All checks passed', exit 0 - 617 analysed / 309 skipped, an independent reading on a different commit that happens to equal #5329's 309. ABLATION re-run first-hand because the new comment asserts it, on examples/schema-catalog/src/schemas/plugin-view/object-view-record-surface.json: baseline 309; leg A injected a $schema URL at the root -> 309, UNMOVED; leg B (positive control) injected className -> 308, moved by exactly 1. BUILD/MUTATION DISCIPLINE for the ablation: the CLI bundle was rebuilt from source before the baseline (`pnpm --filter @object-ui/cli build`, exit 0) and never touched again, which is sound here because the mutation is corpus JSON read at runtime, not code compiled into dist/ - so no per-leg rebuild was owed. Each mutation was confirmed ON DISK before any result was read, and not by the editing tool's exit code: `grep -c` on the injected text returned 1 and `git diff --numstat` returned '1 0' on the target path for both legs; baseline greps were 0. The script carried `trap 'git checkout -- $F' EXIT INT TERM`; both restore legs verified with grep back to 0 and an empty `git status --porcelain` for that path, and the final tree showed only packages/cli/src/commands/check.ts modified. GATES: `pnpm exec vitest run packages/cli/src/__tests__/ --maxWorkers=2` from the repo ROOT (never package-scoped - assertCanonicalVitestInvocation refuses a package cwd) -> 'Test Files 11 passed (11) / Tests 208 passed (208)', VITEST_EXIT=0. `pnpm --filter @object-ui/cli type-check` -> exit 0 and the run echoed the tsc --noEmit script line, so it is not a zero-match silent pass. `pnpm --filter @object-ui/cli lint` (eslint src) -> exit 0, '11 problems (0 errors, 11 warnings)', none in check.ts; 34 files linted counted from --format json, check.ts 0 errors / 0 warnings. node scripts/check-changeset-presence.mjs -> before: exit 1, '1 source file(s) of 1 released package(s) changed, and this change adds no changeset'; after: exit 0, '... declares 1 changeset(s): .changeset/6074-check-ts-stale-migration-comment.md. Every one of them has an EMPTY frontmatter'. check-changeset-no-major.mjs -> 'No changeset declares a major bump.' check-changeset-fixed.mjs -> 'All workspace packages are in the changeset fixed group.' check-control-bytes.mjs -> 'OK (scanned 5027 tracked text file(s); skipped 85 binary)' - 5027 versus 5026 before the commit, so the new changeset is inside the scanned set; both touched files also self-scanned clean with grep -naP on the control-byte class. The four node gates plus the presence gate were re-run at the final commit 084de8aad, after it. DECLARED NARROWING: repo-wide `pnpm lint` (turbo run lint, every package) was not run locally - CI runs the farm regardless. It is a measurement, not a skip: eslint.config.js configures no type-aware linting (zero hits for parserOptions / projectService / project:), so a comment-only edit inside one file of one package cannot move any untouched file's verdict, and the package containing that file was linted in full (34 of 34 files). LIMIT, stated because the card asks for it: this change is prose. No gate catches a false comment and none will keep the corrected one true - the gates above only establish that behaviour, output and the skipped-file count did not change.", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
Generated by Claude Code