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
New measured evidence for this finding, merged in from #1083 (filed today by me without a dedup search — my error; #1083 is closed as a duplicate of this card).
#1060 / PR #1080 produced a concrete, dated instance of exactly what this card describes, on the i18n rule family:
objectstack lint exit code is 0 both with and without --skip-i18n — measured directly, it does not fail the process on warnings alone.
PR chore(lint): drop --skip-i18n from lint script; fill es-ES/zh-CN page-component i18n keys #1080 merged (2026-08-11) carrying 25 known, enumerated i18n/missing-page warnings (the ja-JP third, deliberately held back for a concurrent claim), and the Quality Checks job was green. That is the failure mode of this card as a merged artifact rather than an argument: a branch with named, counted debt passed the gate.
Two knock-on effects worth recording here, since this card is the root:
Acceptance criteria in this repo have to be stated as rule-hit counts, not exit codes.fix(i18n): fill 25 missing ja-JP page-component translation keys #1084 closed the debt and reported it correctly as i18n/missing-page 25 → 0 rather than "lint exits 0", precisely because the exit code proves nothing. Any future card whose acceptance is "lint passes" is under-specified while this finding stands.
The options for fixing are split by repo: making the rule error-severity is a platform-side change in packages/lint (upstream), while a CI step asserting a zero count is app-side and can be done here. Only the latter is in this repo's power.
No new card needed — this one already covers it, and now has a current instance attached.
PM triage sweep, 2026-08-11 — using this card as the anchor for a cluster, and promoting it to pm:queue.
A findings sweep over all 34 open finding cards shows they are not 34 independent observations. Eight of them say the same structural thing: a gate in this repo has a blind spot. Listing them together because the cluster is the finding, and each one read alone understates it:
Nothing checks that status names / field labels in the docs match the locale packs — the same defect class surfaced three times in one week, all caught by eye
The CI step name for the source-hygiene gate lists three of its four checks
Why this cluster deserves attention ahead of its individual members' severities. Today's work produced a card that states the pattern outright — #1091: nine object files carry an unused import, and typecheck, lint and hygiene are all green on it. Several of today's defects were caught by a person or an agent reading carefully, not by a gate:
An unguarded class does not stay one instance. That is the argument for treating these eight as one body of work rather than eight separately-scheduled small cards.
This card promoted to pm:queue as the cluster's first and cheapest member: the app-side half is a CI step asserting a zero rule-hit count, which is small, and it is the gate that would have caught #1060's 25 warnings. Note the split the card already records — making the rule error-severity is an upstream packages/lint change; only the count assertion is in this repo's power.
⛔ Not merging the other seven into this card. Each has its own file surface and its own measurement; folding them in would make an epic that never closes. They stay separate, now cross-referenced.
Sweep scope, stated honestly: this pass read the 34 cards' titles and labels, not their bodies. Premise-staleness — which of these were silently fixed by today's seven merged PRs — has not been checked, and remains the outstanding half of the triage round.
⚠️Correction to my triage-sweep comment above — one of its three pieces of evidence was wrong.
That comment cited #1091 as proof that this repo's gates have blind spots:
Today's work produced a card that states the pattern outright — #1091: nine object files carry an unused import, and typecheck, lint and hygiene are all green on it.
#1091's premise has since been falsified (see PR #1095 and the dev report on that card). F and P are @objectstack/spec's tagged-template aliases, invoked as F`...` / P`...` and never with a dot. All nine files use them productively. The card's own reproduce command, grep -cE '\b[FP]\.', matches dot-notation only and so returns 0 regardless of real usage — the zero was the instrument's blind spot, not the code's.
So the gates were not blind to an unused import; there was no unused import. Strike that evidence line.
What the cluster's argument rests on now — and it still stands, on two measured instances rather than three:
The other seven cards in the table are unaffected — each was measured on its own terms, and none of them depended on #1091.
The methodological point is worth keeping even though the instance evaporated, because it now cuts the other way too: #1091 was a finding whose measurement could not fail, and it survived in the backlog looking rigorous. That is an argument for the premise-recheck half of the triage round — the half that has not been done — rather than against the cluster.
Session: session_01NM6o28jmBgsyTRQHutn7LC
Branch: claude/issue-1018-i18n-gate
Worktree: hotcrm-issue-1018
File surface: .github/workflows/**, package.json scripts, scripts/** if the assertion needs a helper, and test/. ⛔ Notsrc/translations/** — #597 is in flight on those. Stop on breach; explain in the report.
Container & model: S–M, model: sonnet, mode:subagent.
Serial constraints cleared: nothing else touches CI config; #597 (concurrent) is confined to src/, seeds and the locale packs.
⚠️Read the correction comment on this card before designing. My cluster analysis above originally cited #1091 as evidence that the gates are blind; that evidence was falsified and I struck it. The argument still stands on #1060 (25 enumerated warnings merged green — this card's exact failure mode as a merged artifact), but the second supporting instance (#1093) carries its own "not reproduced end-to-end" caveat. ⛔ Do not repeat the original three-instance framing anywhere.
Scope is the app-side half only: a CI assertion that the rule-hit count is zero. Making the rule error-severity is an upstream packages/lint change and is not in this repo's power.
{
"issue": 1018,
"status": "done",
"branch": "claude/issue-1018-i18n-gate",
"pr": "https://github.com/objectstack-ai/hotcrm/pull/1098",
"premise_still_valid": true,
"summary": "Confirmed the premise by reading @objectstack/cli's lint.js directly and running it: `objectstack lint` exits 0 whenever errors.length===0 regardless of warning/suggestion count (153 warnings, 10 suggestions today, exit 0). Added scripts/check-lint-i18n-gate.mjs, which runs `objectstack lint --json`, counts issues whose rule starts with `i18n/missing-`, and fails when that count is not zero; wired it into `pnpm verify` and both CI workflows (ci.yml, code-quality.yml) as a dedicated step right after the existing lint step. Today's real i18n/missing-* count is 0, matching the PM's assumption. Reverse verification: manufactured a violation (deleted one ja-JP view label) inside a disposable, fully-isolated copy of the worktree under /tmp (never touching the real src/translations/**, which #597 is concurrently editing) and confirmed objectstack lint itself still exited 0 while the new gate exited 1 reporting i18n/missing-view; the disposable copy was then deleted and the real worktree verified byte-identical to origin/main on src/translations/.",
"tests": "pnpm exec vitest run test/lint-i18n-gate.test.ts (under flock /tmp/os-heavy-verify.lock): 6 passed (6), including a real end-to-end run of the gate against current metadata asserting 0 i18n/missing-* issues. pnpm run lint: exit 0, 153 warning(s), 10 suggestion(s) (unchanged baseline). pnpm run lint:i18n-gate: 'i18n lint gate: 0 i18n/missing-* issues (163 total lint issue(s) reported)', exit 0. pnpm run typecheck (tsc --noEmit): no output, exit 0. pnpm run hygiene: 'source hygiene clean'. Self-scan for control bytes on all changed/new files: no matches. On the draft PR's first CI round (single read, not idle-polled): 'Quality Checks' completed conclusion=success, 'Check Changeset' completed conclusion=success; 'Build and Test (22.x)' was still in_progress at read time.",
"open_questions": [],
"out_of_scope_findings": []
}
ACCEPT — PR #1098. All 9 check runs completed: success, and the new step ran inside this PR's own CI (Build and Test + Quality Checks both green), so the wiring is proven rather than asserted.
The premise was confirmed at the source, not inferred from behaviour: @objectstack/cli's lint.js exits 0 whenever errors.length === 0, regardless of warning count. Non-default-locale gaps are warnings, so pnpm verify's lint step could never go red on one. That is this card, measured.
The mandated reverse verification was done, and done in the only safe way available. I required proof the gate can fail, and forbade touching src/translations/** because #597 is editing those files right now. The dev built a disposable isolated copy of the worktree under /tmp, deleted one ja-JP view label there, and showed objectstack lintstill exiting 0 while the gate exited 1 reporting i18n/missing-view — then deleted the copy and verified the real worktree byte-identical to origin/main on src/translations/. Both constraints satisfied at once, with the transcript in the PR body.
Five things in the test file that make this a gate rather than a decoration:
A violation fixture asserts the unrelated warning is not swept in — scope control, proven.
i18n/coverage-below-threshold is asserted not gated: the prefix is i18n/missing-, and over-matching would quietly widen the gate beyond what was ruled.
A default-locale error counts the same as a warning, so severity plumbing can't undercount.
A real, fixture-free run against current metadata — the same command CI runs — so pnpm test catches a regression too, not only the dedicated step.
⭐ A malformed report (no issues array) exits 1 with a clear message. This is the one I would have missed. If the CLI's --json shape ever changes, the gate fails loudly instead of finding zero violations in a structure it no longer understands. A gate that silently passes when its input shape drifts is precisely the failure mode that made Nine object files import F, P from @objectstack/spec and never use them — three of them above the license header #1091 look rigorous for a week.
Scope held. Only the i18n/missing-* family gates; the other ~153 pre-existing warnings are untouched and explicitly documented as out of gate, with a note that widening the script is a separate deliberate change. The upstream half — making the lint rule itself error-severity in packages/lint — is correctly named as out of this repo's reach rather than attempted.
The --fixture seam is documented with its reason (a real gap cannot be manufactured from a test without either editing real translation files or carrying a disposable project copy), and the un-automated reverse verification is disclosed in the test header rather than implied to be covered. That is the honest shape of this trade.
Cluster note: this closes the first and cheapest member of the eight-card gate-blind-spot cluster mapped above. The remaining seven (#838, #809, #802, #1003, #867, #935, #753) stay separate and are unaffected by the #1091 correction.
Activity
huangyiirene commentedon Aug 11, 2026
New measured evidence for this finding, merged in from #1083 (filed today by me without a dedup search — my error; #1083 is closed as a duplicate of this card).
#1060 / PR #1080 produced a concrete, dated instance of exactly what this card describes, on the i18n rule family:
objectstack lintexit code is 0 both with and without--skip-i18n— measured directly, it does not fail the process on warnings alone.i18n/missing-pagewarnings (the ja-JP third, deliberately held back for a concurrent claim), and theQuality Checksjob was green. That is the failure mode of this card as a merged artifact rather than an argument: a branch with named, counted debt passed the gate.Two knock-on effects worth recording here, since this card is the root:
i18n/missing-page25 → 0 rather than "lint exits 0", precisely because the exit code proves nothing. Any future card whose acceptance is "lint passes" is under-specified while this finding stands.packages/lint(upstream), while a CI step asserting a zero count is app-side and can be done here. Only the latter is in this repo's power.No new card needed — this one already covers it, and now has a current instance attached.
Refs #1060 · PR #1080 · PR #1084 · #494
Generated by Claude Code
objectstack lintdoes not fail on i18n warnings, so dropping --skip-i18n makes translation debt visible but still unenforced #1083 as a duplicate of this issuehuangyiirene commentedon Aug 11, 2026
PM triage sweep, 2026-08-11 — using this card as the anchor for a cluster, and promoting it to
pm:queue.A findings sweep over all 34 open
findingcards shows they are not 34 independent observations. Eight of them say the same structural thing: a gate in this repo has a blind spot. Listing them together because the cluster is the finding, and each one read alone understates it:objectstack lintwarnings never fail the process — warning-class defects can never go red inpnpm verifydocs/,.github/,.claude/or the root first-class files (including three root.tsconfigs)content/docs; user-visible strings insrc/(title/label/description/help) are uncheckeddocs-drift'sheadingLabel()rejects explicit fumadocs heading ids, so the dashboards page can never carry[#id]Why this cluster deserves attention ahead of its individual members' severities. Today's work produced a card that states the pattern outright — #1091: nine object files carry an unused import, and
typecheck,lintandhygieneare all green on it. Several of today's defects were caught by a person or an agent reading carefully, not by a gate:i18n/missing-pagewarnings through a greenQuality Checks— this card's exact failure mode, as a merged artifact.period_endwalks around #1008's calendar-boundary fix — a row labelledQ3 2026can still span ten months #1093 (filed today) reports that a hand-typedperiod_endwalks around a boundary rule that shipped this morning.An unguarded class does not stay one instance. That is the argument for treating these eight as one body of work rather than eight separately-scheduled small cards.
This card promoted to
pm:queueas the cluster's first and cheapest member: the app-side half is a CI step asserting a zero rule-hit count, which is small, and it is the gate that would have caught #1060's 25 warnings. Note the split the card already records — making the rule error-severity is an upstreampackages/lintchange; only the count assertion is in this repo's power.⛔ Not merging the other seven into this card. Each has its own file surface and its own measurement; folding them in would make an epic that never closes. They stay separate, now cross-referenced.
Sweep scope, stated honestly: this pass read the 34 cards' titles and labels, not their bodies. Premise-staleness — which of these were silently fixed by today's seven merged PRs — has not been checked, and remains the outstanding half of the triage round.
Refs #1091 · #1060 · #1093 · #494
Generated by Claude Code
huangyiirene commentedon Aug 11, 2026
That comment cited #1091 as proof that this repo's gates have blind spots:
#1091's premise has since been falsified (see PR #1095 and the dev report on that card).
FandPare@objectstack/spec's tagged-template aliases, invoked asF`...`/P`...`and never with a dot. All nine files use them productively. The card's own reproduce command,grep -cE '\b[FP]\.', matches dot-notation only and so returns0regardless of real usage — the zero was the instrument's blind spot, not the code's.So the gates were not blind to an unused import; there was no unused import. Strike that evidence line.
What the cluster's argument rests on now — and it still stands, on two measured instances rather than three:
i18n/missing-pagewarnings through a greenQuality Checks. Unchanged, and it is this card's exact failure mode as a merged artifact. This is the strongest instance and it is directly about this card.period_endwalks around #1008's calendar-boundary fix — a row labelledQ3 2026can still span ten months #1093 — a hand-typedperiod_endwalks around a boundary rule that shipped the same morning.The other seven cards in the table are unaffected — each was measured on its own terms, and none of them depended on #1091.
The methodological point is worth keeping even though the instance evaporated, because it now cuts the other way too: #1091 was a finding whose measurement could not fail, and it survived in the backlog looking rigorous. That is an argument for the premise-recheck half of the triage round — the half that has not been done — rather than against the cluster.
Generated by Claude Code
huangyiirene commentedon Aug 11, 2026
Claim: PM loop round 10
Session:
session_01NM6o28jmBgsyTRQHutn7LCBranch:
claude/issue-1018-i18n-gateWorktree:
hotcrm-issue-1018File surface:
.github/workflows/**,package.jsonscripts,scripts/**if the assertion needs a helper, andtest/. ⛔ Notsrc/translations/**— #597 is in flight on those. Stop on breach; explain in the report.Container & model: S–M,
model: sonnet,mode:subagent.Serial constraints cleared: nothing else touches CI config; #597 (concurrent) is confined to
src/, seeds and the locale packs.Scope is the app-side half only: a CI assertion that the rule-hit count is zero. Making the rule error-severity is an upstream
packages/lintchange and is not in this repo's power.Generated by Claude Code
huangyiirene commentedon Aug 11, 2026
os-dev-report
{ "issue": 1018, "status": "done", "branch": "claude/issue-1018-i18n-gate", "pr": "https://github.com/objectstack-ai/hotcrm/pull/1098", "premise_still_valid": true, "summary": "Confirmed the premise by reading @objectstack/cli's lint.js directly and running it: `objectstack lint` exits 0 whenever errors.length===0 regardless of warning/suggestion count (153 warnings, 10 suggestions today, exit 0). Added scripts/check-lint-i18n-gate.mjs, which runs `objectstack lint --json`, counts issues whose rule starts with `i18n/missing-`, and fails when that count is not zero; wired it into `pnpm verify` and both CI workflows (ci.yml, code-quality.yml) as a dedicated step right after the existing lint step. Today's real i18n/missing-* count is 0, matching the PM's assumption. Reverse verification: manufactured a violation (deleted one ja-JP view label) inside a disposable, fully-isolated copy of the worktree under /tmp (never touching the real src/translations/**, which #597 is concurrently editing) and confirmed objectstack lint itself still exited 0 while the new gate exited 1 reporting i18n/missing-view; the disposable copy was then deleted and the real worktree verified byte-identical to origin/main on src/translations/.", "tests": "pnpm exec vitest run test/lint-i18n-gate.test.ts (under flock /tmp/os-heavy-verify.lock): 6 passed (6), including a real end-to-end run of the gate against current metadata asserting 0 i18n/missing-* issues. pnpm run lint: exit 0, 153 warning(s), 10 suggestion(s) (unchanged baseline). pnpm run lint:i18n-gate: 'i18n lint gate: 0 i18n/missing-* issues (163 total lint issue(s) reported)', exit 0. pnpm run typecheck (tsc --noEmit): no output, exit 0. pnpm run hygiene: 'source hygiene clean'. Self-scan for control bytes on all changed/new files: no matches. On the draft PR's first CI round (single read, not idle-polled): 'Quality Checks' completed conclusion=success, 'Check Changeset' completed conclusion=success; 'Build and Test (22.x)' was still in_progress at read time.", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
huangyiirene commentedon Aug 11, 2026
ACCEPT — PR #1098. All 9 check runs
completed: success, and the new step ran inside this PR's own CI (Build and Test+Quality Checksboth green), so the wiring is proven rather than asserted.The premise was confirmed at the source, not inferred from behaviour:
@objectstack/cli'slint.jsexits 0 whenevererrors.length === 0, regardless of warning count. Non-default-locale gaps are warnings, sopnpm verify's lint step could never go red on one. That is this card, measured.The mandated reverse verification was done, and done in the only safe way available. I required proof the gate can fail, and forbade touching
src/translations/**because #597 is editing those files right now. The dev built a disposable isolated copy of the worktree under/tmp, deleted one ja-JP view label there, and showedobjectstack lintstill exiting 0 while the gate exited 1 reportingi18n/missing-view— then deleted the copy and verified the real worktree byte-identical toorigin/mainonsrc/translations/. Both constraints satisfied at once, with the transcript in the PR body.Five things in the test file that make this a gate rather than a decoration:
i18n/coverage-below-thresholdis asserted not gated: the prefix isi18n/missing-, and over-matching would quietly widen the gate beyond what was ruled.errorcounts the same as a warning, so severity plumbing can't undercount.pnpm testcatches a regression too, not only the dedicated step.issuesarray) exits 1 with a clear message. This is the one I would have missed. If the CLI's--jsonshape ever changes, the gate fails loudly instead of finding zero violations in a structure it no longer understands. A gate that silently passes when its input shape drifts is precisely the failure mode that made Nine object files importF, Pfrom @objectstack/spec and never use them — three of them above the license header #1091 look rigorous for a week.Scope held. Only the
i18n/missing-*family gates; the other ~153 pre-existing warnings are untouched and explicitly documented as out of gate, with a note that widening the script is a separate deliberate change. The upstream half — making the lint rule itself error-severity inpackages/lint— is correctly named as out of this repo's reach rather than attempted.The
--fixtureseam is documented with its reason (a real gap cannot be manufactured from a test without either editing real translation files or carrying a disposable project copy), and the un-automated reverse verification is disclosed in the test header rather than implied to be covered. That is the honest shape of this trade.Cluster note: this closes the first and cheapest member of the eight-card gate-blind-spot cluster mapped above. The remaining seven (#838, #809, #802, #1003, #867, #935, #753) stay separate and are unaffected by the #1091 correction.
Generated by Claude Code