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
Raised by card 08 (#18, seed data), by Claude Code session session_01KcrVDXSptwDukFsHPHPR1V, rather than editing the governed surface. DESIGN.md §01–§04 is a governed surface; §10 is the seed table.
The conflict
§03 declares clm_contract_version with file* — required. src/objects/contract-version.object.ts implements it as Field.file({ required: true, accept: ['application/pdf', '.docx'] }).
A file value is an opaque sys_file id minted by an upload. sys_file is a fileId-to-storage-key mapping; the bytes live in the storage backend under key. A declarative seed has no upload and cannot mint one.
Measured, three ways (@objectstack/* 17.3.0, sqlite, objectstack dev)
One seed load, three version rows differing only in the spelling of file:
file omitted — refused, and the whole row is lost:
ERROR [SeedLoader] Failed to write clm_contract_version record #2
(contract+version_no=... 1): File is required
file is a URL (https://example.invalid/probe.pdf) — the row inserts, and the platform then refuses to attest its own migration:
WARN [migration] NOT attesting 'adr-0104-file-references' on this new datastore:
this boot already wrote 1 value(s) that the migration's own contract rejects
(clm_contract_version.file: Expected an opaque sys_file id).
file is an id-shaped token (probe-file-token-0001) — the row inserts silently, no warning, and reads back verbatim because no sys_file matches it. It is a download that 404s.
Positive control: the other 12 rows of the same seed load inserted without complaint, so the refusal in (1) is about the value, not the seed path.
Why card 08 shipped zero versions
Option 3 is the one a seed could get away with, and it is the one AGENTS.md forbids: "Honest capabilities. No AI output that is a stub; no seeded number that looks computed. A capability the runtime does not deliver is hidden, not faked." So #18 seeds no versions at all, version_count reads an honest 0 on every one of the 120 contracts, and this card carries the decision.
What that costs today
The version timeline of §05 is empty, and the counterparty-redline story of §10 cannot be demonstrated from the seed.
version_count is one of the five roll-ups §10 wants shown; it is the only one that reads 0 everywhere. (The other four are verified correct against their seeded children in Seed data: demo-en (default) and demo-zh (card 08, M2) #18.)
A seeded draft cannot be submitted through the UI. The draft to submitted guard wants "至少一个版本文件或类型带模板", and the seed can supply neither, so the ten seeded drafts refuse submission with Upload a first version, or choose a contract type that carries a template, before submitting. Driving intake in the demo means creating a new contract and uploading a real file.
A. Leave §03 as it is; the seed ships no versions. What #18 does today. Zero cost, zero risk, and the demo keeps a visible hole. The file* requirement is defensible on its own terms: a version without its document is not a version.
B. Have pnpm demo upload one real document and let the fixture reference it. The priming boot in scripts/demo.mjs already signs in; it could POST a small PDF, capture the returned sys_file id, and pass it to the demo boot as an environment variable the fixture stamps on all 300 rows. sys_file ownership is exclusive per (object, record, field), and the platform copies the bytes into a fresh row rather than sharing one, so 300 references are legal. Cost: the declarative seed gains a runtime dependency, and the fixture's row count becomes conditional on a variable — if the upload fails, the version dataset has to be dropped, silently changing what pnpm demo produces.
C. Relax clm_contract_version.file to optional in §03 and in the object, and move "a version must carry a document" into the state-machine guards that already read versions (approved to signing wants a current clean version; signing to active wants a final_signed one). Cost: an edit to the governed surface, and a window where a version row can exist with nothing attached — which is arguably what a "by template" version already is.
Recommendation: A now, C when a maintainer next opens §03. B buys the demo one artefact at the price of making the seed non-declarative and its row count conditional, which is a bad trade for a fixture whose whole design is that both locales produce provably identical rows. C is the honest long-term shape, but it is a §03 decision and #18 has no mandate to take it.
Raised by card 08 (#18, seed data), by Claude Code session
session_01KcrVDXSptwDukFsHPHPR1V, rather than editing the governed surface.DESIGN.md§01–§04 is a governed surface; §10 is the seed table.The conflict
clm_contract_versionwithfile*— required.src/objects/contract-version.object.tsimplements it asField.file({ required: true, accept: ['application/pdf', '.docx'] }).clm_contract_versionrows ("谈判中的合同有 3 到 5 版,含对方红线").filevalue is an opaquesys_fileid minted by an upload.sys_fileis a fileId-to-storage-key mapping; the bytes live in the storage backend underkey. A declarative seed has no upload and cannot mint one.Measured, three ways (
@objectstack/*17.3.0, sqlite,objectstack dev)One seed load, three version rows differing only in the spelling of
file:fileomitted — refused, and the whole row is lost:fileis a URL (https://example.invalid/probe.pdf) — the row inserts, and the platform then refuses to attest its own migration:fileis an id-shaped token (probe-file-token-0001) — the row inserts silently, no warning, and reads back verbatim because nosys_filematches it. It is a download that 404s.Positive control: the other 12 rows of the same seed load inserted without complaint, so the refusal in (1) is about the value, not the seed path.
Why card 08 shipped zero versions
Option 3 is the one a seed could get away with, and it is the one
AGENTS.mdforbids: "Honest capabilities. No AI output that is a stub; no seeded number that looks computed. A capability the runtime does not deliver is hidden, not faked." So #18 seeds no versions at all,version_countreads an honest0on every one of the 120 contracts, and this card carries the decision.What that costs today
version_countis one of the five roll-ups §10 wants shown; it is the only one that reads 0 everywhere. (The other four are verified correct against their seeded children in Seed data:demo-en(default) anddemo-zh(card 08, M2) #18.)drafttosubmittedguard wants "至少一个版本文件或类型带模板", and the seed can supply neither, so the ten seeded drafts refuse submission withUpload a first version, or choose a contract type that carries a template, before submitting.Driving intake in the demo means creating a new contract and uploading a real file.clm_contract_type.template_fileandclm_signature.executed_file; both are optional, so Seed data:demo-en(default) anddemo-zh(card 08, M2) #18 simply leaves them empty.Options
A. Leave §03 as it is; the seed ships no versions. What #18 does today. Zero cost, zero risk, and the demo keeps a visible hole. The
file*requirement is defensible on its own terms: a version without its document is not a version.B. Have
pnpm demoupload one real document and let the fixture reference it. The priming boot inscripts/demo.mjsalready signs in; it couldPOSTa small PDF, capture the returnedsys_fileid, and pass it to the demo boot as an environment variable the fixture stamps on all 300 rows.sys_fileownership is exclusive per (object, record, field), and the platform copies the bytes into a fresh row rather than sharing one, so 300 references are legal. Cost: the declarative seed gains a runtime dependency, and the fixture's row count becomes conditional on a variable — if the upload fails, the version dataset has to be dropped, silently changing whatpnpm demoproduces.C. Relax
clm_contract_version.fileto optional in §03 and in the object, and move "a version must carry a document" into the state-machine guards that already read versions (approvedtosigningwants a currentcleanversion;signingtoactivewants afinal_signedone). Cost: an edit to the governed surface, and a window where a version row can exist with nothing attached — which is arguably what a "by template" version already is.Recommendation: A now, C when a maintainer next opens §03. B buys the demo one artefact at the price of making the seed non-declarative and its row count conditional, which is a bad trade for a fixture whose whole design is that both locales produce provably identical rows. C is the honest long-term shape, but it is a §03 decision and #18 has no mandate to take it.