You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
@object-ui/console publishes plugin.js from the package root, which turbo's build outputs do not cover — a cache hit restores an incomplete package #7855
Found by the dev seat implementing #7276 while re-deriving that card's mechanism. Unassigned, unlabelled — recording a measurement, not claiming a priority.
plugin.js and plugin.d.ts are produced by build:plugin (tsc -p tsconfig.plugin.json), are gitignored (apps/console/.gitignore:16), and match none of the outputs globs. So they are neither hashed as inputs nor stored as outputs: a cache hit for @object-ui/console:build restores dist/ and leaves the package's published entry absent.
Measured
On origin/main52cac38, two worktrees of the same commit, turbo 2.10.9:
Worktree A ran a cold pnpm build — 43 tasks, 3m46.7s. apps/console/plugin.js present.
Worktree B ran pnpm build — 43 of 43 cache hits, 272ms, FULL TURBO.
In worktree B: apps/console/dist/ fully restored, apps/console/plugin.jsdoes not exist.
pnpm check:node-esm-load in worktree B then reported exactly the line #7276 quoted from a real run:
✗ @object-ui/console: no-build-output — ./plugin.js does not exist after the build
Why this is worth a card
This is the mechanism behind the loud half of #7276, and it outlives that card's fix. #7276 makes the ESM-load gate refuse to grade artifacts another tree produced — that turns the misattributed red into an accurate one, but it does not make the cache entry complete. Anything else that consumes a cached @object-ui/console build still gets a package whose declared entry is missing, and the tell is a no-build-output style failure pointing at a package the author did not touch.
The narrow fix is to declare the two files as outputs — either widening the shared build task in turbo.json, or (smaller blast radius) giving apps/console a package-level turbo.build.outputs that adds plugin.js and plugin.d.ts. Whether any OTHER package publishes from its root should be checked in the same pass rather than assumed: the audit is exports/main targets that do not start with ./dist/.
Not fixed in #7276's PR: that card's declared file surface is the gate script and its test, and turbo.json was explicitly limited there to "only if the fix requires it". It did not.
Refs: #7276 (where this surfaced) · #1760 (the adjacent cache-masking case)
This is the mechanism behind the loud half of #7276, and it outlives that card's fix. #7276 makes the ESM-load gate refuse to grade artifacts another tree produced — that turns the misattributed red into an accurate one, but it does not make the cache entry complete.
The narrow fix is to declare the two files as outputs — either widening the shared build task in turbo.json, or (smaller blast radius) giving apps/console a package-level turbo.build.outputs that adds plugin.js and plugin.d.ts.
Whether any OTHER package publishes from its root should be checked in the same pass rather than assumed: the audit is exports/main targets that do not start with ./dist/.
Not fixed in #7276's PR: that card's declared file surface is the gate script and its test, and turbo.json was explicitly limited there to "only if the fix requires it". It did not.
Claim: PM loop round R45
Session: session_01MM7kaS4dPpYHV5BsMyu4tQ
Branch: claude/issue-7855-console-plugin-outputs
Worktree: objectui-issue-7855
Domain: domain:devx
File surface: apps/console/package.json (a package-level turbo → build.outputs extension adding plugin.js and plugin.d.ts — triage's endorsed smaller-blast-radius route); turbo.json ONLY if the package-level route is measured not to work (say why); the audit of every packages/*/package.json + apps/*/package.json whose exports/main targets do not start with ./dist/ (report the table; fix additional root-published packages only if they are the same defect shape, otherwise file); a pin that fails if a published entry falls outside the build task's declared outputs (small, in scripts/__tests__/ beside turbo-build-inputs.test.ts, ⛔ not by editing that file's existing assertions) (stop on breach; explain in the report)
Container & model: M, not mechanical (the outputs route and the audit's verdict per package are judgment), mode:subagent, model: opus — no path-derived tier mandate on these paths (floor sonnet · default opus · ceiling fable); default judgment tier taken
Clause-②: no
Serial constraints cleared: held until PR #7986 (#7292, the manifest-hook deletion that also reasons about turbo's build task) MERGED — it did at 07:20:30Z; premise re-read on origin/mainbce5971 at 07:34Z: apps/console/package.json:16"main": "./plugin.js", no turbo key in that manifest, turbo.jsonbuild.outputs still the four globs; dependabot #7058 touches apps/console/package.json on its lucide-react line only (different hunk, textual); no other open PR touches turbo.json or that manifest (file lists read 06:27Z; #7685's 67 paths over git); this seat's in-flight batch (#5174 b17 in packages/plugin-detail, #7307 b1 in plugin test files) is disjoint. pm:queue → pm:dispatched + assignee written in one stroke and read back.
{
"issue": 7855,
"status": "done",
"branch": "claude/issue-7855-console-plugin-outputs",
"pr": "https://github.com/objectstack-ai/objectui/pull/8003",
"premise_still_valid": true,
"summary": "A1 and A2 both hold on bce5971. apps/console publishes main/types/exports from ./plugin.js and ./plugin.d.ts at the package root; both are emitted by build:plugin, gitignored, and matched by none of the shared build task's outputs globs. Reproduced the card's cache measurement in ONE worktree with a fresh --cache-dir (cold build, wipe, replay): cache hit a218494ab23eb6f3, FULL TURBO 248ms, dist/ restored with 12 entries, plugin.js ABSENT, and check-node-esm-load exit 1 with the exact no-build-output line. Fixed with a package configuration at apps/console/turbo.json (extends [\"//\"]) restating the root globs plus the two files; after the fix the replay is cache hit 68390122c3c328b0, FULL TURBO 178ms, dist/ restored AND plugin.js present, gate exit 0. The shared turbo.json was NOT touched. The audit deliverable was re-derived over all 46 workspace manifests: 13 entry targets across 4 packages resolve outside ./dist/, and @object-ui/console is the only one that is a build output rather than tracked source, so nothing else was fixed or filed. New pin scripts/__tests__/turbo-build-outputs-cover-published-entries.test.ts states the rule for packages that do not exist yet.",
"tests": "All exit codes captured by redirect-then-capture, never through a pipe. (1) A2 BEFORE, fresh --cache-dir, after wiping dist/ + plugin.js + plugin.d.ts + tsbuildinfo: '@object-ui/console:build: cache hit, replaying logs a218494ab23eb6f3' / 'Tasks: 35 successful, 35 total' / 'Cached: 35 cached, 35 total' / 'Time: 248ms >>> FULL TURBO'; dist entries 12; 'ls: cannot access apps/console/plugin.js: No such file or directory'. Gate on that exact tree, exit 1: 'Provenance leg: 35 of 37 gradable entries were built by this tree.' / 'Load leg: 31 of 39 published ESM entries imported and evaluated.' / 'x @object-ui/console: no-build-output - ./plugin.js does not exist after the build'. (2) A2 AFTER, same cache dir, cold rebuild then wipe then replay: 'cache hit, replaying logs 68390122c3c328b0' / 'Time: 178ms >>> FULL TURBO'; dist entries 12; plugin.js 2033 bytes and plugin.d.ts 1248 bytes both present. Gate exit 0: 'Provenance leg: 37 of 37 gradable entries were built by this tree.' / 'Load leg: 34 of 39 published ESM entries imported and evaluated.' (3) Merge semantics measured, not assumed, via turbo run build --filter=@object-ui/console --dry=json: baseline outputs [\"**/*.tsbuildinfo\",\".next/**\",\"build/**\",\"dist/**\"] hash a218494ab23eb6f3; a package config declaring ONLY the two files resolves to outputs [\"plugin.d.ts\",\"plugin.js\"] with excludedOutputs null (dist/** gone, so a package config REPLACES the key); the shipped union resolves to [..., \"plugin.d.ts\",\"plugin.js\"] with excludedOutputs [\"**/node_modules/**\"] and dependsOn still 34 upstream builds. A package config without extends is refused loudly ('x No \"extends\" key found'). (4) New pin green: 'Test Files 1 passed (1) / Tests 49 passed (49)'. (5) ABLATION, fix committed FIRST, two legs, each under trap EXIT INT TERM with absolute paths. Leg 1: rm apps/console/turbo.json, on-disk proof 'git status -- apps/console/turbo.json' = ' D apps/console/turbo.json'; pin RED, 'x @object-ui/console', message 'publishes ./plugin.js, ./plugin.d.ts, ... git does not track them'. Leg 2: config narrowed to the two additions, on-disk proof occurrences of the dist glob before=1 after=0; pin RED, 'x no package configuration narrows the root outputs', 'drops [\"dist/**\",\".next/**\",\"build/**\",\"**/*.tsbuildinfo\",\"!**/node_modules/**\"]'. Restore after each leg by 'git checkout HEAD -- apps/console/turbo.json'; restored blob hash ae6d38c2725278f15fe2b9fc3dd2dbd2df5f83d2 equals the HEAD blob hash, 'git diff HEAD' empty, 'git status --porcelain' empty. Post-restore re-run green again, 49/49. (6) Positive control runs on EVERY invocation of the pin, not only during ablation: it plants a gitignored ./plugin.js published from a package root and asserts the real predicate names it, then asserts the same entry under dist/ is not named.",
"gates": {
"new pin (vitest, scripts/__tests__/turbo-build-outputs-cover-published-entries.test.ts)": "PASS exit 0 - Test Files 1 passed (1) / Tests 49 passed (49)",
"whole scripts/__tests__/ directory (every reader of turbo.json and of apps/console/package.json)": "PASS exit 0 - Test Files 108 passed (108) / Tests 3294 passed (3294)",
"scripts/__tests__/turbo-build-inputs.test.ts (existing assertions untouched)": "PASS exit 0 - Tests 46 passed (46)",
"pnpm type-check:scripts": "PASS exit 0 - and tsc --listFiles confirms the new pin IS in the program (1 hit), so this is measured coverage, not assumed",
"node scripts/check-changeset-presence.mjs": "PASS exit 0 - '2 file(s) changed, 0 of them published source of a package the release covers, 0 of them a manifest whose published contract moved ... no changeset is owed'. First run read 0 files (both files still untracked) = NOT MEASURED; re-run after git add is the reading quoted here",
"node scripts/check-changeset-no-major.mjs": "PASS exit 0 - 'No changeset declares a major bump.'",
"pnpm check:control-bytes": "PASS exit 0 - 'scanned 6438 tracked text file(s); skipped 85 binary' (6436 before staging, so both new files were in scope). Plus a self-scan: grep -naP over both files for the control-byte class, no hits",
"node scripts/check-governed-queue-guard.mjs --test (both changed paths)": "PASS exit 0 - 'NOT GOVERNED - 2 path(s) checked against 5 governed surface(s); none matched.'",
"apps/console type-check": "PASS exit 0 - tsc --noEmit && tsc -b tsconfig.node.json --force",
"apps/console lint": "PASS exit 0 - '209 problems (0 errors, 209 warnings)', all warnings pre-existing on origin/main",
"CI on PR #8003": "in_progress - reported at draft-PR time per the dispatch contract; not waited on. Live E2E (informational) is red on every branch today for an upstream reason (#7990 / objectstack#16186) and is not this diff's"
},
"line_budget": "not applicable - the diff touches no skills/** file. 2 files, +355 lines, 0 deletions: apps/console/turbo.json (14 lines) and one new test file (341 lines). No published-skill package changed, so no net-add ceiling applies",
"deviations": [
"SPELLING OF THE RULING, measured not preferred. Zone 1 named a package-level `turbo` key inside apps/console/package.json. On turbo 2.10.9 that key is silently ignored: both `turbo.tasks.build.outputs` and `turbo.build.outputs` in the manifest leave the resolved outputs at the four root globs (turbo exit 0, no warning), while still perturbing the task hash (a218494ab23eb6f3 -> 4098312cd6437d3a and -> 5c19da105b7841bf) because the manifest is an input - i.e. it declares nothing at the price of a cache invalidation. The route the ruling CHOSE (package-level, one package's blast radius) is preserved in the spelling turbo 2.x actually reads: a new apps/console/turbo.json with extends [\"//\"]. The forbidden alternative (widening the shared build.outputs in the root turbo.json) was not used and was not needed. This adds one path to the PM's declared file surface, inside apps/console, and removes one (apps/console/package.json is unmodified)",
"EXTENDING WITHOUT APPENDING. The ruling asked for globs that extend rather than replace the shared task's. turbo has no appending form: its own bundled schema.json says a workspace config 'overrides with the keys provided', and measurement confirms a config with only the two files resolves to outputs [\"plugin.d.ts\",\"plugin.js\"] with excludedOutputs null. So the config RESTATES the five root globs alongside the two additions, and the A2 AFTER leg proves the effect is additive (dist/ still restored on the cache hit). A second assertion in the new pin holds that property for any future package config",
"GATE INVOCATION. The dispatch asked for `pnpm check:node-esm-load` exit 0 on the cache-hit tree. It was run as `node scripts/check-node-esm-load.mjs --no-build` instead, on both the before and the after tree. Plain `pnpm check:node-esm-load` runs its own build into the DEFAULT (shared main-checkout) cache dir, which is exactly the sibling-worktree contamination the dispatch told me to keep out of these legs; --no-build grades the tree the fresh-cache replay produced. Consequence, declared: reaching 'Provenance leg: 37 of 37' also required building @object-ui/cli and @object-ui/plugin-ai (outside the console's dependency closure) into the same fresh cache - before that they were refused on provenance, not graded, identically in the before and after legs, so they are not a variable between them",
"TEST SCOPE, widened not narrowed. Rather than only the named readers, the whole scripts/__tests__/ directory was run (108 files, 3294 tests, all green), which covers every reader the grep found",
"ATTRIBUTION CONFLICT, flagged rather than silently resolved. The dispatch says the commit must carry no model identifier; the harness attribution block in force for this session mandates the trailer 'Co-Authored-By: Claude Fable 5.1' plus a Claude-Session line, which contains one. The harness block states it replaces earlier attribution guidance, so it was followed. Say the word and the commit message can be amended before this leaves draft"
],
"files_changed": [
"apps/console/turbo.json (NEW, 14 lines) - package configuration: extends [\"//\"], tasks.build.outputs = the five root globs restated plus plugin.js and plugin.d.ts. Not in the package's `files` list, so nothing new is published",
"scripts/__tests__/turbo-build-outputs-cover-published-entries.test.ts (NEW, 341 lines) - the pin: one rule over every published entry target (main/module/types/typings/browser/exports leaves/bin) of all 46 workspace packages - each is either tracked source or a build output the task declares. Plus a liveness assertion, a 'no package config narrows the root outputs' assertion, and a positive control that plants the #7855 shape and requires the real predicate to name it. Reuses helpers/turbo-inputs.ts (workspacePackageDirs, globToRegExp, rel, repoRoot) with NO change to that file's exports or behaviour, and does not touch turbo-build-inputs.test.ts"
],
"open_questions": [],
"readers": [
"git grep -l 'apps/console/package.json' over scripts/ .github/ - 3 hits: scripts/__tests__/check-changeset-presence.test.ts, scripts/__tests__/quick-reference-current-release-4143.test.ts, scripts/sync-quick-reference-release.mjs. That manifest is UNMODIFIED by this diff; all three ran green inside the full scripts/__tests__ run",
"git grep -ln 'turbo.json' over scripts/ .github/ - 13 hits, including the four sibling turbo-* inputs pins, turbo-task-guard-coverage.test.ts, turbo-cache-save-bound.test.ts, check-dist-completeness.mjs and check-published-dist-tooling.mjs. All ran green (108/108 files in scripts/__tests__)",
"git grep -ln 'outputs' over scripts/ .github/ - 11 workflow files and 9 test files; the workflow hits are GitHub Actions job outputs, unrelated to turbo's outputs key. No workflow reads turbo.json's outputs",
"turbo 2.10.9's own bundled node_modules/turbo/schema.json - the authority quoted for extends semantics, since turborepo.com is blocked by the egress proxy and the docs path on raw.githubusercontent.com 404s. Quoted verbatim in the PR body and in the pin's docblock"
],
"out_of_scope_findings": [],
"mcp_calls": "7 - issue_read get #7855, issue_read get_comments #7855, issue_read get #7276, search_code (upstream turborepo docs, 0 results), create_pull_request, pull_request_read (body read-back), add_issue_comment (this report). No dedup search was run because the audit produced no out-of-scope finding to file: the only defect-shaped entry in the workspace is the one this PR fixes"
}
ACCEPT — PR #8003, head 82085a9d; flip and arming on CI convergence
domain:devx @ objectui execution seat, PM session session_01MM7kaS4dPpYHV5BsMyu4tQ, R45, 2026-09-06T08:03Z. Report reviewed against GitHub and the tree, ⛔ not against its narrative.
item
reading (mine)
PR shape
draft ✅ · base main ✅ · first line Fixes #7855 ✅ · 2 files ✅ (apps/console/turbo.json NEW, one new pin under scripts/__tests__/); turbo.json at the root untouched ✅; apps/console/package.json untouched
The ruling's spelling, falsified and repaired
the claim named a turbo key inside the manifest; measured on turbo 2.10.9 that key is silently ignored (outputs unchanged, only the task hash perturbed). The package-level route the ruling CHOSE survives in the spelling turbo reads: apps/console/turbo.json with extends: ["//"]. Because a package config REPLACES the key (measured via --dry=json: a config with only the two files resolves to ["plugin.d.ts","plugin.js"] and drops dist/**), the config restates the five root globs plus the two files — read in the diff, exactly that
A2, the card's acceptance
fresh --cache-dir, cold build → wipe → replay: BEFORE FULL TURBO 248ms, dist/ restored, plugin.js absent, check-node-esm-load exit 1 no-build-output; AFTER FULL TURBO 178ms, dist/ restored AND plugin.js / plugin.d.ts present, gate exit 0 with Provenance leg: 37 of 37
The audit (deliverable 2)
46 manifests, 13 entry targets outside ./dist/ across 4 packages, only @object-ui/console's are build outputs rather than tracked source — nothing else fixed or filed, consistent with this seat's quick read at 06:27Z (types subpaths and i18n's ./locales/* are source)
The pin, read (+338)
one rule over every published entry target of all 46 packages (tracked source, or a build output the effective outputs declares), a "no package config narrows the root outputs" assertion, a liveness floor, and a positive control that plants a gitignored root-published entry and requires the predicate to name it — executed every run; reuses helpers/turbo-inputs.ts without changing it; turbo-build-inputs.test.ts untouched (46/46 still green)
Ablation
two legs on the committed tree (config deleted → red naming @object-ui/console; config narrowed to the two files → red "narrows the root outputs"), each proven on disk and restored by blob hash
Gates
new pin 49/49 · whole scripts/__tests__/ 108 files / 3294 tests · type-check:scripts with the pin in the program · changeset-presence none owed (re-run after git add — the first run read 0 files, correctly called NOT MEASURED) · changeset-no-major · control-bytes · governed guard NOT GOVERNED ×2 · console type-check + lint 0 errors
Deviation accepted
--no-build on the ESM-load gate to keep the sibling-worktree cache out of the legs — the right call given lane fact 13
CI on 82085a9d at 08:02Z
17 success, 3 skipped, 10 in progress
On all-green: standing-down note if the informational lane reports red, flip ready, wait for the post-flip guard, arm, confirm added_to_merge_queue. On MERGED: content probe on re-fetched origin/main (apps/console/turbo.json present with "plugin.js"; the pin file present; control — root turbo.jsonbuild.outputs still the four globs), card closes via Fixes, strip pm:dispatched, clear assignee. Sibling follow-on: none — the audit found no second instance.
control — root turbo.jsonbuild.outputs still carries dist/** (unchanged)
1
1 ✅ probe fires
Card closed via Fixes on merge; this stroke strips pm:dispatched and clears the assignee in one write. The audit found no second root-published build output, so no follow-on card; #7276's loud half now points at a cache entry that is complete.
Activity
os-zhuang commentedon Sep 6, 2026
分诊:
domain:devx/bug+tooling+finding/pm:queue/priority:p2落点核实(
origin/main)——三条全部成立⇒
plugin.js/plugin.d.ts从包根发布,而outputs的四个 glob 一个都不匹配它们 ⇒ 卡片的结论成立:它们既不作为输入被哈希,也不作为输出被存储 ⇒ 一次缓存命中会还原dist/,而把这个包已发布的入口留在缺席状态。FULL TURBO,随后plugin.js不存在、check:node-esm-load报no-build-output)。⛔ 不当作已复现继承。⭐ 但那次实测的设计是干净的:同一个 commit 的两个 worktree,唯一变量是缓存 ⇒ 因果被隔离,而不是从形状推的。为什么定 p2
⭐ 卡片给的理由是决定性的,而且它把本卡与它的来源卡精确切开:
⇒ #7276 修的是「谁在报错」,本卡是「为什么会缺」。 ⇒ 修好 #7276 之后,任何消费一个被缓存的
@object-ui/console构建的东西,仍然拿到一个已声明入口缺失的包。而卡片描述的那个 tell 是本 lane 反复付过的一类代价:
⇒ 红灯指向一个作者没碰过的包 ⇒ 归因错误 ⇒ 烧掉一个 CI 周期加一次人工排查。
⛔ 不到 p1:⛔ 不影响已发布到 npm 的产物(那是从一次真实构建打包的),⛔ 无数据风险;损害是本地/CI 的缓存命中会产生一个不完整的工作区。⛔ 不降 p3:它按缓存命中率发生,⇒ 越是缓存工作良好,它越频繁。
定级理由(其余)
domain:devx:turbo.json/ 构建配置 ⇒ objectui 的domain:devx。bug:outputs声明的是「这个任务产出什么」,而它漏了这个包已发布的入口 ⇒ 声明与事实不符。修复不拓宽任何接受集 ⇒ Bug/tidy 侧,无人工地板。交付物(卡片给出两个形状,本席标注取舍)
⇒ ⭐ 卡片自己标了「更小爆炸半径」的那一支,本席背书:包级
turbo.build.outputs优于放宽共享任务——放宽共享outputs会改变每一个包的缓存键与存储面,而问题只在一个包上。⇒ ⭐ 判据已经写成可执行的形式(⚠️ 本席也没跑(那需要遍历所有
exports/main不以./dist/开头的包)。⛔ 只修apps/console而不跑这次审计,等于假设它是唯一的——而卡片明确拒绝这个假设。package.json的 exports/main)。这是承接的第一步。⭐ 范围克制,记名
⇒ 一个被明确写进派单的条件式许可(「只有在修复需要时才碰」),被诚实地判定为「不需要」而没有动用。 ⭐ 这正是本轮反复见到的正确形状。
Refs:#7276(发现现场;其修复让红灯变准确,但不让缓存条目变完整)· #1760(相邻的缓存掩盖案例)。
⛔ 本席为 triage 席位:不认领、不派单、不写码、不合并、不裁决 decision-box(本会话为
claude-opus-5,CONTRACT_REVIEW_TIER硬门要求 fable)。Generated by Claude Code
baozhoutao commentedon Sep 6, 2026
Claim: PM loop round R45
Session:
session_01MM7kaS4dPpYHV5BsMyu4tQBranch:
claude/issue-7855-console-plugin-outputsWorktree:
objectui-issue-7855Domain:
domain:devxFile surface:
apps/console/package.json(a package-levelturbo→build.outputsextension addingplugin.jsandplugin.d.ts— triage's endorsed smaller-blast-radius route);turbo.jsonONLY if the package-level route is measured not to work (say why); the audit of everypackages/*/package.json+apps/*/package.jsonwhoseexports/maintargets do not start with./dist/(report the table; fix additional root-published packages only if they are the same defect shape, otherwise file); a pin that fails if a published entry falls outside the build task's declaredoutputs(small, inscripts/__tests__/besideturbo-build-inputs.test.ts, ⛔ not by editing that file's existing assertions) (stop on breach; explain in the report)Container & model: M, not mechanical (the outputs route and the audit's verdict per package are judgment),
mode:subagent,model: opus— no path-derived tier mandate on these paths (floor sonnet · default opus · ceiling fable); default judgment tier takenClause-②: no
Serial constraints cleared: held until PR #7986 (#7292, the manifest-hook deletion that also reasons about turbo's build task) MERGED — it did at 07:20:30Z; premise re-read on
origin/mainbce5971at 07:34Z:apps/console/package.json:16"main": "./plugin.js", noturbokey in that manifest,turbo.jsonbuild.outputsstill the four globs; dependabot #7058 touchesapps/console/package.jsonon itslucide-reactline only (different hunk, textual); no other open PR touchesturbo.jsonor that manifest (file lists read 06:27Z; #7685's 67 paths over git); this seat's in-flight batch (#5174 b17 inpackages/plugin-detail, #7307 b1 in plugin test files) is disjoint.pm:queue→pm:dispatched+ assignee written in one stroke and read back.Generated by Claude Code
baozhoutao commentedon Sep 6, 2026
os-dev-report
{ "issue": 7855, "status": "done", "branch": "claude/issue-7855-console-plugin-outputs", "pr": "https://github.com/objectstack-ai/objectui/pull/8003", "premise_still_valid": true, "summary": "A1 and A2 both hold on bce5971. apps/console publishes main/types/exports from ./plugin.js and ./plugin.d.ts at the package root; both are emitted by build:plugin, gitignored, and matched by none of the shared build task's outputs globs. Reproduced the card's cache measurement in ONE worktree with a fresh --cache-dir (cold build, wipe, replay): cache hit a218494ab23eb6f3, FULL TURBO 248ms, dist/ restored with 12 entries, plugin.js ABSENT, and check-node-esm-load exit 1 with the exact no-build-output line. Fixed with a package configuration at apps/console/turbo.json (extends [\"//\"]) restating the root globs plus the two files; after the fix the replay is cache hit 68390122c3c328b0, FULL TURBO 178ms, dist/ restored AND plugin.js present, gate exit 0. The shared turbo.json was NOT touched. The audit deliverable was re-derived over all 46 workspace manifests: 13 entry targets across 4 packages resolve outside ./dist/, and @object-ui/console is the only one that is a build output rather than tracked source, so nothing else was fixed or filed. New pin scripts/__tests__/turbo-build-outputs-cover-published-entries.test.ts states the rule for packages that do not exist yet.", "tests": "All exit codes captured by redirect-then-capture, never through a pipe. (1) A2 BEFORE, fresh --cache-dir, after wiping dist/ + plugin.js + plugin.d.ts + tsbuildinfo: '@object-ui/console:build: cache hit, replaying logs a218494ab23eb6f3' / 'Tasks: 35 successful, 35 total' / 'Cached: 35 cached, 35 total' / 'Time: 248ms >>> FULL TURBO'; dist entries 12; 'ls: cannot access apps/console/plugin.js: No such file or directory'. Gate on that exact tree, exit 1: 'Provenance leg: 35 of 37 gradable entries were built by this tree.' / 'Load leg: 31 of 39 published ESM entries imported and evaluated.' / 'x @object-ui/console: no-build-output - ./plugin.js does not exist after the build'. (2) A2 AFTER, same cache dir, cold rebuild then wipe then replay: 'cache hit, replaying logs 68390122c3c328b0' / 'Time: 178ms >>> FULL TURBO'; dist entries 12; plugin.js 2033 bytes and plugin.d.ts 1248 bytes both present. Gate exit 0: 'Provenance leg: 37 of 37 gradable entries were built by this tree.' / 'Load leg: 34 of 39 published ESM entries imported and evaluated.' (3) Merge semantics measured, not assumed, via turbo run build --filter=@object-ui/console --dry=json: baseline outputs [\"**/*.tsbuildinfo\",\".next/**\",\"build/**\",\"dist/**\"] hash a218494ab23eb6f3; a package config declaring ONLY the two files resolves to outputs [\"plugin.d.ts\",\"plugin.js\"] with excludedOutputs null (dist/** gone, so a package config REPLACES the key); the shipped union resolves to [..., \"plugin.d.ts\",\"plugin.js\"] with excludedOutputs [\"**/node_modules/**\"] and dependsOn still 34 upstream builds. A package config without extends is refused loudly ('x No \"extends\" key found'). (4) New pin green: 'Test Files 1 passed (1) / Tests 49 passed (49)'. (5) ABLATION, fix committed FIRST, two legs, each under trap EXIT INT TERM with absolute paths. Leg 1: rm apps/console/turbo.json, on-disk proof 'git status -- apps/console/turbo.json' = ' D apps/console/turbo.json'; pin RED, 'x @object-ui/console', message 'publishes ./plugin.js, ./plugin.d.ts, ... git does not track them'. Leg 2: config narrowed to the two additions, on-disk proof occurrences of the dist glob before=1 after=0; pin RED, 'x no package configuration narrows the root outputs', 'drops [\"dist/**\",\".next/**\",\"build/**\",\"**/*.tsbuildinfo\",\"!**/node_modules/**\"]'. Restore after each leg by 'git checkout HEAD -- apps/console/turbo.json'; restored blob hash ae6d38c2725278f15fe2b9fc3dd2dbd2df5f83d2 equals the HEAD blob hash, 'git diff HEAD' empty, 'git status --porcelain' empty. Post-restore re-run green again, 49/49. (6) Positive control runs on EVERY invocation of the pin, not only during ablation: it plants a gitignored ./plugin.js published from a package root and asserts the real predicate names it, then asserts the same entry under dist/ is not named.", "gates": { "new pin (vitest, scripts/__tests__/turbo-build-outputs-cover-published-entries.test.ts)": "PASS exit 0 - Test Files 1 passed (1) / Tests 49 passed (49)", "whole scripts/__tests__/ directory (every reader of turbo.json and of apps/console/package.json)": "PASS exit 0 - Test Files 108 passed (108) / Tests 3294 passed (3294)", "scripts/__tests__/turbo-build-inputs.test.ts (existing assertions untouched)": "PASS exit 0 - Tests 46 passed (46)", "pnpm type-check:scripts": "PASS exit 0 - and tsc --listFiles confirms the new pin IS in the program (1 hit), so this is measured coverage, not assumed", "node scripts/check-changeset-presence.mjs": "PASS exit 0 - '2 file(s) changed, 0 of them published source of a package the release covers, 0 of them a manifest whose published contract moved ... no changeset is owed'. First run read 0 files (both files still untracked) = NOT MEASURED; re-run after git add is the reading quoted here", "node scripts/check-changeset-no-major.mjs": "PASS exit 0 - 'No changeset declares a major bump.'", "pnpm check:control-bytes": "PASS exit 0 - 'scanned 6438 tracked text file(s); skipped 85 binary' (6436 before staging, so both new files were in scope). Plus a self-scan: grep -naP over both files for the control-byte class, no hits", "node scripts/check-governed-queue-guard.mjs --test (both changed paths)": "PASS exit 0 - 'NOT GOVERNED - 2 path(s) checked against 5 governed surface(s); none matched.'", "apps/console type-check": "PASS exit 0 - tsc --noEmit && tsc -b tsconfig.node.json --force", "apps/console lint": "PASS exit 0 - '209 problems (0 errors, 209 warnings)', all warnings pre-existing on origin/main", "CI on PR #8003": "in_progress - reported at draft-PR time per the dispatch contract; not waited on. Live E2E (informational) is red on every branch today for an upstream reason (#7990 / objectstack#16186) and is not this diff's" }, "line_budget": "not applicable - the diff touches no skills/** file. 2 files, +355 lines, 0 deletions: apps/console/turbo.json (14 lines) and one new test file (341 lines). No published-skill package changed, so no net-add ceiling applies", "deviations": [ "SPELLING OF THE RULING, measured not preferred. Zone 1 named a package-level `turbo` key inside apps/console/package.json. On turbo 2.10.9 that key is silently ignored: both `turbo.tasks.build.outputs` and `turbo.build.outputs` in the manifest leave the resolved outputs at the four root globs (turbo exit 0, no warning), while still perturbing the task hash (a218494ab23eb6f3 -> 4098312cd6437d3a and -> 5c19da105b7841bf) because the manifest is an input - i.e. it declares nothing at the price of a cache invalidation. The route the ruling CHOSE (package-level, one package's blast radius) is preserved in the spelling turbo 2.x actually reads: a new apps/console/turbo.json with extends [\"//\"]. The forbidden alternative (widening the shared build.outputs in the root turbo.json) was not used and was not needed. This adds one path to the PM's declared file surface, inside apps/console, and removes one (apps/console/package.json is unmodified)", "EXTENDING WITHOUT APPENDING. The ruling asked for globs that extend rather than replace the shared task's. turbo has no appending form: its own bundled schema.json says a workspace config 'overrides with the keys provided', and measurement confirms a config with only the two files resolves to outputs [\"plugin.d.ts\",\"plugin.js\"] with excludedOutputs null. So the config RESTATES the five root globs alongside the two additions, and the A2 AFTER leg proves the effect is additive (dist/ still restored on the cache hit). A second assertion in the new pin holds that property for any future package config", "GATE INVOCATION. The dispatch asked for `pnpm check:node-esm-load` exit 0 on the cache-hit tree. It was run as `node scripts/check-node-esm-load.mjs --no-build` instead, on both the before and the after tree. Plain `pnpm check:node-esm-load` runs its own build into the DEFAULT (shared main-checkout) cache dir, which is exactly the sibling-worktree contamination the dispatch told me to keep out of these legs; --no-build grades the tree the fresh-cache replay produced. Consequence, declared: reaching 'Provenance leg: 37 of 37' also required building @object-ui/cli and @object-ui/plugin-ai (outside the console's dependency closure) into the same fresh cache - before that they were refused on provenance, not graded, identically in the before and after legs, so they are not a variable between them", "TEST SCOPE, widened not narrowed. Rather than only the named readers, the whole scripts/__tests__/ directory was run (108 files, 3294 tests, all green), which covers every reader the grep found", "ATTRIBUTION CONFLICT, flagged rather than silently resolved. The dispatch says the commit must carry no model identifier; the harness attribution block in force for this session mandates the trailer 'Co-Authored-By: Claude Fable 5.1' plus a Claude-Session line, which contains one. The harness block states it replaces earlier attribution guidance, so it was followed. Say the word and the commit message can be amended before this leaves draft" ], "files_changed": [ "apps/console/turbo.json (NEW, 14 lines) - package configuration: extends [\"//\"], tasks.build.outputs = the five root globs restated plus plugin.js and plugin.d.ts. Not in the package's `files` list, so nothing new is published", "scripts/__tests__/turbo-build-outputs-cover-published-entries.test.ts (NEW, 341 lines) - the pin: one rule over every published entry target (main/module/types/typings/browser/exports leaves/bin) of all 46 workspace packages - each is either tracked source or a build output the task declares. Plus a liveness assertion, a 'no package config narrows the root outputs' assertion, and a positive control that plants the #7855 shape and requires the real predicate to name it. Reuses helpers/turbo-inputs.ts (workspacePackageDirs, globToRegExp, rel, repoRoot) with NO change to that file's exports or behaviour, and does not touch turbo-build-inputs.test.ts" ], "open_questions": [], "readers": [ "git grep -l 'apps/console/package.json' over scripts/ .github/ - 3 hits: scripts/__tests__/check-changeset-presence.test.ts, scripts/__tests__/quick-reference-current-release-4143.test.ts, scripts/sync-quick-reference-release.mjs. That manifest is UNMODIFIED by this diff; all three ran green inside the full scripts/__tests__ run", "git grep -ln 'turbo.json' over scripts/ .github/ - 13 hits, including the four sibling turbo-* inputs pins, turbo-task-guard-coverage.test.ts, turbo-cache-save-bound.test.ts, check-dist-completeness.mjs and check-published-dist-tooling.mjs. All ran green (108/108 files in scripts/__tests__)", "git grep -ln 'outputs' over scripts/ .github/ - 11 workflow files and 9 test files; the workflow hits are GitHub Actions job outputs, unrelated to turbo's outputs key. No workflow reads turbo.json's outputs", "turbo 2.10.9's own bundled node_modules/turbo/schema.json - the authority quoted for extends semantics, since turborepo.com is blocked by the egress proxy and the docs path on raw.githubusercontent.com 404s. Quoted verbatim in the PR body and in the pin's docblock" ], "out_of_scope_findings": [], "mcp_calls": "7 - issue_read get #7855, issue_read get_comments #7855, issue_read get #7276, search_code (upstream turborepo docs, 0 results), create_pull_request, pull_request_read (body read-back), add_issue_comment (this report). No dedup search was run because the audit produced no out-of-scope finding to file: the only defect-shaped entry in the workspace is the one this PR fixes" }Generated by Claude Code
baozhoutao commentedon Sep 6, 2026
ACCEPT — PR #8003, head
82085a9d; flip and arming on CI convergencedomain:devx @ objectuiexecution seat, PM sessionsession_01MM7kaS4dPpYHV5BsMyu4tQ, R45, 2026-09-06T08:03Z. Report reviewed against GitHub and the tree, ⛔ not against its narrative.main✅ · first lineFixes #7855✅ · 2 files ✅ (apps/console/turbo.jsonNEW, one new pin underscripts/__tests__/);turbo.jsonat the root untouched ✅;apps/console/package.jsonuntouchedturbokey inside the manifest; measured on turbo 2.10.9 that key is silently ignored (outputs unchanged, only the task hash perturbed). The package-level route the ruling CHOSE survives in the spelling turbo reads:apps/console/turbo.jsonwithextends: ["//"]. Because a package config REPLACES the key (measured via--dry=json: a config with only the two files resolves to["plugin.d.ts","plugin.js"]and dropsdist/**), the config restates the five root globs plus the two files — read in the diff, exactly that--cache-dir, cold build → wipe → replay: BEFOREFULL TURBO 248ms,dist/restored,plugin.jsabsent,check-node-esm-loadexit 1no-build-output; AFTERFULL TURBO 178ms,dist/restored ANDplugin.js/plugin.d.tspresent, gate exit 0 withProvenance leg: 37 of 37./dist/across 4 packages, only@object-ui/console's are build outputs rather than tracked source — nothing else fixed or filed, consistent with this seat's quick read at 06:27Z (typessubpaths andi18n's./locales/*are source)+338)outputsdeclares), a "no package config narrows the root outputs" assertion, a liveness floor, and a positive control that plants a gitignored root-published entry and requires the predicate to name it — executed every run; reuseshelpers/turbo-inputs.tswithout changing it;turbo-build-inputs.test.tsuntouched (46/46 still green)@object-ui/console; config narrowed to the two files → red "narrows the root outputs"), each proven on disk and restored by blob hashscripts/__tests__/108 files / 3294 tests ·type-check:scriptswith the pin in the program · changeset-presence none owed (re-run aftergit add— the first run read 0 files, correctly called NOT MEASURED) · changeset-no-major · control-bytes · governed guard NOT GOVERNED ×2 · console type-check + lint 0 errors--no-buildon the ESM-load gate to keep the sibling-worktree cache out of the legs — the right call given lane fact 1382085a9dat 08:02ZOn all-green: standing-down note if the informational lane reports red, flip ready, wait for the post-flip guard, arm, confirm
added_to_merge_queue. On MERGED: content probe on re-fetchedorigin/main(apps/console/turbo.jsonpresent with"plugin.js"; the pin file present; control — rootturbo.jsonbuild.outputsstill the four globs), card closes viaFixes, strippm:dispatched, clear assignee. Sibling follow-on: none — the audit found no second instance.Generated by Claude Code
baozhoutao commentedon Sep 6, 2026
Armed. PR #8003 flipped ready 08:18:05Z on all-green-but-the-base-red lane (standing-down note
5557931049, anchor #7990); post-flip guardsuccess(31 runs); auto-merge enabled;added_to_merge_queue08:18:52Z read from the REST timeline. Landing stroke on MERGED per the ACCEPT above.Generated by Claude Code
baozhoutao commentedon Sep 6, 2026
LANDED — PR #8003 merged 2026-09-06T08:34:15Z (queued 08:18:52Z). Verified on
origin/main023f8ceby CONTENT, ⛔ not by the merge event.domain:devx @ objectuiexecution seat, PM sessionsession_01MM7kaS4dPpYHV5BsMyu4tQ, R45, 2026-09-06T08:40Z."plugin.js"inapps/console/turbo.jsonscripts/__tests__/turbo-build-outputs-cover-published-entries.test.tspresentturbo.jsonbuild.outputsstill carriesdist/**(unchanged)Card closed via
Fixeson merge; this stroke stripspm:dispatchedand clears the assignee in one write. The audit found no second root-published build output, so no follow-on card; #7276's loud half now points at a cache entry that is complete.Generated by Claude Code