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: 根 tsconfig.json paths 另有 2 条死条目 —— @objectstack/plugin-msw 与 @objectstack/objectql 指向 node_modules 里根本没装的包 #4820

Closed

Description

@yinlianghui

发现来源

实施 #4804(删根 tsconfig.json 里 engine/ui/renderer 六条死 paths + 扩展守卫读 tsconfig paths 表)时发现。不在 #4804 范围内,故未在该 PR 里一并删 —— 那张卡的正文逐条点名的是 engine/ui/renderer 六行,这两条是另一种成因(指向 node_modules 而非 workspace 目录),且牵扯「这两个包是不是本该成为依赖」的取舍,属维护者决定,不该搭 XS 卡的顺风车。

现状

根 tsconfig.json compilerOptions.paths(#4804 删掉六行后的行号):

"@objectstack/plugin-msw": ["node_modules/@objectstack/plugin-msw/src/index.ts"],
"@objectstack/objectql": ["node_modules/@objectstack/objectql/src/index.ts"],

两个目标文件都不存在,而且不是「装了但布局不同」—— 这两个包整个不在依赖图里。在干净 worktree 里 pnpm install 之后实测(objectui @ ac600e5d2):

$ ls node_modules/@objectstack/
spec

$ ls node_modules/.pnpm/ | grep -E '@objectstack.(plugin-msw|objectql)'
(零命中 —— pnpm store 里也没有)

$ grep -rn --include=package.json --exclude-dir=node_modules -E '"@objectstack/(plugin-msw|objectql)"' .
(零命中 —— 全仓 38 个 package.json 都没把它俩声明成依赖)

影响:observation-class,今天零用户可见后果

仓内源码对这两个 specifier 的 import 数为 0;唯二的出现在面向用户的文档示例里,不参与任何编译:

skills/objectui/guides/data-integration.md:259: import { ObjectQLPlugin } from '@objectstack/objectql';
skills/objectui/guides/data-integration.md:261: import { MSWPlugin } from '@objectstack/plugin-msw';
content/docs/guide/objectos-integration.mdx:56:  import { ObjectQLPlugin } from '@objectstack/objectql';

扫描器反查证伪:同一把 grep 对 @objectstack/spec(真实依赖)在 39 个 package.json 命中,所以零命中是事实而非扫描器坏了。

于是今天没有任何解析走这两条映射 —— 与 #3944 / #3904 / #4804 完全同一种失效模式:配置声明了依赖图并不具备的能力,读起来像「这两个包已接线」,实际删掉它们对编译毫无影响。

与 #4804 的守卫的关系(重要)

#4804 的 PR 把「每个声明目标必须存在」的既有断言扩到了 tsconfig paths 表。这两条会让该断言变红,因此在那个 PR 里被显式列入一条棘轮式豁免名单(KNOWN_MISSING_TARGETS),名单指向本卡:

  • 名单不能悄悄变长 —— 任何新的死目标照样红;
  • 名单里的条目若已从 tsconfig 删除,守卫也会红,强制同时清掉豁免项。

所以本卡关掉的动作是:删这两行(或把这两个包变成真依赖),然后把 KNOWN_MISSING_TARGETS 清空。

建议方向(未决,需维护者判断)

两条路,取舍点在于这两个包到底该不该在本仓:

倾向 A:今天没有任何本仓代码需要它们,而 B 是新增依赖的产品决定,不该由一条死配置反推出来。但若维护者认为 §7 的规定意味着本仓早晚要自带这套 mock 栈,B 更符合长期方向 —— 请维护者定。

Related: #4804(本卡的发现现场)、#3944 / PR #4802、#3904 / PR #3942。observation-class,未认领。

Activity

  1. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator

    Triage — first-touch grading (triage seat, session session_01KTguWpd7WNGYTGmSNY31RL): promoted to pm:queue, type Task. Auto-adjudicated (veto window open in the round report; maintainer may overrule).

    Adjudication — option A: delete the two dead paths entries and empty KNOWN_MISSING_TARGETS in the #4804 guard. Grounds: the card's own measurements (zero in-repo imports of either specifier, zero package.json declarations, positive control on @objectstack/spec proves the grep), so the deletion is behaviour-neutral config hygiene — the guard's exemption list was designed to be emptied by exactly this card. Option B (making plugin-msw/objectql real dependencies) is a new-runtime-dependency product decision that must not be back-derived from a dead config line; choosing A today does not foreclose B — if the mock stack is ever wanted in-repo, the dependency gets added properly then, and the docs examples serve downstream users without needing this repo's paths map either way.

    Dev note: closing action is exactly the card's own — remove both lines, empty KNOWN_MISSING_TARGETS, and the #4804 guard then enforces "every declared target exists" with no exemptions.


    Generated by Claude Code

  2. added
    domain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo
    on Aug 21, 2026
  3. yinlianghui-tw commented on Aug 24, 2026

    @yinlianghui-tw
    Contributor

    Claim: PM loop round 5
    Session: session_019b5UBNMtTzKbVtZZGvFuxe
    Branch: claude/issue-4820-dead-config-alias-targets
    Worktree: objectui-issue-4820
    Domain: domain:devx (@ objectui, seat #5748)
    File surface: tsconfig.json, packages/runner/vite.config.ts, scripts/__tests__/vitest-config-alias-targets-3944.test.ts (stop on breach; explain in the report)
    Container & model: M (folded pair), mode:subagent, model: opus
    Clause-②: no
    Serial constraints cleared: no in-flight PR or claim touches any of the three files — lane in-flight was 0 at round open; the only pm:dispatched card in the lane is #5442 (changeset-release.yml, disjoint). Sibling cards not dispatched this round that share a surface: #5174 batch 2 (scripts/check-doc-snippet-types.mjs + content/docs/**) — read-coupling to this card measured and ruled out, see below. #5867/#5106 touch the doc-snippet gate, not these files.

    ⚠️ Identity: this seat runs under yinlianghui (the maintainer's own account) because that is what get_me returns in this session — ⛔ this is an ordinary loop claim, not the objectstack-ai/objectstack#25947 "maintainer's own, never touch" case. The Session: line above is the arbiter.


    This is a FOLDED dispatch — #4820 (chain head) + #5380

    Both cards are the same defect: a config table declares a target that does not exist, and a shrink-only ratchet in the guard carves it out pending this card. The fold is not a convenience — it is forced by a measurement:

    Both ratchet lists live in the same file. KNOWN_MISSING_TARGETS (#4820) and KNOWN_MISSING_PACKAGE_ALIAS_TARGETS (#5380, at :804) are both in scripts/__tests__/vitest-config-alias-targets-3944.test.ts.

    Serialising them would pay the rebase tax twice on one file for two three-line edits. Fold gates, checked rather than asserted:

    gate status
    ① same defect shape, same fix ✅ dead declaration + empty its ratchet entry, identically
    ② one package/area, one worktree/changeset/queue slot ✅ proven — same guard file
    ③ every member already adjudicated, ⛔ none in the decision box ✅ both ruled direction A, see below
    ④ each member independently verifiable ✅ distinct named criteria per card, below
    ⑤ exclusion list stated ✅ below

    #5380 carries its own claim comment pointing at this branch; it has no branch of its own by design, not as a half-state.

    Adjudications — ⛔ already made, do not re-open

    Both forks are closed. This dispatch does not reopen them:

    ⛔ Adding either package as a dependency, or creating src/app-data, is out of scope and maintainer-floor. If you find evidence that forces direction B, stop and report a fork — ⛔ do not implement B, and ⛔ do not quietly fall back to A-with-caveats.

    Premises — PM-verified on origin/main @ e52fac0, re-verify before editing

    premise PM reading
    the two paths entries still exist ✅ tsconfig.json:34,35
    neither package is installed ✅ node_modules/@objectstack/ holds only spec
    @app alias still declared ✅ packages/runner/vite.config.ts:25
    packages/runner/src/app-data absent ✅ 8 entries under src/, none of them app-data
    both ratchet lists still carve these out ✅ same file, :804 for the alias half

    Positive control on the grep (an empty result is not a reading): the same pattern against @objectstack/spec hits in 39 package.json files.

    The one live nuance, measured: the two @objectstack/* specifiers do appear in prose — skills/objectui/guides/data-integration.md:259,261 and content/docs/guide/objectos-integration.mdx:56. Those are downstream-user examples and need no paths mapping in this repo. ⛔ Do not touch skills/** — it is a governed surface and would turn this into a draft-only, human-merge PR for no benefit. ⛔ Do not touch the .mdx either.

    Independent acceptance criteria — one per member, neither may silently go missing

    One commit per card, and one Fixes #<n> line each in the PR body.

    ⛔ Exclusion list — things that look like this family and are NOT in it

    Named because a blind "fix all the dead aliases" sweep is exactly the failure this gate exists to prevent:

    1. The other 24 package vite.config.ts files with alias tables, and the root vitest.config.mts alias table. In scope for the guard to read; ⛔ not in scope to edit. A new dead target found there is a finding to file, not this PR's work.
    2. The ~10 live @object-ui/* entries in root tsconfig.json — all resolve; ⛔ do not touch.
    3. The six lines finding: 根 tsconfig.json compilerOptions.paths 有 6 行指向不存在目录的死条目(engine/ui/renderer 双形态)—— #3944 同类,vitest 侧已修,tsconfig 侧未覆盖 #4804 already removed (REMOVED_BY_4804) — already gone; that pin stays as-is.
    4. @object-ui/data-objectql referenced in the runner config's comment (the packages/runner/vite.config.ts 的 @object-ui/data-objectql 别名指向不存在的包目录(全仓唯一引用) #3593 case) — already handled; ⛔ not a second deletion.

    Gates to run

    objectui has no scripts/pm/dispatch-gates.mjs, so this list is derived from the diff by hand and you must re-derive it against what you actually change: scripts/__tests__/vitest-config-alias-targets-3944.test.ts (the direct guard, both describe blocks), Type Check, Lint. Changeset: the diff touches no published src/ — judge skip-changeset vs a changeset against the repo's own rule and state which and why in the report.

    Report the ratchet lists' before/after contents verbatim — they are the machine-checkable core of both cards.


    Generated by Claude Code

  4. yinlianghui-tw commented on Aug 24, 2026

    @yinlianghui-tw
    Contributor

    ⛔ Claim VOIDED — never dispatched. Card is back in the queue, unchanged.

    The claim above is withdrawn. pm:dispatched → pm:queue and the assignee cleared, verified on read-back.

    Provenance of this withdrawal — the maintainer, in the live /pm-dispatch devx@objectui session session_019b5UBNMtTzKbVtZZGvFuxe, 2026-08-24 ~08:55Z, verbatim:

    你进入收尾模式,先别派新活了,我要换git账户,然后你教下我怎么换

    Recorded verbatim because a withdrawal without provenance is indistinguishable from a mis-sweep, and a sibling seat would be right to reopen it.

    State, so the next seat does not re-derive any of it

    No os-dev agent was ever launched. No branch, no worktree, no PR, no edit. The claim comment was written and the labels flipped; the stop order arrived before dispatch. Nothing on main moved.

    ⚠️ The analysis in the voided claim is still good and was measured against origin/main @ e52fac0 this morning — reuse it rather than re-deriving:

    The fold with #5380 remains the recommended shape for whoever picks this up.


    Generated by Claude Code

  5. yinlianghui-tw commented on Aug 24, 2026

    @yinlianghui-tw
    Contributor

    Claim: PM loop round 6
    Session: session_019b5UBNMtTzKbVtZZGvFuxe
    Branch: claude/issue-4820-dead-config-alias-targets
    Worktree: objectui-issue-4820
    Domain: domain:devx (@ objectui, seat #5748)
    File surface: tsconfig.json, packages/runner/vite.config.ts, scripts/__tests__/vitest-config-alias-targets-3944.test.ts (stop on breach; explain in the report)
    Container & model: M (folded pair), mode:subagent, model: opus
    Clause-②: no
    Serial constraints cleared: lane in-flight was 0 at round open. Co-dispatched this round: #5174 batch 2 (scripts/check-doc-snippet-types.mjs, content/docs/**) and #5408 (README.md) — both disjoint from this surface, and the #5174 read-coupling was measured and ruled out (below). The lane's only other pm:dispatched card is #5442 (changeset-release.yml, disjoint).

    Re-claim. This supersedes the claim voided at 08:58Z — that one was withdrawn on a maintainer stop order before any agent was launched, then the maintainer resumed: 「好,就用 yinlianghui-tw 开工吧」. The technical content of the voided claim is unchanged and is restated below in full; ⛔ the withdrawal was procedural, not a change of plan.

    Identity note: this seat now runs as yinlianghui-tw (machine account), ⛔ no longer the maintainer's personal account. The R5 caution about misreading these claims is retired.


    This is a FOLDED dispatch — #4820 (chain head) + #5380

    Both cards are one defect: a config table declares a target that does not exist, and a shrink-only ratchet in the guard carves it out pending this card. The fold is forced by a measurement, not chosen for convenience:

    Both ratchet lists live in the same file. KNOWN_MISSING_TARGETS (#4820) and KNOWN_MISSING_PACKAGE_ALIAS_TARGETS (#5380, at :804) are both in scripts/__tests__/vitest-config-alias-targets-3944.test.ts.

    Serialising them pays the rebase tax twice on one file for two three-line edits. Fold gates, checked rather than asserted:

    gate status
    ① same defect shape, same fix ✅ delete dead declaration + empty its ratchet entry, identically
    ② one package/area, one worktree/changeset/queue slot ✅ proven — same guard file
    ③ every member already adjudicated, ⛔ none in the decision box ✅ both ruled direction A
    ④ each member independently verifiable ✅ distinct named criteria, below
    ⑤ exclusion list stated ✅ below

    #5380 carries its own claim pointing at this branch and has no branch of its own by design — that is the fold convention, ⛔ not a half-state.

    Adjudications — ⛔ already made, do not re-open

    ⚠️ Both card bodies read as open A/B forks and say the call is the maintainer's; the rulings are in the comments. ⛔ Do not dispatch from the bodies, do not re-litigate, do not escalate.

    ⛔ Adding either package as a dependency, or creating src/app-data, is out of scope and maintainer-floor. If evidence forces direction B, stop and report a fork — ⛔ do not implement B, ⛔ do not quietly fall back to A-with-caveats.

    Premises — PM-verified on origin/main @ e52fac0, re-verify before editing

    premise PM reading
    the two paths entries still exist ✅ tsconfig.json:34,35
    neither package installed ✅ node_modules/@objectstack/ holds only spec
    @app alias still declared ✅ packages/runner/vite.config.ts:25
    packages/runner/src/app-data absent ✅ 8 entries under src/, none of them it
    both ratchets still carve these out ✅ same file, :804 for the alias half

    Positive control (an empty result is not a reading): the same grep hits @objectstack/spec in 39 package.json files.

    The one live nuance, measured: both @objectstack/* specifiers appear in prose — skills/objectui/guides/data-integration.md:259,261 and content/docs/guide/objectos-integration.mdx:56. Those are downstream-user examples needing no paths map in this repo. ⛔ Do not touch skills/** — governed surface; it would force the PR draft-only for no benefit. ⛔ Do not touch the .mdx either.

    Independent acceptance criteria — neither member may silently go missing

    One commit per card; one Fixes #<n> line each in the PR body.

    ⛔ Exclusion list — looks like this family, is NOT in it

    Named because a blind "fix all the dead aliases" sweep is the exact failure this guard exists to prevent:

    1. The other 24 package vite.config.ts alias tables and the root vitest.config.mts table — in scope for the guard to read, ⛔ not to edit. A new dead target there is a finding to file, not this PR's work.
    2. The ~10 live @object-ui/* entries in root tsconfig.json — all resolve; ⛔ do not touch.
    3. REMOVED_BY_4804 (the six lines finding: 根 tsconfig.json compilerOptions.paths 有 6 行指向不存在目录的死条目(engine/ui/renderer 双形态)—— #3944 同类,vitest 侧已修,tsconfig 侧未覆盖 #4804 already deleted) — that pin stays as-is.
    4. @object-ui/data-objectql in the runner config's comment (the packages/runner/vite.config.ts 的 @object-ui/data-objectql 别名指向不存在的包目录(全仓唯一引用) #3593 case) — already handled; ⛔ not a second deletion.

    Gates

    objectui has no scripts/pm/dispatch-gates.mjs, so this list is hand-derived and you must re-derive it against what you actually change: scripts/__tests__/vitest-config-alias-targets-3944.test.ts (both describe blocks), Type Check, Lint. Changeset: the diff touches no published src/ — judge skip-changeset vs a changeset against the repo's own rule and state which and why.

    Report both ratchet lists' before/after contents verbatim — they are the machine-checkable core of both cards.


    Generated by Claude Code

  6. yinlianghui-tw commented on Aug 24, 2026

    @yinlianghui-tw
    Contributor
    {
      "issue": 4820,
      "status": "needs_decision",
      "branch": "claude/issue-4820-dead-config-alias-targets",
      "pr": "https://github.com/objectstack-ai/objectui/pull/5966",
      "premise_still_valid": false,
      "summary": "Folded pair, split by measurement. objectstack-ai/objectui#4820 is COMPLETE and shipped in draft PR objectstack-ai/objectui#5966 (1 commit, 2 files, +27/-19): both dead @objectstack paths entries deleted from tsconfig.json and KNOWN_MISSING_TARGETS emptied, its pin now asserting the emptiness instead of passing vacuously. objectstack-ai/objectui#5380 is NOT implemented — the premise_still_valid:false refers to it alone. Its premise-first stop condition fired: packages/runner/src/app-data is not a dead target but a documented, deliberately git-ignored, USER-SUPPLIED directory (packages/runner/.gitignore:1; README.md:85 and content/docs/utilities/runner.mdx:156 both tell the reader to copy or SYMLINK their metadata directory into it; README Development Workflow step 1 says to create it; MetadataLoader.ts:19-28 reads it). That falsifies the stated grounds of BOTH directions — A inherited objectstack-ai/objectui#3593 whose target was a deleted package, while this one is absent by design; B says the symlink convention and docs are missing, and they already exist. Per the dispatch I stopped, deleted nothing, and did not implement B: packages/runner/vite.config.ts:25 and KNOWN_MISSING_PACKAGE_ALIAS_TARGETS are untouched.",
      "tests": "All gates run at commit 0d31aa8a5 (= PR head, = final commit). Gate list re-derived from the actual diff; objectui has no scripts/pm/dispatch-gates.mjs. Every exit code captured before any pipe.\n\n(1) scripts/__tests__/vitest-config-alias-targets-3944.test.ts — 'Test Files 1 passed (1)' / 'Tests 289 passed (289)'. Verbose run confirms BOTH describe blocks executed: 'objectui#4804 — root tsconfig.json compilerOptions.paths table > the objectui#4820 carve-out is empty, so no paths entry is exempt' PASSED, and 'objectui#5168 — package-level vite.config.ts alias tables > the objectui#5168 carve-out still describes exactly the entries it was written for' PASSED. The objectstack-ai/objectui#4804 describe now enumerates exactly 10 paths entries, all @object-ui/*, no @objectstack/*.\n(2) turbo run type-check --concurrency=2 (FULL, not narrowed — root tsconfig.json is extended by every package tsconfig) — 'Tasks: 81 successful, 81 total', VERDICT command-exit 0.\n(3) pnpm type-check:scripts — TC_SCRIPTS_EXIT=0.\n(4) pnpm lint:root — LINT_ROOT_EXIT=0.\n(5) vitest run scripts/__tests__ — 'Test Files 62 passed (62)' / 'Tests 1664 passed (1664)'.\n(6) check-phantom-dependencies.mjs — 'Every in-scope import is declared by the package that publishes it.' exit 0.\n(7) check-type-check-coverage.mjs — '45/46 via type-check ... 41/41 packages compile their tests' exit 0.\n(8) check-control-bytes.mjs — 'OK (scanned 4950 tracked text file(s); skipped 85 binary)' exit 0; plus a direct grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]' over both changed files, zero hits.\n(9) check-changeset-presence.mjs — exit 0, 'No source of a released package changed in this range, so no changeset is owed.'\n\nDECLARED NARROWING: pnpm lint (turbo, all packages) was narrowed to lint:root, with all three required pieces of evidence. (a) population read from eslint's own config, not guessed: eslint reports root tsconfig.json as 'File ignored because no matching configuration was supplied', so it is outside eslint's population entirely; (b) file count from --format json: the one linted changed file, scripts/__tests__/vitest-config-alias-targets-3944.test.ts, reports errors=0 warnings=0; (c) invariance: type-aware linting is NOT enabled in eslint.config.js (grep for projectService/parserOptions/project: returns only a bare languageOptions at :29), so this diff cannot move any untouched file's verdict. CI runs the full farm regardless.\n\nREVERSE VERIFICATION (#4820), run on top of the commit so restore had a recovery point. Predicted direction stated first: RED, because with the carve-out empty the generic existence check must catch a re-added entry. Mutation proven on disk before running, anchored on the text being injected: occurrences of \"@objectstack/plugin-msw\" in tsconfig.json went 0 -> 1, shown at tsconfig.json:34. Result: GATE_EXIT=1, 'Tests 1 failed | 289 passed (290)', failing case 'objectui#4804 ... > @objectstack/plugin-msw maps to a path that exists' with 'AssertionError: paths[@objectstack/plugin-msw] maps to node_modules/@objectstack/plugin-msw/src/index.ts, which does not exist in the workspace.' Restore leg ran through a trap '... EXIT INT TERM'; git status empty afterwards and grep -c objectstack tsconfig.json = 0. No build/dist step is involved — this gate reads config files from the worktree, not compiled output, so no ablation-dist rebuild applies.\n\nRATCHET LISTS, VERBATIM (both live in scripts/__tests__/vitest-config-alias-targets-3944.test.ts, confirming the fold premise).\n\nKNOWN_MISSING_TARGETS — BEFORE:\n  const KNOWN_MISSING_TARGETS: readonly string[] = [\n    '@objectstack/plugin-msw',\n    '@objectstack/objectql',\n  ];\nKNOWN_MISSING_TARGETS — AFTER:\n  const KNOWN_MISSING_TARGETS: readonly string[] = [];\n\nKNOWN_MISSING_PACKAGE_ALIAS_TARGETS — BEFORE:\n  const KNOWN_MISSING_PACKAGE_ALIAS_TARGETS: readonly { config: string; specifier: string }[] = [\n    { config: 'packages/runner/vite.config.ts', specifier: '@app' },\n  ];\nKNOWN_MISSING_PACKAGE_ALIAS_TARGETS — AFTER: UNCHANGED, byte-for-byte identical to BEFORE (#5380 not implemented).\n\nPREMISE RE-VERIFICATION on this branch off origin/main e52fac05b. objectstack-ai/objectui#4820: tsconfig.json:34,35 still declared both entries; zero @objectstack/plugin-msw or @objectstack/objectql declarations across every package.json (positive control: the same grep hits @objectstack/spec in 31 files); node_modules/@objectstack/ holds only spec after pnpm install; zero hits in node_modules/.pnpm/ for either name; zero real import/require statements for either specifier across .ts/.tsx/.mts/.js/.mjs/.jsx (positive control: the same regex finds 12 real imports of @objectstack/spec) — so no program's module resolution changes. objectstack-ai/objectui#5380: packages/runner/vite.config.ts:25 still declares \"@app\"; packages/runner/src/app-data absent in every form; the declaration is still the repo's only @app reference. PM assumption that BOTH ratchet lists live in one file: CONFIRMED (KNOWN_MISSING_PACKAGE_ALIAS_TARGETS at :804 pre-edit).\n\nNOT A READING, stated so it is not mistaken for one: the clone is SHALLOW (51 commits reachable, .git/shallow present), so git log -S results about when the @app alias was added, and about whether src/app-data was ever tracked, are artifacts of the truncated history and are NOT offered as evidence. The working-tree evidence above stands on its own.\n\nBODY INTEGRITY: both issue bodies were read in full and are NOT truncated by the sanitizer — objectstack-ai/objectui#4820 ends at its 'Related:' line, objectstack-ai/objectui#5380 at its complete '## 严重度' section. All 4 comments on each issue were read to the last page.",
      "open_questions": [
        {
          "question": "#5380: what should happen to packages/runner/vite.config.ts:25 \"@app\" -> ./src/app-data, now that the target is measured to be a documented, deliberately git-ignored, user-supplied directory rather than a dead pointer? The 2026-08-21 ruling chose A by inheritance from objectstack-ai/objectui#3593, but objectstack-ai/objectui#3593's target was a DELETED PACKAGE, while this one is absent by design in a fresh checkout and appears the moment a reader follows README Development Workflow step 1. Direction B's stated gap ('the symlink convention and docs are missing') is also falsified — README.md:85, content/docs/utilities/runner.mdx:156 and MetadataLoader.ts:19-28 already document it, two of them using the word symlink. The narrower true statement is that the ALIAS has zero importers because LocalBundleLoader consumes the directory through relative import.meta.glob('../app-data/...'), never through @app.",
          "options": [
            "A' — delete the alias line on the NARROWER ground actually measured (an unused alias; the loader uses relative globs, so nothing breaks), and empty KNOWN_MISSING_PACKAGE_ALIAS_TARGETS. Cheapest, matches the ruling's action but replaces its reasoning. Cost: removes the ergonomic @app entry point for the very DX three docs tell readers to set up.",
            "B' — keep the alias and instead teach the gate that this target is legitimately optional (an 'expected-absent, user-supplied' classification rather than a carve-out pending a card). Preserves the affordance and fixes the pin's checkout-state dependence. Cost: a new gate concept, larger than either card scoped for.",
            "C — keep the alias, delete only the carve-out, and let the gate red-line it. Not viable: it reddens CI immediately.",
            "D — defer objectstack-ai/objectui#5380 entirely and re-triage it now that the target's status is measured, since both the A and B write-ups on the card rest on facts that no longer hold."
          ],
          "recommendation": "D, then A'. Re-triage is warranted because the ruling was made on an inherited analogy (#3593) that the measurement breaks, and a dev seat should not silently re-base a maintainer ruling on different grounds. If the maintainer wants the action without a re-triage round, A' is the right call on the four axes: real business need — zero importers today and the documented DX demonstrably does not route through the alias, so the affordance being preserved is hypothetical; long-term soundness — declared = enforced argues against a config line that only reads as if it were wired up; AI-authored-metadata safety — an alias resolving into a directory that may or may not exist is exactly the ambiguous surface that produces confident wrong output; startup scope discipline — B' invents a new gate classification for one entry with no pull behind it. But A' should be landed with the corrected reasoning in the commit, not the objectstack-ai/objectui#3593 analogy."
        },
        {
          "question": "#5168's shrink-only pin is checkout-state dependent for the @app entry, independent of which direction objectstack-ai/objectui#5380 takes. It asserts the carved-out entry is still declared AND still missing via fs.existsSync; any developer who follows README Development Workflow step 1 and creates packages/runner/src/app-data/ makes the target exist, and the pin then fails locally with 'A carved-out target now exists, so the carve-out is obsolete for it'. It is green in CI only because CI never creates the directory. Should this be fixed on its own, or is it acceptable as a transient that objectstack-ai/objectui#5380's resolution removes?",
          "options": [
            "Accept as transient — resolving objectstack-ai/objectui#5380 in any direction empties the carve-out and the failure mode disappears with it.",
            "Fix now — exclude expected-absent user-supplied targets from the 'still missing' half of the pin, so a correctly-configured developer machine does not go red."
          ],
          "recommendation": "Accept as transient, provided objectstack-ai/objectui#5380 is resolved promptly; the trap only exists while the carve-out does. I deliberately did NOT file this as a separate issue — it would be closed by objectstack-ai/objectui#5380 either way and would duplicate a card that is already open and dispatched. Flagging it here and in the PR body instead, for the PM to file if objectstack-ai/objectui#5380 is going to sit."
        }
      ],
      "out_of_scope_findings": [
        "NOT FILED (deliberate, reason stated): the objectstack-ai/objectui#5168 pin's checkout-state dependence described in open_questions[1]. It is a property of the carve-out that objectstack-ai/objectui#5380's resolution removes in either direction, and objectstack-ai/objectui#5380 is already open and dispatched, so a separate card would duplicate it. Recorded here and in PR objectstack-ai/objectui#5966's body rather than filed; PM to file if objectstack-ai/objectui#5380 will not be resolved soon.",
        "No new dead targets found in the excluded surfaces. The exclusion list was honoured and not swept: the other 24 package vite.config.ts alias tables, the root vitest.config.mts table, the ~10 live @object-ui/* paths, REMOVED_BY_4804, and @object-ui/data-objectql were all left untouched, and the gate reports them green on its own (289 passing cases), so there is nothing to file from them."
      ]
    }

    Generated by Claude Code

  7. yinlianghui-tw commented on Aug 24, 2026

    @yinlianghui-tw
    Contributor

    os-dev-report

    This supersedes the previous comment — same report, reposted. The <!-- os-dev-report --> HTML-comment marker was stripped by the body sanitizer on that one (verified on read-back: the stored body begins at the ```json fence), which would make it invisible to a marker scan. The marker is written as literal text here instead. No comment-edit tool is reachable from this seat, so the earlier comment is left in place rather than removed.

    {
      "issue": 4820,
      "status": "needs_decision",
      "branch": "claude/issue-4820-dead-config-alias-targets",
      "pr": "https://github.com/objectstack-ai/objectui/pull/5966",
      "premise_still_valid": false,
      "summary": "Folded pair, split by measurement. objectstack-ai/objectui#4820 is COMPLETE and shipped in draft PR objectstack-ai/objectui#5966 (1 commit, 2 files, +27/-19): both dead @objectstack paths entries deleted from tsconfig.json and KNOWN_MISSING_TARGETS emptied, its pin now asserting the emptiness instead of passing vacuously. objectstack-ai/objectui#5380 is NOT implemented — the premise_still_valid:false refers to it alone. Its premise-first stop condition fired: packages/runner/src/app-data is not a dead target but a documented, deliberately git-ignored, USER-SUPPLIED directory (packages/runner/.gitignore:1; README.md:85 and content/docs/utilities/runner.mdx:156 both tell the reader to copy or SYMLINK their metadata directory into it; README Development Workflow step 1 says to create it; MetadataLoader.ts:19-28 reads it). That falsifies the stated grounds of BOTH directions — A inherited objectstack-ai/objectui#3593 whose target was a deleted package, while this one is absent by design; B says the symlink convention and docs are missing, and they already exist. Per the dispatch I stopped, deleted nothing, and did not implement B: packages/runner/vite.config.ts:25 and KNOWN_MISSING_PACKAGE_ALIAS_TARGETS are untouched.",
      "tests": "All gates run at commit 0d31aa8a5 (= PR head, = final commit). Gate list re-derived from the actual diff; objectui has no scripts/pm/dispatch-gates.mjs. Every exit code captured before any pipe.\n\n(1) scripts/__tests__/vitest-config-alias-targets-3944.test.ts — 'Test Files 1 passed (1)' / 'Tests 289 passed (289)'. Verbose run confirms BOTH describe blocks executed: 'objectui#4804 — root tsconfig.json compilerOptions.paths table > the objectui#4820 carve-out is empty, so no paths entry is exempt' PASSED, and 'objectui#5168 — package-level vite.config.ts alias tables > the objectui#5168 carve-out still describes exactly the entries it was written for' PASSED. The objectstack-ai/objectui#4804 describe now enumerates exactly 10 paths entries, all @object-ui/*, no @objectstack/*.\n(2) turbo run type-check --concurrency=2 (FULL, not narrowed — root tsconfig.json is extended by every package tsconfig) — 'Tasks: 81 successful, 81 total', VERDICT command-exit 0.\n(3) pnpm type-check:scripts — TC_SCRIPTS_EXIT=0.\n(4) pnpm lint:root — LINT_ROOT_EXIT=0.\n(5) vitest run scripts/__tests__ — 'Test Files 62 passed (62)' / 'Tests 1664 passed (1664)'.\n(6) check-phantom-dependencies.mjs — 'Every in-scope import is declared by the package that publishes it.' exit 0.\n(7) check-type-check-coverage.mjs — '45/46 via type-check ... 41/41 packages compile their tests' exit 0.\n(8) check-control-bytes.mjs — 'OK (scanned 4950 tracked text file(s); skipped 85 binary)' exit 0; plus a direct grep -naP over both changed files for the control-byte class, zero hits.\n(9) check-changeset-presence.mjs — exit 0, 'No source of a released package changed in this range, so no changeset is owed.'\n\nDECLARED NARROWING: pnpm lint (turbo, all packages) was narrowed to lint:root, with all three required pieces of evidence. (a) population read from eslint's own config, not guessed: eslint reports root tsconfig.json as 'File ignored because no matching configuration was supplied', so it is outside eslint's population entirely; (b) file count from --format json: the one linted changed file, scripts/__tests__/vitest-config-alias-targets-3944.test.ts, reports errors=0 warnings=0; (c) invariance: type-aware linting is NOT enabled in eslint.config.js (grep for projectService/parserOptions/project: returns only a bare languageOptions at :29), so this diff cannot move any untouched file's verdict. CI runs the full farm regardless.\n\nREVERSE VERIFICATION (#4820), run on top of the commit so restore had a recovery point. Predicted direction stated first: RED, because with the carve-out empty the generic existence check must catch a re-added entry. Mutation proven on disk before running, anchored on the text being injected: occurrences of the plugin-msw key in tsconfig.json went 0 -> 1, shown at tsconfig.json:34. Result: GATE_EXIT=1, 'Tests 1 failed | 289 passed (290)', failing case 'objectui#4804 ... > @objectstack/plugin-msw maps to a path that exists' with 'AssertionError: paths[@objectstack/plugin-msw] maps to node_modules/@objectstack/plugin-msw/src/index.ts, which does not exist in the workspace.' Restore leg ran through a trap on EXIT INT TERM; git status empty afterwards and grep -c objectstack tsconfig.json = 0. No build/dist step is involved — this gate reads config files from the worktree, not compiled output, so no ablation-dist rebuild applies.\n\nRATCHET LISTS, VERBATIM (both live in scripts/__tests__/vitest-config-alias-targets-3944.test.ts, confirming the fold premise).\n\nKNOWN_MISSING_TARGETS — BEFORE:\n  const KNOWN_MISSING_TARGETS: readonly string[] = [\n    '@objectstack/plugin-msw',\n    '@objectstack/objectql',\n  ];\nKNOWN_MISSING_TARGETS — AFTER:\n  const KNOWN_MISSING_TARGETS: readonly string[] = [];\n\nKNOWN_MISSING_PACKAGE_ALIAS_TARGETS — BEFORE:\n  const KNOWN_MISSING_PACKAGE_ALIAS_TARGETS: readonly { config: string; specifier: string }[] = [\n    { config: 'packages/runner/vite.config.ts', specifier: '@app' },\n  ];\nKNOWN_MISSING_PACKAGE_ALIAS_TARGETS — AFTER: UNCHANGED, byte-for-byte identical to BEFORE (#5380 not implemented).\n\nPREMISE RE-VERIFICATION on this branch off origin/main e52fac05b. objectstack-ai/objectui#4820: tsconfig.json:34,35 still declared both entries; zero @objectstack/plugin-msw or @objectstack/objectql declarations across every package.json (positive control: the same grep hits @objectstack/spec in 31 files); node_modules/@objectstack/ holds only spec after pnpm install; zero hits in node_modules/.pnpm/ for either name; zero real import/require statements for either specifier across .ts/.tsx/.mts/.js/.mjs/.jsx (positive control: the same regex finds 12 real imports of @objectstack/spec) — so no program's module resolution changes. objectstack-ai/objectui#5380: packages/runner/vite.config.ts:25 still declares the @app key; packages/runner/src/app-data absent in every form; the declaration is still the repo's only @app reference. PM assumption that BOTH ratchet lists live in one file: CONFIRMED (KNOWN_MISSING_PACKAGE_ALIAS_TARGETS at :804 pre-edit).\n\nNOT A READING, stated so it is not mistaken for one: the clone is SHALLOW (51 commits reachable, .git/shallow present), so git log -S results about when the @app alias was added, and about whether src/app-data was ever tracked, are artifacts of the truncated history and are NOT offered as evidence. The working-tree evidence above stands on its own.\n\nBODY INTEGRITY: both issue bodies were read in full and are NOT truncated by the sanitizer — objectstack-ai/objectui#4820 ends at its 'Related:' line, objectstack-ai/objectui#5380 at its complete severity section. All 4 comments on each issue were read to the last page.",
      "open_questions": [
        {
          "question": "#5380: what should happen to the packages/runner/vite.config.ts:25 @app alias pointing at ./src/app-data, now that the target is measured to be a documented, deliberately git-ignored, user-supplied directory rather than a dead pointer? The 2026-08-21 ruling chose A by inheritance from objectstack-ai/objectui#3593, but objectstack-ai/objectui#3593's target was a DELETED PACKAGE, while this one is absent by design in a fresh checkout and appears the moment a reader follows README Development Workflow step 1. Direction B's stated gap ('the symlink convention and docs are missing') is also falsified — README.md:85, content/docs/utilities/runner.mdx:156 and MetadataLoader.ts:19-28 already document it, two of them using the word symlink. The narrower true statement is that the ALIAS has zero importers because LocalBundleLoader consumes the directory through relative import.meta.glob('../app-data/...'), never through @app.",
          "options": [
            "A-prime — delete the alias line on the NARROWER ground actually measured (an unused alias; the loader uses relative globs, so nothing breaks), and empty KNOWN_MISSING_PACKAGE_ALIAS_TARGETS. Cheapest, matches the ruling's action but replaces its reasoning. Cost: removes the ergonomic @app entry point for the very DX the docs tell readers to set up.",
            "B-prime — keep the alias and instead teach the gate that this target is legitimately optional (an 'expected-absent, user-supplied' classification rather than a carve-out pending a card). Preserves the affordance and fixes the pin's checkout-state dependence. Cost: a new gate concept, larger than either card scoped for.",
            "C — keep the alias, delete only the carve-out, and let the gate red-line it. Not viable: it reddens CI immediately.",
            "D — defer objectstack-ai/objectui#5380 entirely and re-triage it now that the target's status is measured, since both the A and B write-ups on the card rest on facts that no longer hold."
          ],
          "recommendation": "D, then A-prime. Re-triage is warranted because the ruling was made on an inherited analogy (#3593) that the measurement breaks, and a dev seat should not silently re-base a maintainer ruling on different grounds. If the maintainer wants the action without a re-triage round, A-prime is the right call on the four axes: real business need — zero importers today and the documented DX demonstrably does not route through the alias, so the affordance being preserved is hypothetical; long-term soundness — declared = enforced argues against a config line that only reads as if it were wired up; AI-authored-metadata safety — an alias resolving into a directory that may or may not exist is exactly the ambiguous surface that produces confident wrong output; startup scope discipline — B-prime invents a new gate classification for one entry with no pull behind it. But A-prime should be landed with the corrected reasoning in the commit, not the objectstack-ai/objectui#3593 analogy."
        },
        {
          "question": "#5168's shrink-only pin is checkout-state dependent for the @app entry, independent of which direction objectstack-ai/objectui#5380 takes. It asserts the carved-out entry is still declared AND still missing via fs.existsSync; any developer who follows README Development Workflow step 1 and creates packages/runner/src/app-data/ makes the target exist, and the pin then fails locally with 'A carved-out target now exists, so the carve-out is obsolete for it'. It is green in CI only because CI never creates the directory. Should this be fixed on its own, or is it acceptable as a transient that objectstack-ai/objectui#5380's resolution removes?",
          "options": [
            "Accept as transient — resolving objectstack-ai/objectui#5380 in any direction empties the carve-out and the failure mode disappears with it.",
            "Fix now — exclude expected-absent user-supplied targets from the 'still missing' half of the pin, so a correctly-configured developer machine does not go red."
          ],
          "recommendation": "Accept as transient, provided objectstack-ai/objectui#5380 is resolved promptly; the trap only exists while the carve-out does. I deliberately did NOT file this as a separate issue — it would be closed by objectstack-ai/objectui#5380 either way and would duplicate a card that is already open and dispatched. Flagging it here and in the PR body instead, for the PM to file if objectstack-ai/objectui#5380 is going to sit."
        }
      ],
      "out_of_scope_findings": [
        "NOT FILED (deliberate, reason stated): the objectstack-ai/objectui#5168 pin's checkout-state dependence described in open_questions[1]. It is a property of the carve-out that objectstack-ai/objectui#5380's resolution removes in either direction, and objectstack-ai/objectui#5380 is already open and dispatched, so a separate card would duplicate it. Recorded here and in PR objectstack-ai/objectui#5966's body rather than filed; PM to file if objectstack-ai/objectui#5380 will not be resolved soon.",
        "No new dead targets found in the excluded surfaces. The exclusion list was honoured and not swept: the other 24 package vite.config.ts alias tables, the root vitest.config.mts table, the live @object-ui/* paths, REMOVED_BY_4804, and @object-ui/data-objectql were all left untouched, and the gate reports them green on its own (289 passing cases), so there is nothing to file from them."
      ]
    }

    Generated by Claude Code

  8. yinlianghui-tw commented on Aug 24, 2026

    @yinlianghui-tw
    Contributor

    ACCEPT — PR #5966. Landing under the maintainer's 2026-08-24 auto-merge authorisation.

    Reviewer of record: domain:devx @ objectui seat (#5748), round R6, PM session session_019b5UBNMtTzKbVtZZGvFuxe. Verified against the diff, file list and check runs on GitHub — ⛔ not against the report.

    item reading
    PR shape draft ✅ · base main ✅ · first line Fixes objectstack-ai/objectui#4820 ✅ (⛔ correctly no Fixes objectstack-ai/objectui#5380)
    scope 2 files, +27/−19 — tsconfig.json and the guard test, exactly the declared surface
    the diff read directly: the two @objectstack/* paths lines removed and nothing else in that block touched — the neighbouring @object-ui/* entries are byte-identical in the context lines
    KNOWN_MISSING_TARGETS […two entries…] → [] ✅
    KNOWN_MISSING_PACKAGE_ALIAS_TARGETS unchanged, confirmed in the diff — #5380 genuinely untouched, ⛔ not partially applied
    CI 20 checks: 17 success, 3 skipped, 0 failed. Type Check took 9 min — a real run, as it must be when root tsconfig.json is extended by every package
    changeset none owed; the dev ran the gate rather than asserting it, and Changeset Declaration + Fixed Group Check pass on CI

    The judgement call that earns this ACCEPT

    Emptying the ratchet would have made the existing pin vacuously green — with an empty list, its two expectations iterate over nothing. The dev saw that and added expect(KNOWN_MISSING_TARGETS).toEqual([]), renaming the case to say so.

    That is exactly the trap this file guards against elsewhere in its own words ("a zero-hit parse would make every case below vacuous"), and nothing in the card or the dispatch order asked for it. Without it the card would have "landed" while quietly retiring the guard it was supposed to complete.

    Reverse verification — checked, not taken on trust

    Predicted direction stated before the run (red), mutation proven on disk by grepping the injected text (occurrences 0 → 1 at tsconfig.json:34) rather than trusting an editor exit code, restore through an EXIT INT TERM trap, working tree clean afterwards. Result GATE_EXIT=1, failing case named, 1 failed | 289 passed. The gate genuinely catches a re-added entry now that no exemption stands.

    Deviation — the fold split, correctly

    Dispatched as a folded pair; only #4820 is implemented. #5380's premise-first stop condition fired and the dev stopped without deleting anything or implementing B — precisely as the dispatch required. ⛔ That is not a shortfall: the fold's gate ③ assumed both members were adjudicated, and the measurement showed one of them was adjudicated on grounds that do not hold.

    #5380 is now pm:queue + pm:retriage with the dissent recorded; the consequential defect it uncovered is filed as #5968. Neither is this PR's business.

    Landing

    Path fork checked against the PR's actual file list before touching ready: tsconfig.json and scripts/__tests__/** are not governed surface (docs/adr/**, .claude/**, skills/**, AGENTS.md, CLAUDE.md). Every check green — the authorised bar, ⛔ not the required subset.

    Maintainer's ruling, in-session 2026-08-24, verbatim:

    授权 auto-merge(推荐)

    given against the alternatives of insisting on the merge queue or leaving everything draft, and on the measured ground that this repo's merge queue has never produced a merge_group build (#4986). The standing contradiction between that ruling and the skill's "queue is the only sanctioned path" is filed for the skills seat as objectstack#11621 so no further seat stalls on it.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

domain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions