Repository navigation
objectui check skips 263 real corpus files it should judge — the recall debt #5329 could not repay #6075
Description
Filed by the domain:devx @ objectui execution PM seat (#5748, PM session session_019b5UBNMtTzKbVtZZGvFuxe) as the tracking follow-up promised when #5329 was closed as superseded. Unassigned; grading and domain:* are the triage seat's.
Blocked-by discharged 2026-08-25 — #5392 ruled B (no shipped artifact; recorded there); released to the queue with the safeValidateSchema recogniser route (see the routing comment below).
The debt
objectui check skips files that have a root type and no recognised ObjectUI schema marker. Measured on origin/main @ a1c41c516:
Analyzing 617 files...
Skipped 309 files with a root "type" and no ObjectUI schema marker.
Broken down by an independent harness that reproduced the CLI's own predicate exactly (617 globbed / 475 eligible / 166 judged / 309 skipped):
| bucket | count | verdict |
|---|---|---|
| real corpus files, skipped | 263 | |
| foreign files, skipped | 46 | ✅ correct — 45 package.json with "type":"module", plus one draft-07 document (packages/vscode-extension/schemas/objectui-schema.json) |
The 263 are leaf schemas: real ObjectUI content the checker cannot currently recognise, so nothing validates them.
Why this is not simply "run the migration"
That was #5329, and it is closed as superseded. The route it assumed does not exist:
- the maintainer's 2026-08-20 ruling (verbatim C) superseded the
$schemahalf of the 2026-08-19 ruling; - PR fix(cli):
objectui checkjudges only files that are recognisable as ObjectUI schemas, and reports what it skipped #5334 deletedOBJECTUI_SCHEMA_URLandpointsAtObjectUi()before merge; - there is deliberately no
$schemaarm in the merged checker and no ObjectUI$schemaURL exists to declare.
Proved empirically rather than by reading, with a positive control that makes the flat reading a measurement rather than a probe that missed:
| leg | injected into a currently-skipped real file | D-arm skipped |
|---|---|---|
| A | a $schema marker |
309 — unmoved |
| B (control) | "className": "" (a structural key) |
308 — moved by exactly 1 |
A corpus-wide $schema sweep is a measured no-op. Stamping it anyway would make the corpus look migrated while recall stayed at zero.
Why it is blocked rather than queued
#5334 names @object-ui/types shipping a generated JSON Schema as the soundest trigger for adding a $schema arm later — and that decision is #5392, already in the queue. Two things follow:
- Minting a permanent public identifier before the document it names exists is backwards.
- Because matching would be host-based, the arm can be added after [Decision] Should
@object-ui/typesship a generated JSON Schema? — the contract an AI author can read before writing #5392 lands without invalidating a single file. So waiting costs nothing and forecloses nothing — which is exactly the interim the ruling permits.
Routes, for whoever picks this up after #5392
- Add the
$schemaarm once a real generated schema document exists to point at. The corpus sweep becomes meaningful at that moment and not before. - Widen
OBJECTUI_STRUCTURAL_KEYSto admit leaf vocabulary (fields,label,variant,onClick), recognising leaf schemas with no corpus edit at all.⚠️ This needs per-key foreign-retention measurement first: fix(cli):objectui checkjudges only files that are recognisable as ObjectUI schemas, and reports what it skipped #5334 measuredlabelas held out by name precisely because admittingBaseSchema-adjacent naming keys drives foreign retention from 0 files toward all 46. A key that recovers leaf schemas but starts judgingpackage.jsonis a net loss. - ⛔ Not injecting structural keys into the corpus to move the count. It fabricates presentational content to satisfy a heuristic and changes rendered output; Migrate the in-repo schema corpus (~424 files) to carry the canonical
$schemamarker — the producer-side half of #5127's Option B #5329's dispatch prohibited it explicitly and its dev correctly refused.
Two claims from #5329's body that did not survive measurement
Recorded so they are not inherited:
- The corpus figure moves. Migrate the in-repo schema corpus (~424 files) to carry the canonical
$schemamarker — the producer-side half of #5127's Option B #5329's stamped table said ~424 real / 258 skipped / 304 D-arm; measured five days later it is 429 / 263 / 309. The surface grew, against an unlock comment predicting it "may be materially smaller". Re-measure; do not adopt any number here either. - The claimed editor-validation side benefit does not exist. 0 of 429 in-repo files declare an ObjectUI
$schema, and the VS Code extension binds by filename glob (contributes.jsonValidation.fileMatchon*.objectui.json/*.oui.json), not by$schema— with 0 of 429 corpus files matching either glob, and no$idin the bundled schema.
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, ablation and four-option analysis - fix(cli):
objectui checkjudges only files that are recognisable as ObjectUI schemas, and reports what it skipped #5334 /objectui check把每个 JSON 文件的根type都当成组件键判定,于是在任何 Node 工程里都对 package.json 的"type": "module"报未知类型 #5127 — the merged checker and the Option B this descends from check.tspromises that "the corpus migration repays" the 263-file recall debt — the mechanism was deleted before #5334 merged #6074 — the falsecheck.tscomment promising this debt is repaid by a migration; actionable now, independent of this card- [Decision] Should
@object-ui/typesship a generated JSON Schema? — the contract an AI author can read before writing #5392 — the blocker
Activity
os-warren commentedon Aug 25, 2026
Claim: PM loop round 30⚠️ If your implementation ends up altering
Session:
session_012CZgmFFzqA9cX8tBMhvpFeBranch:
claude/issue-6075-check-recogniser-recallWorktree:
objectui-issue-6075Domain:
domain:devx(@ objectui, seat #5748)File surface:
packages/cli/src/commands/check.tsand its tests; read-only use ofsafeValidateSchemafrom@object-ui/types/zodContainer & model: M leaning L,
mode:subagent,model: opusClause-②: no — this changes which files
objectui checkjudges, not what the schema contract accepts or rejects.packages/typesvalidation behaviour or widening a public export, stop: that is a different card and a different tier.Serial constraints cleared: in flight 0 at round open. Co-dispatched this batch: #5306 (root
package.json,CONTRIBUTING.md) and #6245 (scripts/check-eager-closure-budget.mjs) — both disjoint. #6074, the adjacentcheck.tscomment card, is closed and merged (PR #6079), so its corrected comment is now part of your base, not a conflict — but it does describe this debt, so keep it true.Zone 1 — Rulings (not re-litigable)
Two maintainer rulings govern this card.
$schemahalf of the 2026-08-19 ruling. PR fix(cli):objectui checkjudges only files that are recognisable as ObjectUI schemas, and reports what it skipped #5334 deletedOBJECTUI_SCHEMA_URLandpointsAtObjectUi()before merge. There is deliberately no$schemaarm and no ObjectUI$schemaURL exists to declare.@object-ui/typesship a generated JSON Schema? — the contract an AI author can read before writing #5392 — Option B, no shipped artifact. Maintainer accepted the batch recommendation verbatim: 「同意你的建议」. That discharged this card's blocker, and the routing comment of 10:13Z records the ruled route:⛔ Therefore: do not add a
$schemaarm, do not mint a URL, do not stamp markers into the corpus (that prohibition is what #5329 died on), and do not widenOBJECTUI_STRUCTURAL_KEYS— #5334 measuredlabelas held out by name because admittingBaseSchema-adjacent naming keys drives foreign retention from 0 files toward all 46. A key that recovers leaf schemas but starts judgingpackage.jsonis a net loss.The design question this card owns — answer it explicitly
Carried from the routing comment, and it is the part that needs your judgement rather than transcription:
⭐ This is the load-bearing part of the change. A recogniser that says "not ObjectUI" about a genuinely broken ObjectUI file makes the checker quietly less able to find the thing it exists to find, and the symptom is an absence — the file simply stops being mentioned. Decide how that bucket surfaces, implement it, and state the decision and its cost in your PR body. Measure the bucket's size rather than assuming it is empty.
Zone 2 — PM mechanism readings (verify; some will have moved)
Read on
origin/main@090927f4fat 11:55Z:safeValidateSchemais exported from@object-ui/types/zodand already consumed bypackages/cli/src/commands/validate.ts:13and:58. Soobjectui checkandobjectui validatewould share one recogniser — worth saying in the PR whether that coupling is intended, because it makescheck's recall move whenever validation tightens.OBJECTUI_STRUCTURAL_KEYSlives atpackages/cli/src/commands/check.ts:35, is used at:128, and is printed to the user at:255. If your change alters what gets judged, that user-facing sentence at:255is part of the change — an explanation that no longer describes the predicate is the same defect class as the commentcheck.tspromises that "the corpus migration repays" the 263-file recall debt — the mechanism was deleted before #5334 merged #6074 just fixed.$schemamarker — the producer-side half of #5127's Option B #5329, or from this order.@object-ui/typesship a generated JSON Schema? — the contract an AI author can read before writing #5392 / PR docs(audits): measure zod to JSON Schema conversion fidelity for@object-ui/types#6203. Re-derive it against your base rather than quoting it — ifsafeValidateSchemaadmits materially fewer than the ruling expects, that is a finding worth stopping on, not a number to quietly ship past.Zone 3 — Suggested route (optional; measurement wins)
Replace the marker predicate's negative arm with a validity probe, keep the structural-key arm as the fast path, and give the skip report three buckets instead of two: judged, foreign (refused by the recogniser and structurally implausible), and candidate ObjectUI content that failed validation — the last one reported rather than swallowed. ⛔ My guess at the shape, not a constraint; if the honest design is two buckets plus a diagnostic, take that and say why.
Keep the printed count honest either way. The card is explicit: the debt's visibility in the printed count is the point — ⛔ do not silence it, and do not let the number fall because files moved into an unreported bucket.
Gates
Derive from your diff. A recall change needs a test that pins the new behaviour on real corpus shapes — including at least one genuinely invalid ObjectUI file, so the bucket decision above is pinned and not just described.
packages/cliis a released package, so followcheck-changeset-presence.mjs's verdict. Capture exit codes by redirect before any pipe; quote each gate's own verdict line, not its exit code.⛔ Do not edit
content/docs/releases/.Standing
Worktree-first before your first edit. Post your own claim comment here with your own session ID and branch — this one identifies the PM session, not you. Lead your report with the literal text
os-dev-report, write angle-bracket fragments in words, and read it back after posting.Expected outcome:
donewith a draft PR carryingFixes #6075.premise_still_valid: falsewith no PR is a legitimate delivery if the debt has already been repaid by something merged since 10:13Z.Generated by Claude Code
os-warren commentedon Aug 25, 2026
Dev claim (os-dev, dispatched by the PM comment above).
Session:
session_012CZgmFFzqA9cX8tBMhvpFe— note: I run as themode:subagentdev inside the dispatching PM session, so the container session ID is the same string the PM comment carries. It identifies the container, not a separate seat; this comment is the dev-side claim on top of it.Branch:
claude/issue-6075-check-recogniser-recall(pushed empty at claim time as the write-route probe — push succeeded)Worktree:
objectui-issue-6075Base:
origin/main@090927f4fRoute taken as ruled:
safeValidateSchemaas the recogniser. No$schemaarm, no minted URL, no corpus marker stamping, no widening ofOBJECTUI_STRUCTURAL_KEYS.Owned design question: how the failed-validation bucket is reported. Will measure its size on my own base and state the decision plus its cost in the PR body.
Generated by Claude Code
Generated by Claude Code
os-warren commentedon Aug 25, 2026
os-dev-report
{ "issue": 6075, "status": "done", "branch": "claude/issue-6075-check-recogniser-recall", "pr": "https://github.com/objectstack-ai/objectui/pull/6322", "premise_still_valid": true, "summary": "Added safeValidateSchema as the second recogniser arm in packages/cli/src/commands/check.ts, behind the existing structural-key fast path, per the ruled route. Re-measured on my own base (origin/main @ 090927f4f, clean checkout): 617 globbed / 475 eligible / 166 judged / 309 skipped before; 375 judged (166 structural + 209 validity) / 54 reported / 46 skipped after, and the three close over 475. The design question this card owns is answered with three buckets, not two: a refused file whose root type names a registered component is listed BY NAME as ObjectUI content that did not validate, never folded into the skip count. That bucket was measured, not assumed - 54 files, 53 of them real corpus content such as the schema-catalog leaf with variant 'small' that is not in TextSchema's enum, so a two-bucket recogniser would have filed 53 real broken schemas as foreign. Its cost is stated and pinned as a test: one foreign draft-07 JSON Schema document whose root type is 'object' collides with a registered key and lands in the report. OBJECTUI_STRUCTURAL_KEYS is unchanged, no dollar-schema arm, no minted URL, no corpus marker stamped, packages/types untouched and no export widened. The user-facing sentence formerly at check.ts:255 now names both arms, and content/docs/utilities/cli.mdx (which claimed check validates every schema file) now describes the real predicate. NOTE ON THE CARD BODY: no sanitizer truncation found in the issue body or in either comment - all three read complete, ending on the Related list, the routing note and the dispatch footer respectively. Sanitizer damage DID hit my own writes: the PR body lost every angle-bracket fragment including inside code fences (objectui validate FILE now spelled in words), and issue 6318 lost a z.literal placeholder the same way. Both were caught on read-back and corrected, with an editor's note left in each.", "tests": "All run in the dedicated worktree, heavy legs serialised through scripts/pm/os-verify-lock.sh, exit codes captured by redirect BEFORE any pipe, and the union re-run at the FINAL commit 1c2ade6a8. vitest run packages/cli/ verdict: 'Test Files 13 passed (13)' / 'Tests 226 passed (226)'. pnpm --filter @object-ui/cli run type-check verdict: echoed '@object-ui/cli@17.6.0 type-check' then 'tsc --noEmit', exit 0; tsc --listFiles confirms check.ts and BOTH test files are in that program, so 'typecheck clean' is a statement about the files I edited. pnpm lint over the whole repo (NOT narrowed) verdict: 'Tasks: 47 successful, 47 total', 0 errors, 2m55s under the lock. check-changeset-presence.mjs verdict: 'OK 3 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'. check-control-bytes.mjs verdict: 'OK check-control-bytes: OK (scanned 5197 tracked text file(s); skipped 85 binary)'. check-lint-coverage.mjs verdict: 'lint coverage: 46/46 packages linted, 0 with outstanding errors'. check-type-check-coverage.mjs verdict: 'test type-check coverage: 41/41 packages compile their tests'. check-doc-snippet-types.mjs verdict: 'Semantic phase: 267 of 267 block(s) judged, 0 failed.'. check-doc-links.mjs verdict: 'Links are valid across 17 scan roots.'. check-phantom-dependencies.mjs verdict: 'Every in-scope import is declared by the package that publishes it.'. Also exit 0: check-vi-mock-specifiers, check-doc-fence-languages, check-doc-component-types, check-package-self-import, check-published-dist-tooling, check-node-esm-load, check-changeset-no-major, check-changeset-fixed, check-shell-escape-residue, check-skills-paths, lint:root. ABLATION (predicted direction: red): collapsed the third bucket back to two by making isUnvalidatedCandidate return false, so every refused file becomes skipped - the exact failure mode the card names. Mutation proved ON DISK before reading any result, not from an editor exit code: injected-marker grep -c = 1, original return still present, and git hash-object moved 95832826 became 3929785e. NO REBUILD is involved on either leg and none is claimed: the suites import '../commands/check.js', a relative specifier vitest resolves to source, so no dist/ can go stale under them (unlike a cross-package ablation). Result: 8 tests failed, covering every test in 'a broken ObjectUI schema is never filed as a foreign file' plus the absence-detector. Restore ran via trap on EXIT INT TERM against an ABSOLUTE path and was proved afterwards rather than assumed: git diff HEAD empty, marker residue 0, hash back to 95832826, git status clean. One toolchain trap hit and recorded: pnpm --filter cli exec vitest is blocked by this repo's own guard (objectui#3378, vitest root would silently run another package's 22 files and report green); re-ran from the repo root as the guard instructs.", "open_questions": [], "out_of_scope_findings": [ "filed as #6318: 53 in-repo schema files carry a registered ObjectUI type but fail safeValidateSchema - 49 violate a schema the Zod union models (e.g. TextSchema.variant enum), 4 carry a registered type (code-editor, bar-chart) with no Zod schema at all; also records the 36 already-judged files that fail validation and that Zod 4 collapses every failure to invalid_union at the root", "filed as #6320: objectui check scans build output - its ignore list ['node_modules/**','dist/**','.git/**'] is matched relative to cwd, so only a TOP-LEVEL dist/ is excluded. Measured on the same tree: 617 files globbed on a clean checkout vs 1047 after a full build, with every printed count roughly doubling. Pre-existing on main; it is also why every count in this report states 'clean checkout'" ] }Generated by Claude Code
os-warren commentedon Aug 25, 2026
ACCEPT — PR #6322
Reviewed by the
domain:devx@ objectui execution seat (#5748), PM sessionsession_012CZgmFFzqA9cX8tBMhvpFe, R30. Read against the diff on GitHub, ⛔ not against the report's summary.Checklist
main✅check.ts(+135/−32), a new 280-line test file, the existing marker suite,content/docs/utilities/cli.mdx, a changesetsafeValidateSchemaas the second arm, structural arm first ✅OBJECTUI_STRUCTURAL_KEYSunchanged ✅ · no$schemaarm ✅ · no URL minted ✅ · no corpus marker stamped ✅ ·packages/typesuntouched, no export widened ✅@object-ui/climinor), and the gate's verdict was that one is owed here — matching, unlike the other two PRs this roundBundle Analysis✅ among 27 checks; zero failures, several still running at review timeThe design question this card owns — answered, and the answer is measured
The card required a decision on the failed-validation bucket, and warned that silently reclassifying broken ObjectUI content as foreign is the failure to avoid. The answer shipped is three buckets, and the accounting closes on my own arithmetic: 375 judged (166 structural + 209 validity) + 54 reported + 46 skipped = 475 eligible, against 166/309 before.
⭐ The bucket was measured rather than assumed to be small: 54 files, 53 of them real corpus content. A two-bucket recogniser would have filed 53 genuinely broken schemas as "not ObjectUI" — so the hazard the card named was not hypothetical, it was 53 files wide.
The discriminator is
isKnownSchemaType— the same derived registered-type universe the judgement arm already uses, so it adds no second hand-maintained list. That is the right choice: a filename skip list is what #5127 existed to delete.Its cost is declared and pinned rather than hidden: a foreign document whose root
typecollides with a registered component key (a draft-07 JSON Schema with"type": "object") lands in the report as one advisory line. There is a test asserting exactly that, with a comment explaining why the opposite error is the worse one. A cost with a test on it is a known cost.The tests are where this PR earns its acceptance
Half the new suite is negative — written to fail if a future simplification collapses the third bucket back into two. The one I would single out:
That is an absence-detector: it fails when the command goes quiet, which is the only symptom this defect class has. A suite that merely proved the newly-recognised files are judged would have passed the very regression the card was filed about. The ablation confirms it bites — collapsing
isUnvalidatedCandidatetofalsereds 8 tests, with the mutation proven on disk by blob hash before any result was read.The honest-limit test is the other one worth naming: an unregistered root
type, no structural key, and a document that does not validate is byte-for-byte the evidence a foreign file offers, so it stays in the skip count. Pinning that as a deliberate limit rather than leaving it as an unexplained residue is the right instinct.Two things I checked because they would have been easy to get wrong
check.ts:255's sentence named one arm; it now names both, with a test asserting two advisory lines and asserting the absence of any$schemaorhttpstring. That closes the same defect classcheck.tspromises that "the corpus migration repays" the 263-file recall debt — the mechanism was deleted before #5334 merged #6074 had just removed from this file — an explanation that stopped describing the code.check's recall is now tied to@object-ui/types' Zod schemas, so tightening a schema moves files out of recognition. That is survivable precisely because of the third bucket — a file that stops validating stops being judged but does not stop being mentioned. Worth remembering the next time someone tightens a schema and the numbers move.Clause-② stays
no: this changes which filescheckjudges, not what the contract accepts or rejects, andpackages/typesis untouched.Out-of-scope findings — verified, and labelled
#6318 (53 files carrying a registered type that fail validation, with the Zod-4
invalid_unioncollapse noted) and #6320 (objectui checkscans build output — thedist/**ignore is matched relative to cwd, so only a top-leveldist/is excluded: 617 files on a clean checkout vs 1047 after a full build) both exist and are well-formed. Both were filed unlabelled; I addedfindingto each.findinglabel is still what the protocol asks a dev to apply, and it marks the card as awaiting first grading, which is why I added it. But "invisible" was wrong.⭐ #6320 also explains why every count in this report is qualified "clean checkout", and it means the numbers on this card are checkout-state dependent — worth knowing before anyone re-measures and gets roughly double.
Landing
Arming on every-check-green — ⛔ not the required subset — then following to MERGED.
Generated by Claude Code