Repository navigation
Description
Found while upgrading objectstack-ai/hotclm to @objectstack/* 17.4.0 (hotclm#35 / hotclm PR #37). Filed at the destination per that repo's AGENTS.md rule for platform gaps — report, never patch. Not triaged: no domain:*, no priority, no assignee.
This is the sharpest of three findings from that boot, because it is the one where a diagnostic actively lies.
Symptom
On the single-boot seed path — CLM_DEMO_SEED=1 objectstack dev --compile --ui --seed-admin against a clean database, i.e. not the two-boot pnpm demo handover — the loader logs, for all 120 clm_contract rows:
Deferred reference UNRESOLVED after pass 2 - clm_contract.owner_id stays NULL
and the database then ends up holding the dev admin's id in owner_id on all 120 rows.
The column is not NULL. The log says it is.
Why this one is worse than a wrong number
A log that under-reports is bad; a log that reports the opposite of what the table holds is worse, because it survives verification. An author who reads the loader summary concludes the rows are ownerless and goes looking for the bug that made them so. An author who queries the table concludes the seed worked. Both are reading real output from the same run, and there is nothing in either to tell them the other exists.
The mechanism appears to be ordering: the deferred-reference resolver reports its own pass-2 outcome, and something later — the ownership claim for newly-minted admin accounts — writes the column afterwards without the summary being recomputed. So the sentence is true when it is emitted and false by the time the boot finishes.
Second symptom on the same path (probably one bug, possibly two)
The same single-boot run installs 760 rows, not 820: all 60 clm_review rows are refused with Reviewer is required. That is exactly the failure hotclm's scripts/demo.mjs two-boot handover exists to prevent — clm_review.reviewer is required: true and resolves against sys_user.name, which matches nothing before the first account exists. Expected on this path; recorded because it is what makes the path worth reproducing.
Reproduce
git clone https://github.com/objectstack-ai/hotclm && cd hotclm && pnpm install
rm -rf .objectstack/data
CLM_DEMO_SEED=1 pnpm exec objectstack dev --compile --ui --seed-admin
# read the loader summary: "owner_id stays NULL" x120
# then read the table:
# sqlite3 .objectstack/data/*.db 'select count(*) from clm_contract where owner_id is not null'
# -> 120pnpm demo never takes this path, so no shipped product is affected — which is precisely why this can sit unnoticed.
Expected
The loader's deferred-reference summary describes the state at end of boot, or says explicitly that it describes the state at end of pass 2 and may be superseded. Either is fine; a bare present-tense claim about a column's value that is false by the time the boot ends is not.
Side effect worth recording
This resolves an open contradiction in hotclm#26. Its annotation "the runtime claims ownerless seeded rows for the dev admin once that account is minted (measured)" is true on the single-boot ordering and false on the two-boot one — so the original measurement was correct and was silently invalidated by hotclm#21's handover, which changed which boot mints the admin. The annotation is a (measured) note that stopped being true without anyone touching it.
Related
Nearest neighbours, all closed and none the same defect: #3932 (a dropped reference field invisible in the summary), #14403, #16488, #8682.
Activity
os-litant commentedon Sep 10, 2026
Triage: lands in the single-boot seed path;⚠️ if the loader turns out to live in
domain:engineas the primary read —packages/cli, that isdomain:cliand the card comes back for a re-route;priority:p2.⭐ The filer calls it "the sharpest of three findings from that boot, because it is the one where a diagnostic actively lies" — and that is exactly right. The seed loader logs
owner_id stays NULLfor 120 rows whoseowner_idis NOT NULL: the summary contradicts the table it just wrote.⇒ p2: an operator reading that line concludes ownership was not applied and goes looking for a bug that is not there — or worse, re-runs something to "fix" it. ⛔ A wrong diagnostic costs more than a missing one, because it directs the investigation.
⇒ Make the summary read the rows it wrote.⚠️ Establish which side is wrong first — if the loader really did intend to leave them NULL and something else set them, the log is right and the write is the surprise. ⛔ Do not silence the line without knowing which.
⭐ Filed at the destination per hotclm's
AGENTS.mdrule — report, never patch. ⇒ a downstream repo declining to patch a platform gap in its own tree is the rule working; this card is where that report is supposed to land.Size/model suggestion:M.分诊席位 ·
session_017VGfRocA8VjczSe84fgjY3· R+166 · 2026-09-10T14:52Z · 本评论来自分诊座位Generated by Claude Code