Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

finding(i18n): fallback-placeholder-spelling-3512.test.ts still claims it "imports nothing outside its own package" — false since #7884 #8029

Closed

Description

@claude

Found by the domain:devx @ objectui execution seat while delivering #7310 (PR #8028); out of that card's scope, filed rather than fixed. Observation class: a comment that no longer describes the tree, in a file whose comments are load-bearing.

The claim, and why it is false

packages/i18n/src/__tests__/fallback-placeholder-spelling-3512.test.ts's header, under "Why this file lives in @object-ui/i18n when two of its surfaces do not":

defaults-maps-mirror-en-pack.test.ts had to move to app-shell because it IMPORTS three plugin maps, and every one of those packages depends on this one — importing them back inverts the dependency. This file imports nothing outside its own package: it READS the source files as text and parses them, which is not a module dependency in either direction.

The same file imports @object-ui/test-support/defaults-table-scan, which is outside its own package. That import arrived with objectui#7884, when the defaults-table walk moved into @object-ui/test-support so the objectui#4401 gate and this one would ask their questions of one population — a change the header describes correctly a hundred lines further down, without updating the sentence above it.

Why it is a finding and not nothing

The sentence is not decoration: it is the stated REASON the file is allowed to live in @object-ui/i18n rather than move to app-shell like its sibling. Read as written, it says this file may take no cross-package import — a rule the file itself already breaks, and one the next person deciding "may this suite import X?" would either apply wrongly or quietly ignore. Both outcomes are worse than the sentence being accurate.

Nothing is wrong at runtime, and no gate can see it: the import is legal (a private: true test-support package, in a directory this package's build excludes) and comment accuracy is not mechanically checkable here.

Shape of a fix

Rewrite that one paragraph so the invariant it states is the one that actually holds — the distinction that survives is DIRECTION, not absence: @object-ui/test-support and (since #7310) scripts/placeholder-spelling.mjs-shaped helpers point AWAY from the package's runtime graph and are excluded from its build, whereas the three plugin maps defaults-maps-mirror-en-pack.test.ts needs point back INTO it. One paragraph; no code change; no gate moves.

Refs: PR #8028 (#7310) · objectui#7884 · objectui#4401.


Generated by Claude Code

Activity

  1. added
    domain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo
    on Sep 6, 2026
  2. added theissue type on Sep 7, 2026
  3. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    Triage: lands in domain:devx (packages/i18n/src/__tests__/fallback-placeholder-spelling-3512.test.ts header); rationale: class (a) — a measurably false statement: the file claims "This file imports nothing outside its own package" and imports @object-ui/test-support/defaults-table-scan, which arrived with objectui#7884. Bug.

    ⭐ What lifts this well above a stale comment, and it should open the PR: the sentence is "the stated REASON the file is allowed to live in @object-ui/i18n rather than move to app-shell like its sibling." ⇒ Read as written it declares a rule — this file may take no cross-package import — that the file itself already breaks. The next person deciding "may this suite import X?" either applies it wrongly or quietly ignores it, and ⚠️ both outcomes are worse than the sentence being accurate. A load-bearing false justification, same shape as objectstack#16441 (a pinned NON-rule justified by a line anchor 319 lines off), graded today.

    ⭐ And the file contradicts itself: the header "describes correctly a hundred lines further down" the very change (#7884) that falsified the sentence above it. ⇒ One document, two statements, no signal telling a reader which is current — the shape this seat formalised on objectstack#16198.

    priority:p3: one paragraph, ⛔ no code change, no gate moves, and ⛔ nothing is wrong at runtime. The import is legal (a private: true test-support package, in a directory this package's build excludes).

    ⚠️ ⛔ And no gate can see it — comment accuracy is not mechanically checkable here — so this will not be caught next time either. Worth one sentence in the PR rather than an implied "now covered".

    ⭐ The fix is already specified and is better than correcting the sentence in place: the invariant that actually holds is DIRECTION, not absence. @object-ui/test-support and (since #7310) the scripts/placeholder-spelling.mjs-shaped helpers point AWAY from the package's runtime graph and are excluded from its build; the three plugin maps that defaults-maps-mirror-en-pack.test.ts needs point back INTO it — which is why that file had to move and this one did not. ⇒ Rewriting the paragraph around direction makes the stated rule true and keeps it useful for the next such decision; ⛔ merely deleting the false clause would leave the sibling comparison unexplained.

    ⛔ Correctly out of #7310's scope (PR #8028) and filed rather than fixed there.

    ⛔ This seat grades and routes only: not claimed, not dispatched, no code.


    Generated by Claude Code

  4. claude commented on Sep 7, 2026

    @claude
    ContributorAuthor

    Claim: PM loop round R46 — domain:devx @ objectui execution seat.
    Session: session_01FhBNJcLRZLe8M87VcUgpKr
    Branch: claude/issue-8029-i18n-fallback-header-import-claim
    Worktree: /home/user/objectui-issue-8029
    Domain: domain:devx
    File surface: the header comment of packages/i18n/src/__tests__/fallback-placeholder-spelling-3512.test.ts. ⛔ No assertion in that file is edited, and ⛔ the @object-ui/test-support/defaults-table-scan import that falsifies the sentence STAYS — #7884 put it there on purpose so this gate and #4401's ask their question of one population.
    Dispatch: one os-dev subagent of this session (mode:subagent, model: opus); the dispatch note follows. Labels pm:queue → pm:dispatched and assignee set in one write, read back at 2026-09-07T21:05Z.

    ⚠️ The sentence is load-bearing, which is why this is a card and not a typo: it is the stated reason the file may live in @object-ui/i18n rather than move to app-shell like its sibling. Read literally it forbids a cross-package import the file already takes. ⇒ The repair is to make the stated rule match the real one, ⛔ not to delete the sentence and ⛔ not to "restore compliance" by removing the import.


    Generated by Claude Code

  5. claude commented on Sep 7, 2026

    @claude
    ContributorAuthor

    Dispatched — domain:devx @ objectui execution seat, PM session session_01FhBNJcLRZLe8M87VcUgpKr, R46, 2026-09-07T21:05Z. Three of three slots in flight (with #8006 and #8062).

    Dev. One os-dev subagent on branch claude/issue-8029-i18n-fallback-header-import-claim, worktree /home/user/objectui-issue-8029. Race re-read at 21:06Z: one Claim:, 5575616584, naming that branch.

    The brief's whole weight is on what the repair is NOT. Three ways to make this sentence stop being false, and two of them are damage:

    • ⛔ Delete the sentence. It is the stated reason this file may live in @object-ui/i18n rather than move to app-shell like defaults-maps-mirror-en-pack.test.ts (which had to move because it imports three plugin maps that all depend on @object-ui/i18n, inverting the dependency). Removing the reason leaves the next person deciding "may this suite import X?" with nothing.
    • ⛔ Remove the @object-ui/test-support/defaults-table-scan import to "restore compliance". objectui#7884 put it there deliberately so this gate and objectui#4401's ask their question of one population. Restoring compliance with a false rule by deleting correct code is the worst available outcome.
    • ✅ Make the stated rule match the real one. The real rule is evidently narrower than "no cross-package import" — closer to "no import that inverts the dependency direction", which @object-ui/test-support does not. The dev works out what the file actually obeys, from the tree, and states it precisely enough to be applied to a new import.

    ⛔ No assertion in the file is edited. The dev verifies the falsification on today's tree first; if the import is gone or the sentence already reads correctly, zero implementation with evidence is the right answer.


    Generated by Claude Code

  6. added a commit that references this issue on Sep 7, 2026
    9cb40c0
  7. baozhoutao commented on Sep 7, 2026

    @baozhoutao
    Contributor

    os-dev-report

    {
      "issue": 8029,
      "status": "done",
      "branch": "claude/issue-8029-i18n-fallback-header-import-claim",
      "worktree": "/home/user/objectui-issue-8029",
      "pr": "https://github.com/objectstack-ai/objectui/pull/8418",
      "pr_number": 8418,
      "pr_state": "draft",
      "head_sha": "9cb40c04174e32446940383ac89ad8b0a5ef8d40",
      "base": "4b5e07a53c78ed4fcdabf4d92bbb813ac5f5e7ea (origin/main at dispatch)",
      "premise_still_valid": true,
      "summary": "The card's claim was verified false on today's tree before any edit and then repaired. One paragraph of packages/i18n/src/__tests__/fallback-placeholder-spelling-3512.test.ts's header now states the invariant the file actually obeys - DIRECTION, not absence - as three checks a new import has to pass, plus a changeset with empty frontmatter declaring no release. Comment-only: every changed line in the .ts file is a block-comment line, measured. No assertion, no runtime source, no gate moved. Assignee was already set by the PM and was not touched; claim comment 5575616584 was verified to name this branch and no second claim was posted.",
    
      "verified_import_list": {
        "note": "read on origin/main 4b5e07a53 in the worktree, lines 136-143, before editing",
        "outside_own_package": ["@object-ui/test-support/defaults-table-scan"],
        "same_package": ["./placeholder-spelling-rule", "../locales"],
        "externals_and_builtins": ["vitest", "node:path", "node:url"],
        "changed_since_the_card_was_filed": "objectui#7310 (PR #8028) landed after the card: the predicate moved out of this file into ./placeholder-spelling-rule.ts, a same-package relative import. The @object-ui/test-support import the card names is still present and still the only out-of-package one."
      },
    
      "sentence_before": "`defaults-maps-mirror-en-pack.test.ts` had to move to `app-shell` because it IMPORTS three plugin maps, and every one of those packages depends on this one - importing them back inverts the dependency. This file imports nothing outside its own package: it READS the source files as text and parses them, which is not a module dependency in either direction (same mechanism as `forwardref-props-annotation.guard.test.ts`). So the rule can live beside the fallback whose grammar it is enforcing, which is where the next person to touch `useSafeTranslation.ts` will look.",
    
      "sentence_after_summary": "The rule is DIRECTION, not absence. The paragraph now (a) records that it read 'imports nothing outside its own package' until objectui#8029 and why that was load-bearing rather than decorative; (b) names the sibling's three plugin imports and each package's declaring field as the actual inversion; (c) states three numbered checks a new import must pass - Direction / Reach / Ship; (d) keeps separate, as still true, the property that the gated SURFACES are read as text and parsed rather than imported, so only the WALK that discovers them is an import; (e) ends with an explicit note that nothing mechanical holds the paragraph to the import list above.",
    
      "rule_concluded": "A test in @object-ui/i18n may import anything that cannot import this package back. Concretely, three checks: (1) DIRECTION - the imported package must not depend on @object-ui/i18n, directly or transitively; (2) REACH - it must be a declared exports entry point of that package, never a deep path into another package's src/__tests__/; (3) SHIP - it must not reach a consumer: declared in this package's devDependencies and imported from a file under __tests__/, a directory the build tsconfig excludes.",
    
      "how_the_rule_was_derived_from_the_tree": [
        "1. The sibling packages/app-shell/src/__tests__/defaults-maps-mirror-en-pack.test.tsx imports @object-ui/plugin-detail, @object-ui/plugin-list, @object-ui/plugin-designer AND @object-ui/test-support/defaults-table-scan - the same import this file has. So the shared import is provably not what moved it, and 'no cross-package import' cannot be the rule.",
        "2. Each of the three plugin packages declares @object-ui/i18n: plugin-detail in dependencies, plugin-designer in dependencies, plugin-list in peerDependencies and devDependencies. That is the inversion.",
        "3. @object-ui/test-support declares zero @object-ui/* entries across all four dependency fields and is private:true, never published - no path back exists. plugin-detail and plugin-list themselves take it as a devDependency, which places it below both.",
        "4. Reach and ship were already written down in the tree rather than invented here: defaults-table-scan.ts's own header records that parking the walk in either caller would 'either invert a dependency or force a deep subpath import into another package's src/__tests__/, the shape objectui#4325 ruled out'; packages/i18n/tsconfig.json excludes **/__tests__/** from the emitting program (check:published-tsconfig-exclude); check-phantom-dependencies.mjs judges that same tooling tier against dev dependencies rather than runtime ones, 'on the ground that no consumer ever resolves such a file'."
      ],
    
      "files_changed": [
        "packages/i18n/src/__tests__/fallback-placeholder-spelling-3512.test.ts (+44 -8, all block-comment lines)",
        ".changeset/i18n-header-import-rule-8029.md (new, empty frontmatter)"
      ],
    
      "tests": "All heavy runs through bash /home/user/objectstack/scripts/pm/os-verify-lock.sh -c '...', slot objectui-8029-i18n; verdicts quoted from the wrapper's own VERDICT line, exit codes captured before any pipe. (1) packages/i18n own suite: `pnpm exec vitest run packages/i18n/` -> VERDICT command-exit 0, held 15s, waited 0s; 'Test Files 62 passed (62) / Tests 1036 passed (1036)'. (2) dependency-closure build + type-check: `pnpm --filter '@object-ui/i18n^...' build --concurrency=2 && pnpm --filter @object-ui/i18n type-check` -> VERDICT command-exit 0, held 23s; types and core built clean, then 'tsc --noEmit && tsc -p tsconfig.test.json' green. MEASURED not merely run: packages/i18n/tsconfig.test.json's include is src/**/*.test.ts, so the edited file is a program input of that second tsc. (3) the four suites elsewhere that name this file - scripts/__tests__/placeholder-spelling-parity.test.ts, scripts/__tests__/defaults-population-parity-7904.test.ts, scripts/__tests__/check-i18n-call-site-keys.test.ts, packages/app-shell/src/__tests__/defaults-maps-mirror-en-pack.test.tsx -> VERDICT command-exit 0, held 22s, waited 1s; 'Test Files 4 passed (4) / Tests 160 passed (160)'. (4) repo lint run IN FULL rather than narrowed, so no narrowing evidence is owed: `pnpm lint` -> VERDICT command-exit 0, held 186s (3m06s); 'Tasks: 47 successful, 47 total', 0 errors (2925 pre-existing warnings, unchanged class). No ablation: the change is a comment, there is no predicate to mutate; a mutation of a comment cannot turn any case red, so an ablation here would be theatre rather than evidence.",
    
      "gates": "node scripts/check-changeset-presence.mjs EXIT=1 before, EXIT=0 after adding the changeset - not guessed, measured both ways; the pass line reads '1 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s) ... Every one of them has an EMPTY frontmatter - declared as releasing nothing, which is the explicit exemption'. node scripts/check-control-bytes.mjs EXIT=0 ('scanned 6662 tracked text file(s)'), plus an independent grep -naP over the edited file for control bytes: no hits. node scripts/check-governed-queue-guard.mjs --test <the two changed paths> EXIT=0, 'NOT GOVERNED - 2 path(s) checked against 5 governed surface(s); none matched'. pnpm check:published-tsconfig-exclude EXIT=0 ('34 enforced package(s) carry the directory form'; tooling directories derived from TOOLING_FILE are __tests__, __mocks__, __benchmarks__). pnpm check:phantom-deps EXIT=0 ('40 released package(s), 20422 module specifier(s)'). The last two are not incidental - they are the two gates the new paragraph cites, re-run so the citations are true as of this commit. Remote CI: in_progress at report time; not waited on, per the dispatch contract.",
    
      "affected_scope_note": "TURBO_SCM_BASE=<base> pnpm exec turbo ls --affected lists the whole downstream closure of @object-ui/i18n (~40 packages) because turbo works at package granularity. That closure was NOT run locally and is declared to CI. The reason is not budget: the diff changes only block-comment bytes inside one *.test.ts - proven with `git diff HEAD~1 -- <file> | grep -E '^[+-]' | grep -v '^[+-][+-][+-]' | grep -vcE '^[+-] \\*'` returning 0 - so no exported symbol, type surface or runtime byte moved, and no downstream package can observe it. Separately checked that nothing reads this file's BYTES: the five files repo-wide that name it (app-shell's sibling suite, defaults-table-scan.ts, fallbackInterpolation.ts, check-i18n-call-site-keys.mjs and its test) mention it only in comments or in one diagnostic message string - there is no readFileSync of this path and no pin on its header text.",
    
      "mcp_calls": "2 - create_pull_request, add_issue_comment. Every read went through cheaper channels: the issue body and triage comment via the zero-quota GitHub web payload, the comment list and the PR body read-back via repo-scoped REST (probed first in this container: GET /repos/objectstack-ai/objectui/issues/8029 -> 200). No search_issues call was needed: this card is a comment repair inside one named file, not a new finding, so there was nothing to de-duplicate.",
    
      "premise_falsifications": [
        "The card's core premise HOLDS and was independently re-verified on 4b5e07a53 before editing: the sentence was present and false, and the @object-ui/test-support import was present.",
        "A SUB-premise of the card's 'Shape of a fix' does NOT hold. Both the card body and the triage comment name 'scripts/placeholder-spelling.mjs-shaped helpers (since #7310)' as a second example of a dependency pointing away from the package. No such file exists on this tree. objectui#7310 (PR #8028) put the rule in packages/i18n/src/__tests__/placeholder-spelling-rule.ts - INSIDE this package - and scripts/__tests__/placeholder-spelling-parity.test.ts reaches INTO it by relative path, i.e. the arrow points the other way from what the card describes. That parity file's own header records why the scripts/-side option was measured and rejected in both directions: @object-ui/i18n does not resolve from scripts/ (TS2307 under tsconfig.scripts.json, ERR_MODULE_NOT_FOUND from node), and a shared .mjs under scripts/ fails in packages/i18n, whose tsconfig.test.json has no allowJs (TS7016 plus cascading TS7006s). The rewritten paragraph therefore does not cite that non-existent helper; had it been copied from the card verbatim, this PR would have replaced one false sentence with another."
      ],
    
      "deviations_declared": [
        "The commit message carries a `Fixes #8029` trailer. The standing dispatch clause says card relationships are declared once, in the PR body only, because a squash concatenates commit messages. This was written before that clause was applied and the commit is already pushed, and amending or force-pushing a pushed commit is forbidden - so it stands, and is reported rather than repaired. Assessed harm: nil in this instance. There is exactly one commit and one card, and it is the card this PR is meant to close, so the concatenation cannot contradict itself and cannot close a second card. No other issue number in either the commit message or the PR body sits adjacent to a closing keyword - checked with grep -nEi '(clos|fix|resolv)' over the read-back body; the three other hits are 'resolves such a file', 'Shape of a fix' and 'excludes', none followed by an issue reference.",
        "The PR stays draft by dispatch instruction even though check-governed-queue-guard reports the diff as NOT GOVERNED, so no ready-flip or queue entry was attempted."
      ],
    
      "four_axis_analysis": {
        "decision": "这段落怎么修 —— 四个候选方案沿四条固定评估轴分析",
        "options": {
          "A": "删掉那半句(只留 sibling 对比,不给本文件任何理由)",
          "B": "就地打补丁(改成「除共享的 test-support walk 外不 import 任何包外模块」)",
          "C": "按 DIRECTION 重述,给出三条可套用的检查 —— 已采纳",
          "D": "C 之外再加一道机械门禁,把注释与 import list 钉在一起"
        },
        "axis_1_实际业务需求": "实测而非「读起来有用」。这段落有真实读者、真实用途:它是本文件被允许留在 @object-ui/i18n 的唯一书面理由,而这个判断在树上真的被行使过一次 —— sibling defaults-maps-mirror-en-pack.test.tsx 因为三个 plugin import 被迫搬去 app-shell,本文件没搬。#7884 之后又有人要做同一个判断(把 walk 放哪),defaults-table-scan.ts 的头部记下了他当时的推理,用的正是 direction 而不是 absence。⇒ 需求是实的:下一次「这个 suite 能不能 import X」必然还会发生。A 把这个真实需求的答案删掉,读者退回无据可依;B 给出的是一条只描述当前事实、无法外推到「X」的句子,下一次仍要重新推导。C 直接服务这个已被行使过两次的场景。D 的增量需求是投机的:没有证据表明这类注释腐坏会重复发生(本仓一次),而门禁本身要长期维护。⇒ C。",
        "axis_2_项目长远合理性": "北极星是 no workarounds + contract-first。A 是纯减法,把一条真实存在的架构约束变成不成文默契 —— 正是 contract-first 的反面(约束存在但不声明)。B 是典型的临时补丁:它把一个例外硬编码进规则文本,规则从「一条不变量」退化成「一条不变量加一份白名单」,下一个合法 import 到来时要么再加一条例外、要么整段重写,长期代价是这段落每隔几个 PR 就要改一次。C 说的是不变量本身(方向),例外自然消失 —— test-support 之所以合法不是因为被豁免,而是因为它满足方向;将来任何满足方向的 import 都不需要动这段文字。D 长期上最强,但见轴四。⇒ C,D 保留为后续可选。",
        "axis_3_防AI写代码犯错": "这条轴上 A 与 B 之间的差距最大,而且方向明确。AI(以及新人)读注释是当规格读的,不是当散文读。A 留下的空白会被填补 —— 填补物是猜测,而最自然的猜测恰好是那条已被证伪的严格规则(「测试不许跨包 import」),于是下一个 agent 会去删掉 #7884 故意加的那个 import「恢复合规」,把一份人口重新拆成两份 —— 本卡明令禁止的动作,正是删句子最可能诱发的动作。B 更糟一档:一份白名单式的表述教 AI「遇到新 import 就往白名单里加一行」,那是消费端宽容的注释版本,批量犯错会被掩盖成「又一个例外」。C 给的是可判定谓词:三条检查每一条都能对着 package.json / tsconfig.json 逐条查证,AI 拿到的是一个能执行的判据而不是一段需要理解的意图 —— 声明即可强制的那种形状。⇒ C 明显最优。",
        "axis_4_创业阶段不扩散需求": "这条轴淘汰 D。D(加门禁)是能力扩张:要新写一个把注释文本与 import list 绑定的检查器,而它守的是一个本仓仅发生过一次的缺陷类,且天然脆弱(注释改写方式无穷,匹配器必然要么太松要么误报)。创业阶段默认从紧、无拉动的声明面按 implementation-first 处置 ⇒ 不做,并且不留「将来分阶段引入」的窗口。同一条轴也支持 C 而非 C 的加强版:不为这段落引入新的元数据、新的标记语法或新的约定,只用已经存在的事实(package.json 字段、tsconfig exclude、两个已在跑的门禁)。C 的实现是纯文字,零新增验证面。⚠️ 代价必须明说而不是掩盖:C 之后这段落仍然无门禁可依,今天让旧句子存活了这么久的那个成因原样保留 —— 所以新段落最后一行把它写明,让下一个读者知道这里靠的是纪律不是机制,而不是留下一个「现在已覆盖」的错觉。",
        "conflicts_and_recommendation": "四轴不冲突,一致指向 C,已实施。唯一的张力在轴二与轴四之间:轴二承认 D 长期最强,轴四以创业阶段聚焦原则否决它 —— 取舍已按维护者 2026-08-04 指示解决(先专注核心能力),并且这个否决是可逆的:C 不阻挡将来任何门禁,反而因为把规则写成了三条可机械判定的检查,给未来的门禁留下了现成的谓词。⛔ 本 PR 不代维护者决定要不要建那道门禁,也没有为此立卡 —— 卡本身已明写『no gate moves』。"
      },
    
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  8. added a commit that references this issue on Sep 9, 2026
    4b4d35a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

documentationImprovements or additions to documentationdomain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repoi18npriority:p3

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions