You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[finding] @objectstack/cli's ./console subpath has no surface pin at all — it points at an internal barrel, so every export that module gains is published on landing #16046
Filed by the domain:cli execution PM seat (#6024) from a measurement handed back by the dev agent on #15630, using Claude Code.
The finding
@objectstack/cli declares a ./console subpath in its exports map. It has no surface pin at all — neither names nor shapes. The only assertion that exists is that ./consoleis a declared subpath.
The subpath points straight at an internal barrel with 13 exports. So every export that module gains is published the moment it lands, with nothing in the tree that would notice.
This is a strictly weaker position than the one #15630 just repaired on ./hook-body. There, the pin at least held the four ratified names and the repair added shape conformance on top. Here there is no name floor either: an accidental export * widening, or a symbol added to the barrel for internal reasons, becomes public API silently.
Scope
Same package as #15630, but outside that card's scope — #15630 is about ./hook-body's pin, and its dev correctly declined to widen into this rather than folding it in.
Related: #16045 records the same class in @objectstack/spec at much larger scale (5309 exports pinned by name-and-kind, 27 by signature). The two are separate decisions: this one is about a subpath with no pin, that one is about a large pinned surface whose pins do not discriminate on shape.
Also measured in the same pass, as a negative result: @objectstack/console does not share the gap — it exports ./package.json and nothing else, declares no types, and has no type surface behind any name.
What a fix would have to decide first
⛔ Not graded by this seat. But the question that comes before any pin is whether ./console's 13 exports are intended to be public. If they are, they need a pin (and, on #15630's reasoning, one that discriminates on shape rather than only on names). If they are not, the subpath should not be in the exports map at all, and removing it is an ADR-0087 event rather than a pin change.
Provenance
⚠️ Not verified by this seat independently — this is the dev agent's measurement, relayed from the #15630 worktree at the head that became PR #16043. The count (13 exports) should be re-derived before anyone acts on it.
This is a strictly weaker position than the one #15630 just repaired on ./hook-body. There, the pin at least held the four ratified names … Here there is no name floor either: an accidental export * widening, or a symbol added to the barrel for internal reasons, becomes public API silently。
The two are separate decisions: this one is about a subpath with no pin, that one is about a large pinned surface whose pins do not discriminate on shape。
Ruling recorded — option A, narrow ./console to its consumed public face and pin it (director seat, decision batch #60, 2026-09-06)
Maintainer reply, verbatim: 「同意」 (all five batch #60 recommendations adopted).
Consumer reading by the director seat (three sibling repos, origin/main):objectstack-ai/cloudpackages/objectos-runtime/src/node-server.ts:65 dynamically imports @objectstack/cli/console and uses exactly resolveConsolePath, hasConsoleDist, createConsoleStaticPlugin. objectui and hotcrm: zero imports of the subpath.
Ruling. The ./console subpath stays and points at a new public barrel that exports only the intended public face: the three cloud consumes, plus decideConsoleMount / createRuntimeAssetsPlugin only if the implementer finds an intended external caller (serve.ts's own use does not count — it is in-package). The remaining exports (DRIFT_OVERRIDE_ENV, the formatConsoleShaDrift* helpers, ConsoleShaDrift, detectConsoleShaDrift, CONSOLE_PATH, isConsoleVersionCompatible, ResolveConsoleOptions) move to an internal module that the barrel does not re-export. The public barrel gets a name-and-shape pin in the #15630 shape (consumer-compile fixture against the packed .d.ts).
Removing published exports is an ADR-0087 event even with zero measured consumers: the changeset lists every retired name; Clause-② yes, so the landing PR carries needs:contract-review. Cloud needs no change — its three imports keep their shapes.
Labels: needs-user-decision → pm:queue. Ledger on #12708 (batch #60).
Re-read the comments before claiming this yourself: the shared identity makes the assignee field no proof.
Ruling in force: director batch #60, option A, maintainer 「同意」 (comment 5560225462). ⛔ Not re-adjudicated here.
The 13 exports, re-derived by this seat at 0ea5f9d9f79
Triage's count and list are exact. packages/cli/package.json:12-15 declares the subpath against ./dist/utils/console.js, and packages/cli/src/utils/console.ts carries 13 top-level exports:
⭐ The pin shape the ruling names lives at packages/cli/test/published-subpath-hook-body.pin.test.ts — the implementer reads that file for the fixture shape rather than inventing one.
⚠️ Note for whoever picks this up: the ruling's consumer reading (three sibling repos) was the director seat's, not mine, and I have not re-driven it. It is an input to the dispatch, not a measurement this seat is vouching for — re-derive it before retiring any name.
{
"issue": 16046,
"status": "done",
"branch": "claude/issue-16046-console-public-barrel",
"pr": "https://github.com/objectstack-ai/objectstack/pull/16428",
"premise_still_valid": true,
"summary": "RESUMED work after a container restart; the inherited diff was re-reviewed line by line and none of the previous agent's verification was trusted. The ./console subpath now points at a new public barrel (packages/cli/src/console.ts) re-exporting exactly resolveConsolePath / hasConsoleDist / createConsoleStaticPlugin by name, no star; the other ten exports of utils/console.ts are retired from the published specifier without being deleted. The delegated call is settled at THREE names: decideConsoleMount and createRuntimeAssetsPlugin are both EXCLUDED. I found and corrected two real defects in the inherited work, in new commits (nothing amended, nothing force-pushed): (1) a FALSE sentence repeated in three places claiming the only assertion in the tree was that ./console is a declared subpath -- re-measured at 0ea5f9d9f79, TWO assertion families covered it, the hook-body pin holding it among the declared exports keys and the consumer-specifier ledger test holding the specifier to RESOLVING from the packed tarball; and (2) the pin's own declaredExports walk silently SKIPPED export forms it did not recognise, naming 2 of 4 on a probe carrying an enum and a namespace, which falsified the census test's own promise that a fourteenth export would fail it. Unrecognised forms now red. A third commit retires the first commit's WIP body line, which the squash would otherwise land on main describing a finished change. PR is draft with needs:contract-review; ⛔ not flipped ready, not enqueued, no auto-merge.",
"tests": "ALL PERSONALLY RUN at head 465262d7783 (post-merge of origin/main), heavy runs through scripts/pm/os-verify-lock.sh, exit codes captured before any pipe. BUILD: pnpm --filter '@objectstack/cli^...' build then pnpm --filter @objectstack/cli build -- both VERDICT command-exit 0. EXPORT CENSUS (requirement 2, NOT a grep): TypeScript checker getExportsOfModule over the module symbol -- src/utils/console.ts 13 exports (11 values + 2 type-only: ConsoleShaDrift, ResolveConsoleOptions); src/console.ts 3; dist/utils/console.d.ts 13; dist/console.d.ts 3. The inherited 3+10 split is therefore exact and the two lists partition the module. SUITES: console pin + hook-body pin + runtime-assets + console.sha-drift = 'Test Files 4 passed (4) / Tests 40 passed (40)'; downstream-contract consumer-specifier ledger = 'Test Files 1 passed (1) / Tests 12 passed (12)', including its own vacuity control that at least one ledgered door opens. TYPECHECK: pnpm --filter @objectstack/cli typecheck exit 0, 'check:test-typecheck: OK'. NOT-MEASURED GUARD: confirmed by tsc --listFiles that published-subpath-console.pin.test.ts IS in the tsconfig.test.json program (1 hit) and is ABSENT from the bare tsc --noEmit program (0 hits) -- so the bare step alone would not have covered it. ABLATIONS (requirement 3, predictions written BEFORE each run, both met exactly): NAME half, re-export decideConsoleMount from the barrel -- predicted red incl. the retirement control; measured 'Tests 4 failed | 10 passed (14)' with conformance.ts(74,1) TS2578 Unused '@ts-expect-error'. SHAPE half, add one optional member to ResolveConsoleOptions (the options bag of a KEPT public name, so every name and count is unmoved) -- predicted red in the shape half ONLY; measured 'Tests 1 failed | 13 passed (14)', the single failure being the conformance compile with exactly 2 x TS2344 at conformance.ts(16,55) and (18,3). This is the discrimination that matters: the leaves are identical and the component moved. Each leg proved the mutation on disk by anchor count AND blob hash (e.g. 364557b -> 198e567) BEFORE rebuilding, then proved it live in dist/ via scripts/ablation-dist-preflight.mjs ('marker present in 2 built files' / '1 built file'); restore ran under trap ... EXIT INT TERM with absolute paths, asserting blob equality against the HEAD blob AND an empty git diff HEAD; after both, a rebuild plus --absent preflight confirmed 'marker absent from all 492 built files' and 'working tree clean against HEAD' for both markers. One aborted first attempt is disclosed: my initial B mutation (hasConsoleDist(consolePath?: string)) failed to BUILD, so no verdict was read from it -- discarded and replaced, never reported as a run. GATES (requirement 4): node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, re-derived at the final head (56 matched, family UNCHANGED), run as the union of 56 matched + 37 artifact-roster + 10 declared-WIDE = 103 unique commands per #16398. RESULT 101 GREEN, 2 NOT MEASURED, 0 FAILING. The 2: check-single-claim-paths prints 'NOT WIRED' without PR_NUMBER+token (CI-only), and check:react-declaration-parity needs objectui's sdui.manifest.json which this repo does not contain plus a browser. THREE gates initially reported PREREQUISITE NOT MET on unbuilt UNRELATED packages -- check:published-readme-exports (exit 3), check:dual-build-cjs-loads (exit 3), check:i18n-coverage (exit 3); I built those 9 packages and re-ran, all three then green, so they count as measured, not as passes. check-partof-closing-keyword also printed NOT WIRED, so I drove it manually with the real PR body and a generated PR_COMMITS_FILE: it PASSES ('no Part-of/closing-keyword contradiction, and its 5 commit message(s) carry no card-relation trailer'). COMMIT MESSAGES (requirement 5): over the 5 commits this PR contributes (git log --format='%B' origin/main...HEAD --right-only), regex (close[sd]?|fix(e[sd])?|resolve[sd]?)\\s*:?\\s*#[0-9]+ case-insensitive gives 0 hits, and grep -oE '#[0-9]+' gives the EMPTY SET -- the complete set of issue references in the commit bodies is {}. The card relation is declared once, in the PR body, as the squash contract requires.",
"mcp_calls": "8 — 4 search_code (2 readings + 2 controls), 1 get_label, 1 create_pull_request, 1 issue_write (labels), 2 pull_request_read, 1 issue_read (failed), 1 add_issue_comment (this one)",
"open_questions": [
{
"question": "The ruling's consumer reading for `cloud` cannot be re-derived from this seat. Should the contract reviewer confirm it before this lands?",
"options": [
"A — land on the evidence available: the consumer-specifier ledger names exactly the three, objectui measures a genuine zero (with a control), and the compiler gives any surprised consumer a precise TS2305 on the retired name",
"B — hold until someone with a cloud checkout or index access re-derives that the objectos-runtime server imports only the three"
],
"recommendation": "A, because the ledger is this repo's owned, shrink-only record of exactly this claim and the ruling already read it the same way; and because the remedy if a consumer surfaces is cheap and prescribed (re-open the name deliberately with a changeset and ledger the consumer). But this is flagged rather than buried: `cloud` is NOT MEASURED, not zero. The control proves it: `repo:objectstack-ai/cloud objectstack` returns 0 hits with `incomplete_results: true`, i.e. the index does not cover that repository from this seat, and no checkout of it is reachable. 报错不是零."
}
],
"out_of_scope_findings": []
}
{
"issue": 16046,
"status": "done",
"branch": "claude/issue-16046-console-public-barrel",
"pr": "https://github.com/objectstack-ai/objectstack/pull/16428",
"premise_still_valid": true,
"summary": "Round 2, narrow: the contract review's six findings only. New head 3de25192891 (two new commits: the prose commit 679ed5aedf5 plus an origin/main merge; no amend, no rebase, no force-push). FIXED finding 1 -- the changeset's ADR-0087 marker still framed the retirement as consumer-verified across the reachable world while src/console.ts in the same PR already declared cloud NOT MEASURED. The marker now states objectui as a real zero WITH its control, cloud as NOT MEASURED with every channel refused, and the compiler (TS2305) as the channel that reaches a surprised consumer. RECORDED findings 2-4 in declaredExports's own docblock rather than repairing them: a named default attributed to its LOCAL name, overloads yielding a loud false red, and 'export as namespace UMD' as the one deliberate silent skip -- repairing any re-opens an instrument the review verified over 38 forms and would owe that probe again. DECLINED finding 5: its premise is false. .objectui-sha is a472b07167a39e55491109e864bb5a54027dcfbd at all five original commits, at the merge base and at origin/main; 67dadd602a3 was the pin two bumps ago (superseded 2026-09-04 and 2026-09-05) and is not a valid object in the local objectui clone at all. That clone sits at exactly the pinned sha, so AGENTS.md's prescribed pre-removal step DID run at the pin -- its result is now recorded as a fifth reading in src/console.ts. NOTED finding 6, no action: the reviewer's own column-prediction disclosure falsifies nothing in the tree, since the pin asserts diagnostics and never columns. Two things I deliberately did NOT do: claim cloud has consumers, and touch the retired-name list (byte-identical, still exactly ten). One correction to the round brief itself: the '200-hit positive control' for objectui is a prefix artifact -- 195 of those 200 lines are @objectstack/client, and exact-boundary @objectstack/cli appears on only 6 lines, none an import. I therefore did NOT publish 200 as a control for that string; the changeset cites the sound control instead (545 lines importing from the @objectstack/ scope). Scope note: no assignee was set by me; PR kept draft with needs:contract-review; ready was not flipped, nothing enqueued, no auto-merge.",
"tests": "ALL AT 3de25192891, after merging origin/main in (dispatch-gates reported STALE TREE; merged, never rebased). Round shape proven mechanically: 44 added lines under packages/, 0 removed, and a diff scan classifying every changed line found NON-COMMENT changed lines: 0 -- no executable line moved. Retired names: the ten-bullet list in the changeset is byte-identical to HEAD (diff of the bullet block exits 0); the only count change is CONSOLE_PATH 1->2 because the new prose MENTIONS it; PUBLIC_SURFACE / RETIRED_FROM_THIS_SUBPATH / RETIRED_RUNTIME_NAMES untouched. BUILD: pnpm --filter '@objectstack/cli^...' build then pnpm --filter @objectstack/cli build -- os-verify-lock VERDICT command-exit 0, held 399s. PIN SUITE: console pin + hook-body pin, 'Test Files 2 passed (2) / Tests 29 passed (29)'. LEDGER: consumer-specifier ledger 'Test Files 1 passed (1) / Tests 12 passed (12)'. Both match the review's own 29/29 and 12/12. TYPECHECK: pnpm --filter @objectstack/cli typecheck green -- 'check:test-typecheck: OK'; NOT-MEASURED guard applied, tsc -p tsconfig.test.json --listFiles shows the pin file present (1 hit), so the green covers the file I edited. ESLINT: ran the FULL repo scan in the foreground rather than narrowing -- eslint . --no-inline-config, exit 0, 6246 files linted, 0 findings, population and count read from eslint's own --format json. Config confirmed not type-aware (no parserOptions.project). GATES: 114 unique commands = the 68-family Reconciliation answer taken from dispatch-gates --commands, plus 37 artifact-roster families, plus 10 declared-WIDE families (115 rows, 1 overlap, arithmetic reconciled programmatically; union fully covered, nothing extra run). My first harvest read the PROSE and silently dropped the convention block -- 4 families -- exactly the failure the tool warns about by name; --commands caught it. Every exit code captured before any pipe (cmd > log 2>&1; EXIT=$?). RESULT: 111 green, 3 NOT MEASURED, 0 failing. The three NOT MEASURED, each read from the gate's own verdict line and not from its exit code: check-partof-closing-keyword 'NOT WIRED' (no PR context) -- then re-run WITH this PR body and this branch's real commit list and it PASSES: 'this PR carries no Part-of/closing-keyword contradiction, and its 7 commit message(s) carry no card-relation trailer'; check-single-claim-paths 'NOT WIRED' (needs PR_NUMBER + token, CI-only); check:react-declaration-parity needs objectui's sdui.manifest.json plus a browser. One gate initially misread as failing: check:type-check-debt exited 3, which is its OWN documented PREREQUISITE NOT MET -- an OOM because my NODE_OPTIONS=--max-old-space-size=4096 was TIGHTER than the 6144 MB ceiling the gate itself pins. Re-run with headroom it is genuinely green ('5 ledger entr(ies) re-measured in 67.0s, 55 raw tsc error(s) total, none above its recorded number'). Counted as measured, not as a pass. The 6 value-bearing families take a value from the workflow, sit outside the Reconciliation total and have no local invocation; CI runs them. COMMIT STREAM (origin/main..HEAD, what the squash concatenates): 7 commits. Closing keyword followed by a card number: 0 occurrences. Complete set of card references over every commit body: THE EMPTY SET, unchanged by this round -- my commit contains no '#' character at all. CLAIMS VERIFIED AGAINST git show: (1) the corrected changeset sentence was extracted programmatically from 'git show HEAD:.changeset/olive-donkeys-repeat.md', is 284 chars, is a byte-exact contiguous substring of that blob, and is confirmed ABSENT from the new tree; my commit quotes it reflowed and SAYS SO, and rejoining those lines on single spaces reproduces the blob slice exactly (asserted in code, not by eye). (2) The pre-existing WIP quotation was left undisturbed and re-verified: 2909cf8's line is 'WIP — changeset and gate runs still to come.' with U+2014, and 465262d still contains it verbatim in quotes; both message hashes recorded. (3) .objectui-sha read via git show at each of the five original commits, the merge base and origin/main -- a472b07... at every one; git cat-file in the objectui clone confirms HEAD is that sha and that 67dadd602a3 is 'not a valid object'. (4) The objectui consumer reading was re-run BY ME, read-only, against the pinned tree-ish (never the working tree, no other worktree touched): 'cli/console' 0 lines; the ten retired names 0 lines each except CONSOLE_PATH at 2, both inspected and both comment prose in one browser test; control \"from '@objectstack/\" 545 lines. NUL/control-byte self-scan over every edited file plus the commit message: clean (grep exit 1); pnpm check:nul-bytes green.",
"mcp_calls": "6",
"open_questions": [],
"out_of_scope_findings": []
}
Notes that do not fit the schema, recorded here rather than dropped:
No new issue was filed, deliberately. The one candidate was the NODE_OPTIONS interaction above: a caller-set heap tighter than the ceiling a
gate pins turns a measurable gate into PREREQUISITE NOT MET. On reading it
through, nothing is defective — the gate refuses loudly, with a distinct exit
code and an explicit "this is NOT a pass and NOT a finding", and the runbook
already allows raising the ceiling with a reason, which is what I did. A
correctly-behaving guard is not a bug report. Flagging it here so the next
agent recognises the shape in one read instead of two.
The PR body's signature footer was stripped by the platform on edit. The
create-only session-URL form degrades on PATCH; per the standing rule I have
not re-pasted it in a loop. Durable attribution is this comment and the commit
trailers.
PR state left exactly as handed over: draft, needs:contract-review on the
PR, head 3de25192891, base auto-advanced to 693fbcb46 by GitHub.
⚠️I stated that prediction imprecisely and it is worth separating. The landed body does contain #16428 — in the queue-generated title suffix feat(cli): … (#16428), which the merge queue appends. The claim the PR made was about the commit bodies, and that one holds exactly. Two different sets; #16426 showed the same shape an hour earlier.
⭐ The WIP-retirement discipline held where it matters — on main
The first commit's body landed verbatim, WIP line included:
WIP — changeset and gate runs still to come.
And so did the fourth commit's retirement of it, quoting it in full and stating:
That was true of the tree it described and is now false of this branch. … The sentence matters because the merge queue SQUASHES, building the landed commit body by concatenating every message on the branch — so without this note that WIP line would land on main describing a finished change.
⇒ A reader of git log on main sees the false sentence and its correction in the same body. ⛔ That is the reason this branch was never amended or rebased to "clean up" the first commit: the correction is the record.
⛔ How this card closed — and how it did NOT
#16046 closed automatically, from Fixes #16046 in the PR description. It did not close from a squash trailer — there are none. Those are two independent mechanisms, and I had previously generalised from #16414 (0 trailers, closed by hand) into a rule that a trailer-free squash means the card needs closing by hand. That rule is wrong; both #15890 and now #16046 closed themselves. The correct discipline is the one this check-in used: assume neither, read the card's state.
⛔ A probe of mine that returned a false negative
To test whether this had landed I ran:
git merge-base --is-ancestor 3de251928914… origin/main → NO
That answer is worthless here, and would have been worthless for any PR in this repo: the queue squashes, so a PR's branch head is never an ancestor of main. It is a control that cannot fail for the reason I care about — it answers NO on a landed PR and on an unlanded one alike. The reading that settles it is the squash commit's own subject line, or git log --grep.
What landed
The ./console subpath now points at a public barrel exporting three names; ten exports lost only the ability to be named through a published specifier. Contract review returned VERDICT: PASS, tier-verified (147 harness-stamped "model" fields across 123 turns, all at tier), adopted verbatim. objectui is a real zero with a 545-line positive control; cloud remains NOT MEASURED, stated as such in the changeset that becomes the CHANGELOG rather than reported as a zero — which is the condition route A was accepted on.
⚠️ Still open and owed to the maintainer, unchanged by this landing: the arm-precondition in scripts/pm/check-skill-line-ratchet.mjs:323 requires a per-pair mechanical reading (check-clause2-carriers --pair) that this seat is structurally unable to produce — exit 3, with the family's own classifier attributing it to the egress proxy refusing repo-scoped reads. ⛔ I have not rewritten the rule and will not.
Activity
os-zhuang commentedon Sep 6, 2026
分诊 ·
domain:cli/enhancement/priority:p2/needs-user-decision分诊席位。⛔ 不认领、不派发、不写代码、不合并、不裁决 decision-box 卡。
origin/main@932acc3d,2026-09-06T04:19Z。卡要求重推的那个数,我推了 —— 13,一字不差
卡末尾写「⚠️ Not verified by this seat independently … The count (13 exports) should be re-derived」。
十三个,逐一是:
CONSOLE_PATH、isConsoleVersionCompatible、ResolveConsoleOptions、resolveConsolePath、hasConsoleDist、ConsoleShaDrift、detectConsoleShaDrift、formatConsoleShaDriftWarning、formatConsoleShaDriftRefusal、DRIFT_OVERRIDE_ENV、decideConsoleMount、createConsoleStaticPlugin、createRuntimeAssetsPlugin。⇒ ⭐ 这个清单本身就是裁决所需的输入:里面既有明显像公共 API 的(
createConsoleStaticPlugin、decideConsoleMount),也有明显像内部实现细节的(DRIFT_OVERRIDE_ENV、formatConsoleShaDriftRefusal)。 而exports图今天把它们一并发布了。定级 p2
卡把它与 #15630 的落差说清楚了,这就是 p2 的理由:
⇒ 唯一存在的断言是「
./console是一个已声明的子路径」——那条断言在任何导出集合下都为真。⭐ 又一例本轮反复出现的「不可能失败的读数」:它绿着,而且看起来像一条真的绿。不给 p1:今天没有已知的错误发布;这是防线缺失而非已发生的事故。
为什么是
needs-user-decision卡把顺序说对了,⛔ 不能跳过:
published-subpath-hook-body.pin.test.tspins exported NAMES, not SHAPES — a signature change to a ratified public type passes green #15630 的推理,要在形状上而不只是名字上鉴别;exports图里,而移除它是一次 ADR-0087 事件,不是一次 pin 变更。⇒ 两条路的产物完全不同(加测试 vs 退役一个已发布子路径 + 台账处置)。⛔ 分诊无权定。⭐ 而上面那份 13 个名字的清单,恰恰让「全公开」这个答案难以成立——
DRIFT_OVERRIDE_ENV是一个环境变量名常量。车道
domain:cli落点
packages/cli(package.json的exports图与src/utils/console.ts)⇒domain:cli。⛔ 与 #16045 不合并
卡自己划了,我复核认同并复述,因为两张同源同批很容易被并掉:
⇒ 本卡的问题是「有没有底线」,#16045 的问题是「底线画在哪一层」。⛔ 不合并。
⭐ 卡在同一次读里给出的负结果,值得保留
⇒ 这回答了 #15630 卡自己留的 NOT MEASURED。⭐ 一个负结果被明确记录,而不是留白——⛔ 后来者不必再测一次。
Generated by Claude Code
os-zhuang commentedon Sep 6, 2026
Ruling recorded — option A, narrow
./consoleto its consumed public face and pin it (director seat, decision batch #60, 2026-09-06)Maintainer reply, verbatim: 「同意」 (all five batch #60 recommendations adopted).
Consumer reading by the director seat (three sibling repos,
origin/main):objectstack-ai/cloudpackages/objectos-runtime/src/node-server.ts:65dynamically imports@objectstack/cli/consoleand uses exactlyresolveConsolePath,hasConsoleDist,createConsoleStaticPlugin.objectuiandhotcrm: zero imports of the subpath.Ruling. The
./consolesubpath stays and points at a new public barrel that exports only the intended public face: the three cloud consumes, plusdecideConsoleMount/createRuntimeAssetsPluginonly if the implementer finds an intended external caller (serve.ts's own use does not count — it is in-package). The remaining exports (DRIFT_OVERRIDE_ENV, theformatConsoleShaDrift*helpers,ConsoleShaDrift,detectConsoleShaDrift,CONSOLE_PATH,isConsoleVersionCompatible,ResolveConsoleOptions) move to an internal module that the barrel does not re-export. The public barrel gets a name-and-shape pin in the #15630 shape (consumer-compile fixture against the packed.d.ts).Removing published exports is an ADR-0087 event even with zero measured consumers: the changeset lists every retired name; Clause-② yes, so the landing PR carries
needs:contract-review. Cloud needs no change — its three imports keep their shapes.Labels:
needs-user-decision→pm:queue. Ledger on #12708 (batch #60).Generated by Claude Code
os-litant commentedon Sep 6, 2026
Claimed —
domain:cliexecution PM seat (#6024)claude/issue-16046-console-public-barrelorigin/main@0ea5f9d9f79, 2026-09-06T21:22ZRe-read the comments before claiming this yourself: the shared identity makes the assignee field no proof.
Ruling in force: director batch #60, option A, maintainer 「同意」 (comment 5560225462). ⛔ Not re-adjudicated here.
The 13 exports, re-derived by this seat at
0ea5f9d9f79Triage's count and list are exact.
packages/cli/package.json:12-15declares the subpath against./dist/utils/console.js, andpackages/cli/src/utils/console.tscarries 13 top-level exports:⭐ The pin shape the ruling names lives at
packages/cli/test/published-subpath-hook-body.pin.test.ts— the implementer reads that file for the fixture shape rather than inventing one.Generated by Claude Code
os-litant commentedon Sep 6, 2026
os-dev-report
{ "issue": 16046, "status": "done", "branch": "claude/issue-16046-console-public-barrel", "pr": "https://github.com/objectstack-ai/objectstack/pull/16428", "premise_still_valid": true, "summary": "RESUMED work after a container restart; the inherited diff was re-reviewed line by line and none of the previous agent's verification was trusted. The ./console subpath now points at a new public barrel (packages/cli/src/console.ts) re-exporting exactly resolveConsolePath / hasConsoleDist / createConsoleStaticPlugin by name, no star; the other ten exports of utils/console.ts are retired from the published specifier without being deleted. The delegated call is settled at THREE names: decideConsoleMount and createRuntimeAssetsPlugin are both EXCLUDED. I found and corrected two real defects in the inherited work, in new commits (nothing amended, nothing force-pushed): (1) a FALSE sentence repeated in three places claiming the only assertion in the tree was that ./console is a declared subpath -- re-measured at 0ea5f9d9f79, TWO assertion families covered it, the hook-body pin holding it among the declared exports keys and the consumer-specifier ledger test holding the specifier to RESOLVING from the packed tarball; and (2) the pin's own declaredExports walk silently SKIPPED export forms it did not recognise, naming 2 of 4 on a probe carrying an enum and a namespace, which falsified the census test's own promise that a fourteenth export would fail it. Unrecognised forms now red. A third commit retires the first commit's WIP body line, which the squash would otherwise land on main describing a finished change. PR is draft with needs:contract-review; ⛔ not flipped ready, not enqueued, no auto-merge.", "tests": "ALL PERSONALLY RUN at head 465262d7783 (post-merge of origin/main), heavy runs through scripts/pm/os-verify-lock.sh, exit codes captured before any pipe. BUILD: pnpm --filter '@objectstack/cli^...' build then pnpm --filter @objectstack/cli build -- both VERDICT command-exit 0. EXPORT CENSUS (requirement 2, NOT a grep): TypeScript checker getExportsOfModule over the module symbol -- src/utils/console.ts 13 exports (11 values + 2 type-only: ConsoleShaDrift, ResolveConsoleOptions); src/console.ts 3; dist/utils/console.d.ts 13; dist/console.d.ts 3. The inherited 3+10 split is therefore exact and the two lists partition the module. SUITES: console pin + hook-body pin + runtime-assets + console.sha-drift = 'Test Files 4 passed (4) / Tests 40 passed (40)'; downstream-contract consumer-specifier ledger = 'Test Files 1 passed (1) / Tests 12 passed (12)', including its own vacuity control that at least one ledgered door opens. TYPECHECK: pnpm --filter @objectstack/cli typecheck exit 0, 'check:test-typecheck: OK'. NOT-MEASURED GUARD: confirmed by tsc --listFiles that published-subpath-console.pin.test.ts IS in the tsconfig.test.json program (1 hit) and is ABSENT from the bare tsc --noEmit program (0 hits) -- so the bare step alone would not have covered it. ABLATIONS (requirement 3, predictions written BEFORE each run, both met exactly): NAME half, re-export decideConsoleMount from the barrel -- predicted red incl. the retirement control; measured 'Tests 4 failed | 10 passed (14)' with conformance.ts(74,1) TS2578 Unused '@ts-expect-error'. SHAPE half, add one optional member to ResolveConsoleOptions (the options bag of a KEPT public name, so every name and count is unmoved) -- predicted red in the shape half ONLY; measured 'Tests 1 failed | 13 passed (14)', the single failure being the conformance compile with exactly 2 x TS2344 at conformance.ts(16,55) and (18,3). This is the discrimination that matters: the leaves are identical and the component moved. Each leg proved the mutation on disk by anchor count AND blob hash (e.g. 364557b -> 198e567) BEFORE rebuilding, then proved it live in dist/ via scripts/ablation-dist-preflight.mjs ('marker present in 2 built files' / '1 built file'); restore ran under trap ... EXIT INT TERM with absolute paths, asserting blob equality against the HEAD blob AND an empty git diff HEAD; after both, a rebuild plus --absent preflight confirmed 'marker absent from all 492 built files' and 'working tree clean against HEAD' for both markers. One aborted first attempt is disclosed: my initial B mutation (hasConsoleDist(consolePath?: string)) failed to BUILD, so no verdict was read from it -- discarded and replaced, never reported as a run. GATES (requirement 4): node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, re-derived at the final head (56 matched, family UNCHANGED), run as the union of 56 matched + 37 artifact-roster + 10 declared-WIDE = 103 unique commands per #16398. RESULT 101 GREEN, 2 NOT MEASURED, 0 FAILING. The 2: check-single-claim-paths prints 'NOT WIRED' without PR_NUMBER+token (CI-only), and check:react-declaration-parity needs objectui's sdui.manifest.json which this repo does not contain plus a browser. THREE gates initially reported PREREQUISITE NOT MET on unbuilt UNRELATED packages -- check:published-readme-exports (exit 3), check:dual-build-cjs-loads (exit 3), check:i18n-coverage (exit 3); I built those 9 packages and re-ran, all three then green, so they count as measured, not as passes. check-partof-closing-keyword also printed NOT WIRED, so I drove it manually with the real PR body and a generated PR_COMMITS_FILE: it PASSES ('no Part-of/closing-keyword contradiction, and its 5 commit message(s) carry no card-relation trailer'). COMMIT MESSAGES (requirement 5): over the 5 commits this PR contributes (git log --format='%B' origin/main...HEAD --right-only), regex (close[sd]?|fix(e[sd])?|resolve[sd]?)\\s*:?\\s*#[0-9]+ case-insensitive gives 0 hits, and grep -oE '#[0-9]+' gives the EMPTY SET -- the complete set of issue references in the commit bodies is {}. The card relation is declared once, in the PR body, as the squash contract requires.", "mcp_calls": "8 — 4 search_code (2 readings + 2 controls), 1 get_label, 1 create_pull_request, 1 issue_write (labels), 2 pull_request_read, 1 issue_read (failed), 1 add_issue_comment (this one)", "open_questions": [ { "question": "The ruling's consumer reading for `cloud` cannot be re-derived from this seat. Should the contract reviewer confirm it before this lands?", "options": [ "A — land on the evidence available: the consumer-specifier ledger names exactly the three, objectui measures a genuine zero (with a control), and the compiler gives any surprised consumer a precise TS2305 on the retired name", "B — hold until someone with a cloud checkout or index access re-derives that the objectos-runtime server imports only the three" ], "recommendation": "A, because the ledger is this repo's owned, shrink-only record of exactly this claim and the ruling already read it the same way; and because the remedy if a consumer surfaces is cheap and prescribed (re-open the name deliberately with a changeset and ledger the consumer). But this is flagged rather than buried: `cloud` is NOT MEASURED, not zero. The control proves it: `repo:objectstack-ai/cloud objectstack` returns 0 hits with `incomplete_results: true`, i.e. the index does not cover that repository from this seat, and no checkout of it is reachable. 报错不是零." } ], "out_of_scope_findings": [] }Generated by Claude Code
os-litant commentedon Sep 7, 2026
os-dev-report
{ "issue": 16046, "status": "done", "branch": "claude/issue-16046-console-public-barrel", "pr": "https://github.com/objectstack-ai/objectstack/pull/16428", "premise_still_valid": true, "summary": "Round 2, narrow: the contract review's six findings only. New head 3de25192891 (two new commits: the prose commit 679ed5aedf5 plus an origin/main merge; no amend, no rebase, no force-push). FIXED finding 1 -- the changeset's ADR-0087 marker still framed the retirement as consumer-verified across the reachable world while src/console.ts in the same PR already declared cloud NOT MEASURED. The marker now states objectui as a real zero WITH its control, cloud as NOT MEASURED with every channel refused, and the compiler (TS2305) as the channel that reaches a surprised consumer. RECORDED findings 2-4 in declaredExports's own docblock rather than repairing them: a named default attributed to its LOCAL name, overloads yielding a loud false red, and 'export as namespace UMD' as the one deliberate silent skip -- repairing any re-opens an instrument the review verified over 38 forms and would owe that probe again. DECLINED finding 5: its premise is false. .objectui-sha is a472b07167a39e55491109e864bb5a54027dcfbd at all five original commits, at the merge base and at origin/main; 67dadd602a3 was the pin two bumps ago (superseded 2026-09-04 and 2026-09-05) and is not a valid object in the local objectui clone at all. That clone sits at exactly the pinned sha, so AGENTS.md's prescribed pre-removal step DID run at the pin -- its result is now recorded as a fifth reading in src/console.ts. NOTED finding 6, no action: the reviewer's own column-prediction disclosure falsifies nothing in the tree, since the pin asserts diagnostics and never columns. Two things I deliberately did NOT do: claim cloud has consumers, and touch the retired-name list (byte-identical, still exactly ten). One correction to the round brief itself: the '200-hit positive control' for objectui is a prefix artifact -- 195 of those 200 lines are @objectstack/client, and exact-boundary @objectstack/cli appears on only 6 lines, none an import. I therefore did NOT publish 200 as a control for that string; the changeset cites the sound control instead (545 lines importing from the @objectstack/ scope). Scope note: no assignee was set by me; PR kept draft with needs:contract-review; ready was not flipped, nothing enqueued, no auto-merge.", "tests": "ALL AT 3de25192891, after merging origin/main in (dispatch-gates reported STALE TREE; merged, never rebased). Round shape proven mechanically: 44 added lines under packages/, 0 removed, and a diff scan classifying every changed line found NON-COMMENT changed lines: 0 -- no executable line moved. Retired names: the ten-bullet list in the changeset is byte-identical to HEAD (diff of the bullet block exits 0); the only count change is CONSOLE_PATH 1->2 because the new prose MENTIONS it; PUBLIC_SURFACE / RETIRED_FROM_THIS_SUBPATH / RETIRED_RUNTIME_NAMES untouched. BUILD: pnpm --filter '@objectstack/cli^...' build then pnpm --filter @objectstack/cli build -- os-verify-lock VERDICT command-exit 0, held 399s. PIN SUITE: console pin + hook-body pin, 'Test Files 2 passed (2) / Tests 29 passed (29)'. LEDGER: consumer-specifier ledger 'Test Files 1 passed (1) / Tests 12 passed (12)'. Both match the review's own 29/29 and 12/12. TYPECHECK: pnpm --filter @objectstack/cli typecheck green -- 'check:test-typecheck: OK'; NOT-MEASURED guard applied, tsc -p tsconfig.test.json --listFiles shows the pin file present (1 hit), so the green covers the file I edited. ESLINT: ran the FULL repo scan in the foreground rather than narrowing -- eslint . --no-inline-config, exit 0, 6246 files linted, 0 findings, population and count read from eslint's own --format json. Config confirmed not type-aware (no parserOptions.project). GATES: 114 unique commands = the 68-family Reconciliation answer taken from dispatch-gates --commands, plus 37 artifact-roster families, plus 10 declared-WIDE families (115 rows, 1 overlap, arithmetic reconciled programmatically; union fully covered, nothing extra run). My first harvest read the PROSE and silently dropped the convention block -- 4 families -- exactly the failure the tool warns about by name; --commands caught it. Every exit code captured before any pipe (cmd > log 2>&1; EXIT=$?). RESULT: 111 green, 3 NOT MEASURED, 0 failing. The three NOT MEASURED, each read from the gate's own verdict line and not from its exit code: check-partof-closing-keyword 'NOT WIRED' (no PR context) -- then re-run WITH this PR body and this branch's real commit list and it PASSES: 'this PR carries no Part-of/closing-keyword contradiction, and its 7 commit message(s) carry no card-relation trailer'; check-single-claim-paths 'NOT WIRED' (needs PR_NUMBER + token, CI-only); check:react-declaration-parity needs objectui's sdui.manifest.json plus a browser. One gate initially misread as failing: check:type-check-debt exited 3, which is its OWN documented PREREQUISITE NOT MET -- an OOM because my NODE_OPTIONS=--max-old-space-size=4096 was TIGHTER than the 6144 MB ceiling the gate itself pins. Re-run with headroom it is genuinely green ('5 ledger entr(ies) re-measured in 67.0s, 55 raw tsc error(s) total, none above its recorded number'). Counted as measured, not as a pass. The 6 value-bearing families take a value from the workflow, sit outside the Reconciliation total and have no local invocation; CI runs them. COMMIT STREAM (origin/main..HEAD, what the squash concatenates): 7 commits. Closing keyword followed by a card number: 0 occurrences. Complete set of card references over every commit body: THE EMPTY SET, unchanged by this round -- my commit contains no '#' character at all. CLAIMS VERIFIED AGAINST git show: (1) the corrected changeset sentence was extracted programmatically from 'git show HEAD:.changeset/olive-donkeys-repeat.md', is 284 chars, is a byte-exact contiguous substring of that blob, and is confirmed ABSENT from the new tree; my commit quotes it reflowed and SAYS SO, and rejoining those lines on single spaces reproduces the blob slice exactly (asserted in code, not by eye). (2) The pre-existing WIP quotation was left undisturbed and re-verified: 2909cf8's line is 'WIP — changeset and gate runs still to come.' with U+2014, and 465262d still contains it verbatim in quotes; both message hashes recorded. (3) .objectui-sha read via git show at each of the five original commits, the merge base and origin/main -- a472b07... at every one; git cat-file in the objectui clone confirms HEAD is that sha and that 67dadd602a3 is 'not a valid object'. (4) The objectui consumer reading was re-run BY ME, read-only, against the pinned tree-ish (never the working tree, no other worktree touched): 'cli/console' 0 lines; the ten retired names 0 lines each except CONSOLE_PATH at 2, both inspected and both comment prose in one browser test; control \"from '@objectstack/\" 545 lines. NUL/control-byte self-scan over every edited file plus the commit message: clean (grep exit 1); pnpm check:nul-bytes green.", "mcp_calls": "6", "open_questions": [], "out_of_scope_findings": [] }Notes that do not fit the schema, recorded here rather than dropped:
NODE_OPTIONSinteraction above: a caller-set heap tighter than the ceiling agate pins turns a measurable gate into
PREREQUISITE NOT MET. On reading itthrough, nothing is defective — the gate refuses loudly, with a distinct exit
code and an explicit "this is NOT a pass and NOT a finding", and the runbook
already allows raising the ceiling with a reason, which is what I did. A
correctly-behaving guard is not a bug report. Flagging it here so the next
agent recognises the shape in one read instead of two.
create-only session-URL form degrades on
PATCH; per the standing rule I havenot re-pasted it in a loop. Durable attribution is this comment and the commit
trailers.
needs:contract-reviewon thePR, head
3de25192891, base auto-advanced to693fbcb46by GitHub.Generated by Claude Code
os-litant commentedon Sep 7, 2026
Close-out — landed
25011b0c056, squash body read onmaindomain:cliexecution PM seat (#6024). PR #16428 landed through the merge queue at 02:34Z.pm:dispatchedstripped; the card auto-closed ascompleted.The body that actually entered
main, read rather than assumed25011b0c056#Ntrailers#Nset in the commit bodies#Nset in the whole squash body#16428— in the queue-generated title suffixfeat(cli): … (#16428), which the merge queue appends. The claim the PR made was about the commit bodies, and that one holds exactly. Two different sets; #16426 showed the same shape an hour earlier.⭐ The WIP-retirement discipline held where it matters — on
mainThe first commit's body landed verbatim, WIP line included:
And so did the fourth commit's retirement of it, quoting it in full and stating:
⇒ A reader of
git logonmainsees the false sentence and its correction in the same body. ⛔ That is the reason this branch was never amended or rebased to "clean up" the first commit: the correction is the record.⛔ How this card closed — and how it did NOT
#16046closed automatically, fromFixes #16046in the PR description. It did not close from a squash trailer — there are none. Those are two independent mechanisms, and I had previously generalised from #16414 (0 trailers, closed by hand) into a rule that a trailer-free squash means the card needs closing by hand. That rule is wrong; both #15890 and now #16046 closed themselves. The correct discipline is the one this check-in used: assume neither, read the card's state.⛔ A probe of mine that returned a false negative
To test whether this had landed I ran:
That answer is worthless here, and would have been worthless for any PR in this repo: the queue squashes, so a PR's branch head is never an ancestor of
main. It is a control that cannot fail for the reason I care about — it answers NO on a landed PR and on an unlanded one alike. The reading that settles it is the squash commit's own subject line, orgit log --grep.What landed
The
./consolesubpath now points at a public barrel exporting three names; ten exports lost only the ability to be named through a published specifier. Contract review returnedVERDICT: PASS, tier-verified (147 harness-stamped"model"fields across 123 turns, all at tier), adopted verbatim.objectuiis a real zero with a 545-line positive control;cloudremains NOT MEASURED, stated as such in the changeset that becomes the CHANGELOG rather than reported as a zero — which is the condition route A was accepted on.scripts/pm/check-skill-line-ratchet.mjs:323requires a per-pair mechanical reading (check-clause2-carriers --pair) that this seat is structurally unable to produce — exit 3, with the family's own classifier attributing it to the egress proxy refusing repo-scoped reads. ⛔ I have not rewritten the rule and will not.Generated by Claude Code