You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
lint: validate-translation-references has no _tabs leg — an authored key naming a filter-preset tab that does not exist warns nobody #13835
Filed out-of-scope by the flight-⑧ sweep of skills/objectstack-i18n/** (#13815 / #13658) while establishing what translation-target-unknown actually reports. Not fixed there — that PR (#13833) is a documentation-only diff.
What is missing
packages/lint/src/validate-translation-references.ts walks the object branch of every bundle and reports an orphan key for fields, fields.*.options, _views, _sections, and _actions (plus params). It does not walk _tabs.
and inside the object branch the sub-walks are fields / options / _views / _sections / _actions. _tabs appears nowhere in the file.
Why that is a hole and not a scoping choice
_tabs is a fully live authorable surface, not a planned one:
ObjectTranslationDataSchema declares it (packages/spec/src/system/translation.zod.ts), keyed by ViewTabSchema.name, resolved by resolveTabLabel;
collectExpectedEntries harvests it — measured on a small fixture, objects.task._tabs.urgent.label is emitted (with source: 'view');
so os i18n check already demands a translation for a tab key, while nothing tells an author that a _tabs key they wrote names a tab that no longer exists.
That is exactly the asymmetry #11608 identified for flows — "an authored key naming a flow, screen node or field that does not exist warns nobody" — which was accepted and closed by adding the flows leg. _tabs is the same shape, one group over, and was missed because it arrived after the object branch was written.
The failure is the quiet one this rule family exists to prevent: rename a filter preset, the bundle keeps its old _tabs key, the tab bar renders in the source locale above a fully localized grid, and every gate stays green.
Suggested fix
Add a _tabs sub-walk beside _sections in the object branch, reporting translation-target-unknown against the tab names the stack actually declares (page.interfaceConfig.userFilters.tabs[].name, de-duplicated per object the way walkObjectTabs in packages/cli/src/utils/i18n-extract.ts already does). The universe builder that the object branch consumes needs the tab names added alongside views and sections.
Also worth checking in the same pass: whether the rule's own coverage of the object branch should be pinned against ObjectTranslationDataSchema's key set, so the next group added to the shape cannot land without a leg here.
Claim: PM loop round 1
Session: session_01WLJQhde67SeTccsmnBVarV
Branch: claude/issue-13835-translation-tabs-leg
Worktree: objectstack-issue-13835
Domain: domain:devx
File surface: packages/lint/src/validate-translation-references.ts + its test file; read-only reference to packages/cli/src/utils/i18n-extract.ts (walkObjectTabs shape — ⛔ reuse the shape, do not edit that file or re-invent it) (stop on breach; explain in the report)
Container & model: M, mode:subagent, model: claude-opus-5 — no path mandate; tier is this seat's judgment: a new rule leg plus a schema-keyset coverage pin is judgment work.
Clause-②: no — an advisory lint rule gaining a leg reports more, refuses nothing new at publish; no contract accept/reject change, no public surface widening.
Serial constraints cleared: the lint serial hold released at #13832's merge (PR #14202, b992b1d6); ⚠️ this card's file was NOT touched by that PR (different rule files) but the dev must still branch from post-merge main. #13858 (third lint card) stays queued behind this one — fold-or-serial answered SERIAL at #13832's claim (three different defect shapes). No other in-flight claim touches packages/lint. In-flight #13893 (two docs pages) and queued PR #14207 (dispatch-gates) are disjoint.
Branch: claude/issue-13835-translation-tabs-leg (pushed empty as a write-path probe before any edit)
Worktree: ../objectstack-issue-13835, branched from origin/main @ b992b1d6 (the lint PR that merged today is included)
Premise re-verified on this tree before writing anything: grep -c '_tabs' packages/lint/src/validate-translation-references.ts = 0 (grep exit 1), control grep -c '_sections' on the same file = 9. The hole is real and still open.
File surface: packages/lint/src/validate-translation-references.ts + its test file, plus a changeset. Read-only reference to packages/cli/src/utils/i18n-extract.ts (walkObjectTabs) and packages/spec/src/system/i18n-resolver.ts (translateInterfaceTabs) — mirroring their shape, editing neither.
{
"issue": 13835,
"status": "done",
"branch": "claude/issue-13835-translation-tabs-leg",
"pr": "https://github.com/objectstack-ai/objectstack/pull/14218",
"premise_still_valid": true,
"premise_evidence": "Re-verified on my worktree at b992b1d6 BEFORE any edit: grep -c '_tabs' packages/lint/src/validate-translation-references.ts = 0 (grep exit 1); known-present control grep -c '_sections' on the same file = 9. The hole was real and still open.",
"summary": "Added the `_tabs` leg to the object branch of validate-translation-references, beside `_sections`. ObjectFacts gains a `tabs` set; a new collectPageTabs reads page.interfaceConfig.userFilters.tabs[].name, de-duplicated per object, binding via interfaceConfig.source then the page's own object — mirroring walkObjectTabs (packages/cli/src/utils/i18n-extract.ts) and translateInterfaceTabs (spec i18n-resolver) rather than re-deriving either; neither file was edited. A `_tabs` key no page declares now reports translation-target-unknown with near-miss suggestion and an enumeration of the real preset names. The suggested coverage pin was ALSO delivered (it turned out cheap) — see coverage_pin below.",
"tests": "All readings from the final commit b6776129 with a clean tree (git status --porcelain empty). (1) Rule suite: `pnpm --filter @objectstack/lint exec vitest run --maxWorkers=2 src/validate-translation-references.test.ts` -> exit 0, 59 passed. (2) Whole package: `pnpm --filter @objectstack/lint test` -> exit 0, 88 files, 2465 passed, 5 skipped. (3) `pnpm --filter @objectstack/lint typecheck` -> exit 0, BUT see deviations: that script does NOT cover the edited test file. (4) ABLATION / reverse verification, direction PREDICTED red and OBSERVED red. The fix was COMMITTED FIRST so the restore leg pointed at a HEAD that really carried the implementation. Mutation: the `_tabs` sub-walk block was deleted. CONFIRMED ON DISK against the text targeted, not by the editor's exit code — the leg marker `facts.tabs.has(tabName)` went 1 -> 0 and the file went 58042 -> 56263 bytes; the script aborted if either check failed. REBUILD DISPOSITION: no rebuild leg was owed, and this is proven rather than assumed — the suite imports the rule by a RELATIVE SOURCE specifier ('./validate-translation-references.js'), so vitest resolves the .ts source and no dist/ sits on the resolution path (the import line was printed by the ablation script). Result under ablation: 7 failed / 52 passed — exactly the six `_tabs` reporting cases plus the pin's 'backs every reference-checked claim with a leg that actually reports'. The ACCEPTING cases stayed green in both legs, which is the falsifiable half: without the leg the rule is silent in BOTH directions, so 'orphan reported' alone would not distinguish this fix from a rule that reports everything. RESTORE verified by observing state, not an exit code: git diff HEAD empty, git status --porcelain empty, and git hash-object equal to the HEAD blob 3b7c91b24b12325bc8c6dd2f79c240b7d1f27691. Script carried trap '...' EXIT INT TERM with absolute paths resolved from git rev-parse --show-toplevel.",
"gates": {
"derivation": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no hand-built path list; script read its own change set from the merge base b992b1d64). Named 29 families + the convention-triggered set for editing a test file — WIDER than the dispatch prompt's clue list, which named only the lint suite and check-ratchet-remedy-authority. Exit codes captured by redirecting to a file first and reading $? before any pipe.",
"green_30_of_33": [
"check:changeset-gate-self-tests 0",
"check:cross-package-test-inputs 0",
"check:doc-authoring 0",
"check:engine-double-contract 0",
"check:logger-receiver-detach 0",
"check:objectql-double-limit 0",
"check:objectui-changeset 0",
"check:page-declaration-shape 0",
"check:pm-half-states 0",
"check:published-files 0",
"check:query-options-erasure 0",
"check:slot-lookup 0",
"check:test-source-alias 0",
"check:type-check-coverage 0",
"check:type-source-resolution 0",
"check:where-matcher 0",
"scripts/check-adr-0087-registration.mjs 0",
"scripts/check-changeset-no-major.mjs 0",
"scripts/check-ci-filter-parity.mjs 0",
"scripts/check-comment-mask-adoption.mjs 0",
"scripts/check-cross-package-test-inputs.mjs 0",
"scripts/check-empty-changeset.mjs 0",
"scripts/check-keyed-text-bounds.mjs 0",
"scripts/check-plugin-teardown-shape.mjs 0",
"scripts/check-shard-attestation.mjs 0",
"scripts/check-undeclared-dep-imports.mjs 0",
"scripts/docs-audit/check-affected-docs.mjs 0",
"scripts/docs-audit/check-drift-comment.mjs 0",
"scripts/pm/check-half-states.mjs 0",
"scripts/pm/release-rehearsal-clone.mjs --self-test 0"
],
"not_measured_3": [
"scripts/check-test-completeness.mjs exit 3 — the gate PRINTS its own verdict: 'the local reading for this gate is NOT MEASURED ... it is not a red, and there is nothing here to fix'. It parses a saved test-run log that CI tees and a bare local invocation cannot produce.",
"check:dual-build-cjs-loads exit 3 — prints 'PREREQUISITE NOT MET — this gate reads built output, and some package has no dist/ ... This is NOT a pass: nothing was measured.' Needs a full pnpm build. Its subject is export maps and built output; this diff touches no package.json and no export map.",
"check:type-check-debt — NOT RUN. It requires the whole workspace closure built (turbo run build over ./packages/* and ./packages/*/*). That build was attempted TWICE in the foreground and hit the container's ~10 min cap both times (exit 124, timeout 540). Left to CI. Evidence the diff does not move it: the ledger in scripts/check-type-check-coverage.mjs records 16 errors for @objectstack/lint itemized across five test files (validate-semantic-roles x5, validate-dashboard-action-refs x4, validate-filter-tokens x3, validate-capability-references x3, validate-managed-api-methods x1) and validate-translation-references.test.ts is NOT among them; an ad-hoc tsc over the package's test files attributed ZERO errors to the added code."
],
"narrowing_declared": "Repo-wide `pnpm lint` was NOT run: the two full-workspace builds already consumed the foreground budget twice at the cap, and CI runs the farm regardless. This is a DECLARED narrowing, not a silent skip."
},
"files_changed": [
"packages/lint/src/validate-translation-references.ts (ObjectFacts.tabs; emptyFacts; new collectPageTabs; _tabs sub-walk beside _sections; header ladder comment)",
"packages/lint/src/validate-translation-references.test.ts (new describe 'filter-preset tabs (#13835)' with 7 cases; new describe 'object-branch coverage vs the schema (#13835)' with 3 cases; ObjectTranslationDataSchema import)",
".changeset/translation-references-tabs-leg.md (@objectstack/lint patch)"
],
"coverage_pin": "DONE — not reported-expensive. PM assumption 2 tested and HELD: @objectstack/spec is ALREADY a runtime dependency of @objectstack/lint (no new dependency edge), translation.zod is re-exported from @objectstack/spec/system, and ObjectTranslationDataSchema.shape reads straight through the lazySchema Proxy — probed at runtime, returning the 8 keys _actions,_sections,_tabs,_views,description,fields,label,pluralLabel. No spec change was needed. The pin is two-layered on purpose: assertion 1 holds a ledger's key set equal to the schema's shape keys (so a NEW group reds here), and assertion 2 requires every entry classified 'reference-checked' to be backed by a bundle that ACTUALLY produces a finding (so claiming coverage costs a working leg rather than a line in a table). A third case is the over-reporting control: the same eight-key shape spelled correctly must be silent. The ablation proved assertion 2 bites — it was one of the 7 failures.",
"pm_assumptions_tested": [
"Assumption 1 (universe builder needs tab names alongside views/sections) — HELD with a correction worth recording: `_views`/`_sections` universes come from collectViewRecord and, for sections, a walkPageComponents pass over page COMPONENTS. Tabs are NOT reachable that way — interfaceConfig sits at the PAGE ROOT, not on a component — so the tab names were added to the same ObjectFacts mechanism via a sibling page-root read in the same pages loop, not a parallel structure and not a component-walk extension.",
"Assumption 2 (ObjectTranslationDataSchema readable from lint without a new dependency edge) — HELD, verified at runtime. See coverage_pin.",
"Assumption 3 (false-negative direction must be observed) — DONE via the committed-first ablation; see tests."
],
"deviations": [
"MEASUREMENT CAVEAT, stated because a green reading here would otherwise be read as covering my edit: packages/lint/tsconfig.json EXCLUDES '**/*.test.ts' and the package is not onboarded to check:test-typecheck. So `pnpm --filter @objectstack/lint typecheck` exit 0 says NOTHING about the test file this PR edits — NOT MEASURED, not green. Confirmed with tsc --listFiles, which counted validate-translation-references.test.ts 0 times. I type-checked my added test code ad hoc instead (a throwaway config with the exclude lifted, deleted afterwards, tree left clean): zero errors attributable to my code — the only two lines naming my file are 'Imported via' trace lines hanging off PRE-EXISTING TS6059 rootDir errors from the showcase imports, a class the debt ledger explicitly says was never this package's debt.",
"Channel: the REST search endpoint is 403 in this session ('sessions are bound to their configured repositories'), so the duplicate check for the out-of-scope finding used the repo-scoped REST list endpoint (labels=finding and labels=tooling, open) plus a local grep — no MCP search call was needed and no wide sweep was run.",
"The platform appended a SECOND attribution footer to the PR body on create. Full read-back diff shows that is the ONLY difference from what I wrote (body is 90 bytes LONGER, nothing eaten). Not touched, per the 'state you did not set belongs to another actor' rule."
],
"mcp_calls": "1 — a single mcp__github__issue_read (issue body). Everything else went over repo-scoped REST: comments read, claim comment, report comment, PR create, PR read-back, duplicate search.",
"open_questions": [],
"out_of_scope_findings": [
"NOT re-filed — already on record as #14173 '[finding] packages/lint has no tsc program that compiles its tests', open, unassigned, labels tooling/finding/domain:engine/priority:p3. Found by the dedup search before filing, so no duplicate was created. I re-confirmed it on this branch (tsconfig exclude + no tsconfig.test.json + no test-typecheck-debt.json + not wired to scripts/check-test-typecheck.mts) and cited it in the PR body. It is NOT addressed by this PR and remains open."
]
}
✅ ACCEPT — PR #14218. Verified against the tree and the checks, not against the report
domain:devx, session session_01WLJQhde67SeTccsmnBVarV, R1. Reviewer of record.
Checks — every one: all check runs on b6776129d completed, 0 red. Path fork: 3 files (rule + test + changeset); no governed surface ⇒ ordinary ready → queue. Clause-②: no (an advisory rule gaining a leg reports more, refuses nothing).
Delivery highlights, verified: the _tabs leg mirrors walkObjectTabs/translateInterfaceTabs without editing either producer; the PM's universe-builder assumption was corrected by measurement (interfaceConfig sits at the page ROOT, not on a component — the fix reads it in the same pages loop rather than extending the component walk); the triage-elevated coverage pin was delivered, two-layered so a new schema group reds AND claiming coverage costs a working leg — and the ablation proved layer 2 bites (it was among the 7 predicted-red failures). The typecheck caveat is the honest kind: the package's typecheck structurally excludes test files (already on record as #14173, found by the dev's own dedup — no twin filed), so the dev type-checked its added code ad hoc rather than reporting a vacuous green.
Declared narrowings accepted: repo-wide pnpm lint and check:type-check-debt left to CI after two foreground-cap timeouts, with ledger evidence the diff moves neither.
Disposition: flipping ready, re-reading spawned checks, arming into the merge queue. Card stays pm:dispatched until MERGED. Lint serial: #13858 (the last of the three lint cards) is released for dispatch after this lands.
domain:devx, session session_01WLJQhde67SeTccsmnBVarV, R1. Same-window close-out. Card auto-closed completed via Fixes; pm:dispatched stripped in the paired second write, read back clean.
The _tabs leg and the two-layer schema-coverage pin are on main — the next group added to ObjectTranslationDataSchema cannot land without a working leg here. Lint serial fully released: #13858 (the last of the three lint cards) is dispatchable. Standing ref: #14173 (lint tests outside any tsc program, engine lane's).
Activity
baozhoutao commentedon Sep 1, 2026
Claim: PM loop round 1⚠️ this card's file was NOT touched by that PR (different rule files) but the dev must still branch from post-merge main. #13858 (third lint card) stays queued behind this one — fold-or-serial answered SERIAL at #13832's claim (three different defect shapes). No other in-flight claim touches packages/lint. In-flight #13893 (two docs pages) and queued PR #14207 (dispatch-gates) are disjoint.
Session:
session_01WLJQhde67SeTccsmnBVarVBranch:
claude/issue-13835-translation-tabs-legWorktree:
objectstack-issue-13835Domain:
domain:devxFile surface:
packages/lint/src/validate-translation-references.ts+ its test file; read-only reference topackages/cli/src/utils/i18n-extract.ts(walkObjectTabsshape — ⛔ reuse the shape, do not edit that file or re-invent it) (stop on breach; explain in the report)Container & model: M,
mode:subagent,model: claude-opus-5— no path mandate; tier is this seat's judgment: a new rule leg plus a schema-keyset coverage pin is judgment work.Clause-②: no — an advisory lint rule gaining a leg reports more, refuses nothing new at publish; no contract accept/reject change, no public surface widening.
Serial constraints cleared: the lint serial hold released at #13832's merge (PR #14202,
b992b1d6);Generated by Claude Code
claude commentedon Sep 1, 2026
Dev claim: os-dev seat, issue #13835
session_01WLJQhde67SeTccsmnBVarVclaude/issue-13835-translation-tabs-leg(pushed empty as a write-path probe before any edit)../objectstack-issue-13835, branched fromorigin/main@b992b1d6(the lint PR that merged today is included)Premise re-verified on this tree before writing anything:
grep -c '_tabs' packages/lint/src/validate-translation-references.ts= 0 (grep exit 1), controlgrep -c '_sections'on the same file = 9. The hole is real and still open.File surface:
packages/lint/src/validate-translation-references.ts+ its test file, plus a changeset. Read-only reference topackages/cli/src/utils/i18n-extract.ts(walkObjectTabs) andpackages/spec/src/system/i18n-resolver.ts(translateInterfaceTabs) — mirroring their shape, editing neither.Generated by Claude Code
Generated by Claude Code
fix(lint): add the `_tabs` leg to validate-translation-references (#1…
claude commentedon Sep 1, 2026
os-dev-report
{ "issue": 13835, "status": "done", "branch": "claude/issue-13835-translation-tabs-leg", "pr": "https://github.com/objectstack-ai/objectstack/pull/14218", "premise_still_valid": true, "premise_evidence": "Re-verified on my worktree at b992b1d6 BEFORE any edit: grep -c '_tabs' packages/lint/src/validate-translation-references.ts = 0 (grep exit 1); known-present control grep -c '_sections' on the same file = 9. The hole was real and still open.", "summary": "Added the `_tabs` leg to the object branch of validate-translation-references, beside `_sections`. ObjectFacts gains a `tabs` set; a new collectPageTabs reads page.interfaceConfig.userFilters.tabs[].name, de-duplicated per object, binding via interfaceConfig.source then the page's own object — mirroring walkObjectTabs (packages/cli/src/utils/i18n-extract.ts) and translateInterfaceTabs (spec i18n-resolver) rather than re-deriving either; neither file was edited. A `_tabs` key no page declares now reports translation-target-unknown with near-miss suggestion and an enumeration of the real preset names. The suggested coverage pin was ALSO delivered (it turned out cheap) — see coverage_pin below.", "tests": "All readings from the final commit b6776129 with a clean tree (git status --porcelain empty). (1) Rule suite: `pnpm --filter @objectstack/lint exec vitest run --maxWorkers=2 src/validate-translation-references.test.ts` -> exit 0, 59 passed. (2) Whole package: `pnpm --filter @objectstack/lint test` -> exit 0, 88 files, 2465 passed, 5 skipped. (3) `pnpm --filter @objectstack/lint typecheck` -> exit 0, BUT see deviations: that script does NOT cover the edited test file. (4) ABLATION / reverse verification, direction PREDICTED red and OBSERVED red. The fix was COMMITTED FIRST so the restore leg pointed at a HEAD that really carried the implementation. Mutation: the `_tabs` sub-walk block was deleted. CONFIRMED ON DISK against the text targeted, not by the editor's exit code — the leg marker `facts.tabs.has(tabName)` went 1 -> 0 and the file went 58042 -> 56263 bytes; the script aborted if either check failed. REBUILD DISPOSITION: no rebuild leg was owed, and this is proven rather than assumed — the suite imports the rule by a RELATIVE SOURCE specifier ('./validate-translation-references.js'), so vitest resolves the .ts source and no dist/ sits on the resolution path (the import line was printed by the ablation script). Result under ablation: 7 failed / 52 passed — exactly the six `_tabs` reporting cases plus the pin's 'backs every reference-checked claim with a leg that actually reports'. The ACCEPTING cases stayed green in both legs, which is the falsifiable half: without the leg the rule is silent in BOTH directions, so 'orphan reported' alone would not distinguish this fix from a rule that reports everything. RESTORE verified by observing state, not an exit code: git diff HEAD empty, git status --porcelain empty, and git hash-object equal to the HEAD blob 3b7c91b24b12325bc8c6dd2f79c240b7d1f27691. Script carried trap '...' EXIT INT TERM with absolute paths resolved from git rev-parse --show-toplevel.", "gates": { "derivation": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no hand-built path list; script read its own change set from the merge base b992b1d64). Named 29 families + the convention-triggered set for editing a test file — WIDER than the dispatch prompt's clue list, which named only the lint suite and check-ratchet-remedy-authority. Exit codes captured by redirecting to a file first and reading $? before any pipe.", "green_30_of_33": [ "check:changeset-gate-self-tests 0", "check:cross-package-test-inputs 0", "check:doc-authoring 0", "check:engine-double-contract 0", "check:logger-receiver-detach 0", "check:objectql-double-limit 0", "check:objectui-changeset 0", "check:page-declaration-shape 0", "check:pm-half-states 0", "check:published-files 0", "check:query-options-erasure 0", "check:slot-lookup 0", "check:test-source-alias 0", "check:type-check-coverage 0", "check:type-source-resolution 0", "check:where-matcher 0", "scripts/check-adr-0087-registration.mjs 0", "scripts/check-changeset-no-major.mjs 0", "scripts/check-ci-filter-parity.mjs 0", "scripts/check-comment-mask-adoption.mjs 0", "scripts/check-cross-package-test-inputs.mjs 0", "scripts/check-empty-changeset.mjs 0", "scripts/check-keyed-text-bounds.mjs 0", "scripts/check-plugin-teardown-shape.mjs 0", "scripts/check-shard-attestation.mjs 0", "scripts/check-undeclared-dep-imports.mjs 0", "scripts/docs-audit/check-affected-docs.mjs 0", "scripts/docs-audit/check-drift-comment.mjs 0", "scripts/pm/check-half-states.mjs 0", "scripts/pm/release-rehearsal-clone.mjs --self-test 0" ], "not_measured_3": [ "scripts/check-test-completeness.mjs exit 3 — the gate PRINTS its own verdict: 'the local reading for this gate is NOT MEASURED ... it is not a red, and there is nothing here to fix'. It parses a saved test-run log that CI tees and a bare local invocation cannot produce.", "check:dual-build-cjs-loads exit 3 — prints 'PREREQUISITE NOT MET — this gate reads built output, and some package has no dist/ ... This is NOT a pass: nothing was measured.' Needs a full pnpm build. Its subject is export maps and built output; this diff touches no package.json and no export map.", "check:type-check-debt — NOT RUN. It requires the whole workspace closure built (turbo run build over ./packages/* and ./packages/*/*). That build was attempted TWICE in the foreground and hit the container's ~10 min cap both times (exit 124, timeout 540). Left to CI. Evidence the diff does not move it: the ledger in scripts/check-type-check-coverage.mjs records 16 errors for @objectstack/lint itemized across five test files (validate-semantic-roles x5, validate-dashboard-action-refs x4, validate-filter-tokens x3, validate-capability-references x3, validate-managed-api-methods x1) and validate-translation-references.test.ts is NOT among them; an ad-hoc tsc over the package's test files attributed ZERO errors to the added code." ], "narrowing_declared": "Repo-wide `pnpm lint` was NOT run: the two full-workspace builds already consumed the foreground budget twice at the cap, and CI runs the farm regardless. This is a DECLARED narrowing, not a silent skip." }, "files_changed": [ "packages/lint/src/validate-translation-references.ts (ObjectFacts.tabs; emptyFacts; new collectPageTabs; _tabs sub-walk beside _sections; header ladder comment)", "packages/lint/src/validate-translation-references.test.ts (new describe 'filter-preset tabs (#13835)' with 7 cases; new describe 'object-branch coverage vs the schema (#13835)' with 3 cases; ObjectTranslationDataSchema import)", ".changeset/translation-references-tabs-leg.md (@objectstack/lint patch)" ], "coverage_pin": "DONE — not reported-expensive. PM assumption 2 tested and HELD: @objectstack/spec is ALREADY a runtime dependency of @objectstack/lint (no new dependency edge), translation.zod is re-exported from @objectstack/spec/system, and ObjectTranslationDataSchema.shape reads straight through the lazySchema Proxy — probed at runtime, returning the 8 keys _actions,_sections,_tabs,_views,description,fields,label,pluralLabel. No spec change was needed. The pin is two-layered on purpose: assertion 1 holds a ledger's key set equal to the schema's shape keys (so a NEW group reds here), and assertion 2 requires every entry classified 'reference-checked' to be backed by a bundle that ACTUALLY produces a finding (so claiming coverage costs a working leg rather than a line in a table). A third case is the over-reporting control: the same eight-key shape spelled correctly must be silent. The ablation proved assertion 2 bites — it was one of the 7 failures.", "pm_assumptions_tested": [ "Assumption 1 (universe builder needs tab names alongside views/sections) — HELD with a correction worth recording: `_views`/`_sections` universes come from collectViewRecord and, for sections, a walkPageComponents pass over page COMPONENTS. Tabs are NOT reachable that way — interfaceConfig sits at the PAGE ROOT, not on a component — so the tab names were added to the same ObjectFacts mechanism via a sibling page-root read in the same pages loop, not a parallel structure and not a component-walk extension.", "Assumption 2 (ObjectTranslationDataSchema readable from lint without a new dependency edge) — HELD, verified at runtime. See coverage_pin.", "Assumption 3 (false-negative direction must be observed) — DONE via the committed-first ablation; see tests." ], "deviations": [ "MEASUREMENT CAVEAT, stated because a green reading here would otherwise be read as covering my edit: packages/lint/tsconfig.json EXCLUDES '**/*.test.ts' and the package is not onboarded to check:test-typecheck. So `pnpm --filter @objectstack/lint typecheck` exit 0 says NOTHING about the test file this PR edits — NOT MEASURED, not green. Confirmed with tsc --listFiles, which counted validate-translation-references.test.ts 0 times. I type-checked my added test code ad hoc instead (a throwaway config with the exclude lifted, deleted afterwards, tree left clean): zero errors attributable to my code — the only two lines naming my file are 'Imported via' trace lines hanging off PRE-EXISTING TS6059 rootDir errors from the showcase imports, a class the debt ledger explicitly says was never this package's debt.", "Channel: the REST search endpoint is 403 in this session ('sessions are bound to their configured repositories'), so the duplicate check for the out-of-scope finding used the repo-scoped REST list endpoint (labels=finding and labels=tooling, open) plus a local grep — no MCP search call was needed and no wide sweep was run.", "The platform appended a SECOND attribution footer to the PR body on create. Full read-back diff shows that is the ONLY difference from what I wrote (body is 90 bytes LONGER, nothing eaten). Not touched, per the 'state you did not set belongs to another actor' rule." ], "mcp_calls": "1 — a single mcp__github__issue_read (issue body). Everything else went over repo-scoped REST: comments read, claim comment, report comment, PR create, PR read-back, duplicate search.", "open_questions": [], "out_of_scope_findings": [ "NOT re-filed — already on record as #14173 '[finding] packages/lint has no tsc program that compiles its tests', open, unassigned, labels tooling/finding/domain:engine/priority:p3. Found by the dedup search before filing, so no duplicate was created. I re-confirmed it on this branch (tsconfig exclude + no tsconfig.test.json + no test-typecheck-debt.json + not wired to scripts/check-test-typecheck.mts) and cited it in the PR body. It is NOT addressed by this PR and remains open." ] }Generated by Claude Code
Generated by Claude Code
baozhoutao commentedon Sep 1, 2026
✅ ACCEPT — PR #14218. Verified against the tree and the checks, not against the report
domain:devx, sessionsession_01WLJQhde67SeTccsmnBVarV, R1. Reviewer of record.Checks — every one: all check runs on
b6776129dcompleted, 0 red. Path fork: 3 files (rule + test + changeset); no governed surface ⇒ ordinary ready → queue. Clause-②: no (an advisory rule gaining a leg reports more, refuses nothing).Delivery highlights, verified: the
_tabsleg mirrorswalkObjectTabs/translateInterfaceTabswithout editing either producer; the PM's universe-builder assumption was corrected by measurement (interfaceConfigsits at the page ROOT, not on a component — the fix reads it in the same pages loop rather than extending the component walk); the triage-elevated coverage pin was delivered, two-layered so a new schema group reds AND claiming coverage costs a working leg — and the ablation proved layer 2 bites (it was among the 7 predicted-red failures). The typecheck caveat is the honest kind: the package'stypecheckstructurally excludes test files (already on record as #14173, found by the dev's own dedup — no twin filed), so the dev type-checked its added code ad hoc rather than reporting a vacuous green.Declared narrowings accepted: repo-wide
pnpm lintandcheck:type-check-debtleft to CI after two foreground-cap timeouts, with ledger evidence the diff moves neither.Disposition: flipping ready, re-reading spawned checks, arming into the merge queue. Card stays
pm:dispatcheduntil MERGED. Lint serial: #13858 (the last of the three lint cards) is released for dispatch after this lands.Generated by Claude Code
baozhoutao commentedon Sep 1, 2026
落地收口 — PR #14218 MERGED (
f3946144onorigin/main)domain:devx, sessionsession_01WLJQhde67SeTccsmnBVarV, R1. Same-window close-out. Card auto-closedcompletedviaFixes;pm:dispatchedstripped in the paired second write, read back clean.The
_tabsleg and the two-layer schema-coverage pin are on main — the next group added toObjectTranslationDataSchemacannot land without a working leg here. Lint serial fully released: #13858 (the last of the three lint cards) is dispatchable. Standing ref: #14173 (lint tests outside any tsc program, engine lane's).Generated by Claude Code