Repository navigation
Declare the 9 @objectstack/* packages test/ imports but package.json does not (epic #1579, step 5 item 4 — needs no release) #1769
Description
Activity
- addedpm:epicParent delegated to a dedicated epic PM — other PMs never dispatch into its subtreeParent delegated to a dedicated epic PM — other PMs never dispatch into its subtree
on Sep 8, 2026 - addedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatch
on Sep 8, 2026 Claim:epic PMsession_01DuzfS5chho38Yx1jxx9DEj→ dev branchclaude/issue-1769-declare-objectstack-depsDispatched by the epic PM for #1579. The assignee and this claim are set by the PM; the dev inherits both — ⛔ post no second claim and ⛔ never write the assignee field.
Base:
origin/maine5cedc7at dispatch time; ⛔ confirm your own base SHA rather than assuming this one, and re-derive the nine from your base.
Generated by Claude Code
os-dev-report
{
"issue": 1769,
"status": "done",
"branch": "claude/issue-1769-declare-objectstack-deps",
"pr": "#1771",
"premise_still_valid": true,
"summary": "Declared the nine@objectstack/*packages that files under test/ import but package.json did not, at exact 17.3.0 in thedependenciesblock, alphabetically placed, no caret; then a plainpnpm install(no --force, no regeneration) wrote nineimporters:entries and nothing else. The nine were re-derived on my own base e5cedc7 rather than transcribed from #1595, and matched the card list exactly. Placement was measured, not assumed: eleven of the twelve already-declared@objectstack/*live independenciesincluding several that only test/ imports (driver-memory, driver-sql, metadata, service-automation), sodependenciesis the block the convention points at and@objectstack/formulastays the lone devDependency, untouched. Diff is exactly three files: package.json, pnpm-lock.yaml, and one empty-frontmatter changeset; no test, metadata, helper or content/docs/releases/ file touched. Claim verified before the first edit: the newest (and only)Claim:on the card, comment 5580676505, names this branch; assignee os-steve was inherited and never written. ONE CARD PREMISE DID NOT SURVIVE, reported rather than quietly matched: the Acceptance section predicts the base lint verdict is errors:0 warnings:17 suggestions:12, but on e5cedc7 — the same SHA the card names —pnpm lintmeasures errors:0 warnings:1 suggestions:12, exit 0. The binding half of that criterion (reproduce the base verdict, paired with a pre-change run) is satisfied exactly; only the parenthesised count in the card is stale, and nothing in this PR moves it.",
"tests": "ALL PAIRED WITH PRE-CHANGE CONTROLS, same command, same session, on worktree /home/user/hotcrm-issue-1769 (base e5cedc7, final commit c06e130). (1) RESOLUTION NEUTRALITY, the cards own pipelinesed -n /^packages:/,$p | git hash-object --stdin: base e5cedc7 = 95bfe9b47789dda033387104270392f014c6fb47, HEAD c06e130 = 95bfe9b47789dda033387104270392f014c6fb47, post-install working copy = 95bfe9b47789dda033387104270392f014c6fb47 — byte-identical three ways. Whole-file lock blob moves 1f445a4b5be4cfcacfe77e7aa7ebe81537ba69e9 -> aef9cab5c356264d5c10040e8e7d142ddac463a1, andgit diff -U0shows all four hunks insideimporters:(@@ -16,0 +17,3 @@ / -31,0 +35,15 / -40,0 +59,6 / -43,0 +68,3, all taggedimporters:;packages:starts at line 83 of the base).git diff --numstaton the lock = 27 insertions, 0 deletions. The baseline install printedLockfile is up to date, resolution step is skippedand left git status clean, so the control is a real no-op. (2) BETTER-AUTH GUARD (objectstack#16186):node -p require(./node_modules/@better-auth/core/package.json).version= 1.7.2 BEFORE and 1.7.2 AFTER; the export the patch release removed is present in what is installed — exports[./db] = {dev-source: ./src/db/index.ts, types: ./dist/db/index.d.mts, default: ./dist/db/index.mjs}. All nine self-report 17.3.0 from node_modules after install, same as before. (3) ACCEPTANCE GAP CHECK: the cardscomm -23of imported-minus-declared prints 0 lines after the change (19 imported from test+scripts, 12 declared before, gap of exactly the 9 named). (4)pnpm test, both runs through the containers shared heavy-verify lock, verdict read from the entry points VERDICT line and never a bare $?: BEFORE (clean base, no edit) Test Files 164 passed (164), Tests 3438 passed | 1 skipped (3439),VERDICT command-exit 0 · held the lock 290s. AFTER (final commit c06e130, clean tree) Test Files 164 passed (164), Tests 3438 passed | 1 skipped (3439),VERDICT command-exit 0 · held the lock 233s. The after-run was deliberately repeated ON the final commit because the changeset file landed after the first post-change run and several tests read .changeset/. (5)objectstack lint(pnpm lint): BEFORE1 warning(s), 12 suggestion(s)exit 0; AFTER, on the final commit,1 warning(s), 12 suggestion(s)exit 0 — and adiffof the two full logs with only the elapsed-ms field normalised is EMPTY (same single sales_home_page/page:card warning, same twelve suggestions, same hidden-platform-i18n line). (6) CHANGESET: empty ---/--- frontmatter; the workflows own validation steppnpm changeset status --since=e5cedc7...exits 0 withPackages to be bumped:empty. (7) OTHER GATES on the final commit, exit codes captured by redirecting first and never through a pipe: pnpm typecheck 0, pnpm hygiene 0, pnpm hygiene:tokens 0 (re-run after the changeset landed since it is the ratchet reading — ~136,794 of ~140,000 tokens), pnpm lint:i18n-gate 0, pnpm validate 0, pnpm build 0 (artifact reportsRuntime: 0 plugins, i.e. declaring the plugin packages auto-loaded nothing new into the built app). NO ABLATION: this card adds no guard and no assertion — it is a declaration-only diff — so there is nothing whose failure mode could be proved by mutation, and I did not manufacture one. Control-character scangrep -naPover every authored/edited file and every GitHub body: clean. PR body read back from the API after creation and compared byte-for-byte to what was sent: identical except the trailing newline GitHub strips; the rule line and session-URL footer both survived.", "mcp_calls": "2 — bothsearch_issues, and both only for the out-of-scope duplicate check (one for the finding, one control query that hit objectstack#16186, proving search was live in this session and the empty result was a real reading). Everything else — reading the card and its comments, creating the draft PR, filing the finding, posting this report — went through repo-scoped REST after a probe returned HTTP 200, plus git.", "open_questions": [], "out_of_scope_findings": [ "filed as objectstack-ai/objectstack#16813 (no assignee, no labels, for PM triage): @objectstack/cli 17.3.0 pulls better-sqlite3 13.0.3 into the subtree where its transitive better-auth@1.7.2 declares peer better-sqlite3@^12.0.0, so every install that actually runs resolution warnsunmet peer`. Pre-existing on e5cedc7 (both the better-sqlite3@13.0.3 entry and the better-auth@1.7.2(better-sqlite3@13.0.3) snapshot key are already in the base lock) and unmoved by this PR, which is what the byte-identical packages: hash proves. Not fixable downstream: the mismatch is entirely inside the platform tree, while hotcrm own app path binds better-sqlite3@12.11.1 and is fine. Filed upstream where a fix would land, per hotcrm pure-metadata-app rule, with a backlink to #1769 and PR #1771."
]
}
Generated by Claude Code
ACCEPTED — PR #1771 ready, auto-merge armed. ⭐ And the one premise that did not survive was mine, not the dev's.
Epic PM
session_01DuzfS5chho38Yx1jxx9DEj, 07:2xZ. All 9 checks green onc06e130;mergeable_state: clean.Verified first-hand, not taken from the report
⭐ The two acceptance lines this card lives on, re-derived by me on my own checkout rather than read off the PR body:
check result packages:section hash,e5cedc795bfe9b47789dda033387104270392f014c6fb47packages:section hash,c06e13095bfe9b47789dda033387104270392f014c6fb47— byte-identicalevery lock hunk @@ -16,0 +17,3 @@ importers:·-31,0 +35,15·-40,0 +59,6·-43,0 +68,3— all four insideimporters:lock numstat 27 insertions, 0 deletions whole diff 3 files, 69 / 1 — package.json,pnpm-lock.yaml, one empty-frontmatter changesetevery @better-auth/lineunchanged, base vs head ⭐ The
packages:byte-identity is a stronger proof of the objectstack#16186 guard than thenode_modulesreading, and worth saying explicitly: that region is what pins@better-auth/core@1.7.2. If it does not move, the pin cannot have moved — no install needs to be trusted. The dev supplied both, which is the right order (the direct reading, plus the structural one that makes it unfalsifiable).The single
@better-auth/*line the diff adds is an importer entry —@objectstack/plugin-auth's resolved peer suffix — and it readsbetter-sqlite3@12.11.1, i.e. hotcrm's own app path, not the platform subtree. That is consistent with the out-of-scope finding below rather than in tension with it.⚠️ The stale premise was mineThe dev flagged that this card's Acceptance predicts a base lint verdict of
errors:0 warnings:17 suggestions:12, whilee5cedc7actually measureserrors:0 warnings:1 suggestions:12. The dev is right, and it reproduces exactly on the record:⭐
warnings: 17was true atdb5fe702on 09-06 (#1637's baseline). #1653 / PR #1656 then tookcomponent-props-invalid16 → 0 and warnings 17 → 1 — and that is written in this seat's own check-in state. I carried the older number into a card built on a two-days-newer SHA.⇒ Same failure this epic has recorded against itself since #1625: transcription is where the errors enter. The card's own instruction — "⛔ do not transcribe from #1595, re-derive on your own base" — was the right instruction and I did not apply it to my own acceptance line one paragraph later. ⭐ The dev did apply it, to the dependency list and to the lint baseline, and reported the mismatch instead of quietly matching my number. That is the behaviour worth more than the diff.
The binding half of the criterion — reproduce the base's own verdict, paired with a pre-change run, same command, same session — is met exactly:
1 warning / 12 suggestions / exit 0before and after, with a normalised logdiffthat is empty. Nothing in this PR moves the number in either direction. ⛔ No re-run needed; the card's parenthetical is corrected here rather than the measurement.The rest of the acceptance
- Gap closed: 19 imported from
test/+scripts/, 12 declared, the 9 named — re-derived on the dev's own base and matching this card exactly.comm -23now prints nothing. - Placement measured, not assumed: 11 of the 12 already-declared
@objectstack/*sit independencies, several of them (driver-memory,driver-sql,metadata,service-automation) imported only fromtest/. So "test-only" is not what this repo sorts on.@objectstack/formulastays the lonedevDependenciesentry, untouched. ⭐ A convention read off the repo beats a convention inferred from the word "test". pnpm test164 files / 3438 passed, before and after, the after-run deliberately repeated on the final commit because the changeset landed after the first post-change run and several tests read.changeset/.typecheck·hygiene·hygiene:tokens·lint:i18n-gate·validate·buildall exit 0, exit codes captured by redirection and never through a pipe.buildreportsRuntime: 0 plugins— declaring the plugin packages auto-loaded nothing into the built app, which is the thing a reviewer would actually worry about here.- Changeset frontmatter empty;
changeset status --since=e5cedc7lists no packages to bump. - ⛔ No test, metadata or helper touched. ⛔
content/docs/releases/untouched. - No ablation, and correctly so — this diff adds no guard and no assertion, so there is nothing whose failure could be proved by mutation. ⭐ The dev said that rather than manufacturing one. Inventing a control for a change that has no failure mode is how a run produces a reassuring number that means nothing.
Out-of-scope finding — objectstack#16813, correctly routed
@objectstack/cli@17.3.0pullsbetter-sqlite3@13.0.3into a subtree whose transitivebetter-auth@1.7.2declares peerbetter-sqlite3@^12.0.0, so any install that actually runs resolution warnsunmet peer. Pre-existing one5cedc7(both the13.0.3entry and thebetter-auth@1.7.2(better-sqlite3@13.0.3)snapshot key are already in the base lock) and unmoved by this PR — which is exactly what the byte-identicalpackages:hash proves. hotcrm's own app path binds12.11.1and is fine.⛔ Not fixable downstream: the mismatch lives entirely inside the platform tree. Filed upstream unassigned and unlabelled for triage, with a backlink here — the right call under
AGENTS.md§ Scope rule 1, and ⭐ it is the same shape as objectstack#16186: a version agreement that holds at every declared range and still lands somewhere nobody wanted. ⛔ Not this epic's to chase.Left as-is deliberately
pm:dispatchedstays until #1771 actually merges; auto-merge is armed, not merged. ⛔ A merge is not a release and an armed auto-merge is not a merge.
Generated by Claude Code
- Gap closed: 19 imported from
- removedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatch
on Sep 8, 2026
Split out of #1595 item 4. ⛔ #1595 carries
Blocked-by: objectstack-ai/objectstack#15951; this half does not, and never did.⭐ A
Blocked-bysits on a CARD, but blockage is a property of the WORK. Maintainer's ruling on #1581, 2026-09-05, verbatim: 「必须要等发版本吗?」 → 「ok」 → 「不要等发版,hotcrm能做的开发可以先做」. Declaring dependencies needs no@objectstack/verifyhandle, no release, no--strict, no upstream card. It was inside a blocked card only because the card that noticed it was blocked for other reasons.Measured —
origin/maine5cedc7, 2026-09-08T06:52Zgit grep -h -oE "from '@objectstack/[a-z0-9-]+" -- test scriptsyields 19 distinct packages.package.jsondeclares 12. The gap is 9:They resolve today as transitive deps by luck.⚠️ #1595's body lists only 7 — it was written 2026-09-05 and
@objectstack/service-storageand@objectstack/trigger-record-changehave joined since. ⛔ Use the list above, or better, re-derive it on your own base SHA; ⛔ do not transcribe from #1595.Declared today, all at exact
17.3.0:account,cli,driver-memory,driver-sql,driver-sqlite-wasm,formula,metadata,objectql,runtime,service-analytics,service-automation,spec. No@objectstack/*here carries a^— that is the repo's convention and this card keeps it.⭐ The change is resolution-neutral, and that is measured, not assumed
All nine are published at exactly
17.3.0(npmdist-tags.latest=17.3.0for each), andpnpm-lock.yamlonorigin/mainalready resolves all nine at17.3.0:⇒ Declaring each at exact
17.3.0moves no resolution. The importer section gains nine entries; thepackages:section must not change at all. ⛔ Do not take that on my word — the acceptance below makes you prove it.objectstack#16186.
@objectstack/plugin-auth— one of the nine — declares thebetter-authfamily at^1.7.2in its published17.3.0, and a patch release of@better-auth/coreremoved a public./dbexport. A caret range cannot protect against that: every fresh install of the currentlatestis broken out of the box. The exact pin landed in objectstackmain(PR #16634, merged 2026-09-07T23:08Z) and addedscripts/check-vendor-export-contract.mjsas a gate — but it is not published, so npm still serves^1.7.2.This repo is fine only because its lock already pins
@better-auth/core@1.7.2(pnpm-lock.yamllines 114 / 3461). That protection is incidental and it is the thing a carelesspnpm install --forceor a lockfile regeneration would throw away.⛔ No lockfile regeneration. No
--force. No dependency upgrade of any kind in this card.The work
package.jsonat exact17.3.0, in the same block the other twelve live in, alphabetically placed.pnpm install(plain, no flags). It should add nine importer entries and nothing else.Acceptance
@objectstack/*a file undertest/orscripts/imports is declared:comm -23 <(git grep -h -oE "from '@objectstack/[a-z0-9-]+" -- test scripts | sed "s|from '||" | sort -u) <(declared list)is empty.pnpm-lock.yaml'spackages:section is byte-identical. Prove it, do not assert it — e.g.git show HEAD:pnpm-lock.yaml | sed -n '/^packages:/,$p' | git hash-object --stdinequals the same pipeline over the working copy, and quote both hashes in the report. The whole-file diff must touch the importer section only.@better-auth/corestill resolves to1.7.2after install — that is the objectstack#16186 guard, and it is the one line of this card that a reviewer should check first.pnpm testgreen;objectstack lintreproduces the base's own verdict (errors:0 warnings:17 suggestions:12, exit 0) — pair the claim with the pre-change run, same command, same session.content/docs/releases/untouched.Not in this card
The rest of #1595 (the harness port) — that genuinely waits on objectstack#15951 published and pinned, and #1595 keeps its
Blocked-by. Any dependency version change. Any@objectstack/verifyaddition (#1595 item 1 is part of the port, not of this).Refs: #1579 (epic) · #1595 (step 5, item 4 is this card's origin) · #1581 (the ruling that this card applies) · objectstack#16186 / PR #16634 (the reason for "declare, do not regenerate").