Repository navigation
Decision: DESIGN.md §10 asks for 300 seeded contract versions, but §03 makes file required and a seed cannot mint one #19
Description
Ruled: 6396327991 · letter D · 2026-10-25T10:07Z (D = platform seed-file primitive, added by the director seat beyond A/B/C below; interim = A)
Blocked-by: objectstack-ai/objectstack#25779
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_versionwithfile*— required.src/objects/contract-version.object.tsimplements it asField.file({ required: true, accept: ['application/pdf', '.docx'] }). - §10 asks for 300 seeded
clm_contract_versionrows ("谈判中的合同有 3 到 5 版,含对方红线"). - A
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:ERROR [SeedLoader] Failed to write clm_contract_version record #2 (contract+version_no=... 1): File is required -
fileis 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). -
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.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_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.)- A seeded draft cannot be submitted through the UI. The
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. - The same wall applies to
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 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.
Activity
Demo seed data: demo-en (default) and demo-zh (#21)
zhuangjianguo commentedon Sep 9, 2026
维护者速读
事情:设计方案第 10 章要 300 条合同版本种子数据,但第 3 章把版本的
file定为必填,而file的值是一次上传才能铸出的sys_fileid —— 声明式种子没有上传,铸不出来。所以卡 08 一条版本都没种,version_count在 120 份合同上诚实地读 0。三种写法都实测过(17.3.0):省略
file整行被拒;写 URL 行进去了但平台拒绝为自己的迁移背书(NOT attesting 'adr-0104-file-references');写一个 id 形状的假 token —— 静默插入、无警告、原样读回,因为没有sys_file匹配它。第三种是种子唯一「蒙得过去」的写法,也正是AGENTS.md的 Honest capabilities 明令禁止的。卡 08 因此选了诚实的 0。代价里最硬的一条,容易被当成小事:
draft → submitted的守卫要「至少一个版本文件或类型带模板」,种子两样都给不了,所以 10 份种子草稿一份都提交不了。要在 demo 里演示发起流程,只能现建一份合同再真上传一个文件。这不是数据稀疏,是展品演示不了自己的主流程。你要做的:回一个字母,A 或 C(B 见下,不建议)。
四棱分析
实际业务需求 — 偏 C。判据不是「表格上少 300 行」,是上面那条:种子草稿提交不了,§05 的版本时间线是空的,§10 的对方红线故事演示不出来。
version_count是 §10 要展示的五个汇总里唯一处处读 0 的一个。展品的第一职责是展现平台能力,这三样都是能力没被展现。项目长远合理性 — 偏 C。§03 那个
file*在自己的语境里站得住(没有文档的版本不是版本),但 C 指出的事实更强:「按模板生成的版本」本来就没有附件,所以「版本必须带文档」这条约束放在字段上就是过紧,放在状态机守卫上才准(approved → signing要一个clean版本,signing → active要一个final_signed,两个守卫本来就在读版本)。C 是把约束搬到它该在的那一层。防 AI 写错 — 偏 A,且这一棱要求你知道一件事:三个选项都不闭合真正的坑。真正的坑是上面第三种写法 —— 一个 id 形状的假 token 静默插入、原样读回、下载 404。那是平台侧的缺口,应用侧关不掉。A 保住诚实的 0(不写就不会写错)。C 会开一个「版本行存在但什么都没附」的窗口,从防错角度是负分,必须靠守卫补回来。B 最差:种子从声明式变成有运行时依赖,行数随一个环境变量条件化 —— 上传失败就静默少一个数据集,正是这个仓库反复在防的形状。
创业阶段不扩散 — 这一棱否决「分两阶段」。维护者 2026-08-27 逐字裁定:「项目在创业阶段,用户也很少,短期不考虑渐进。」staged 选项仅凭具名外部用户证据才可荐,这张卡拿不出。所以「A 现在、C 以后」不是一个可推荐的形状 —— 请在 A 与 C 之间选一个,现在付清。A 的成本是零、代价是展品长期带一个可见的洞;C 的成本是一次 §03 编辑加把约束移到守卫,代价是要把两个守卫写实。
结论:长远合理性与业务需求偏 C,防错偏 A,不扩散要求二选一而非分期。按「长远合理性权重恒 ≥50%、有实测拉动则荐长远形态一次付清」,拟推荐 C 一次付清,并要求同一批把
approved → signing/signing → active两个守卫写成真闸门 —— 否则 C 就只是把必填删掉,那才是真的更糟。若你偏保守选 A,请一并接受 §10 的 300 行改成 0 并写进文档:沉默地留着一个永远填不满的表格,是把矛盾推给下一张卡。
全部三次实测取自
@objectstack/*17.3.0。#35 正在把应用推到 17.4.0(396 个 changeset、35 个 breaking 标记)。本卡的核心前提是「声明式种子铸不出sys_fileid」—— 那是一句平台能力断言,17.4 落地后必须重跑那三次探针再定。⇒ 建议:这张排在 #35 落地之后。#6、#10、#14 不受影响,可以先决。
Generated by Claude Code
zhuangjianguo commentedon Oct 25, 2026
Ruling: batch #3 item 5 · letter D · maintainer 「同意」 2026-10-25T10:07:34Z
裁定:D(新增项)—— 种子数据集可携带打包的文件,由平台 loader 入库并铸
sys_fileid;hotclm 等平台,期间维持 A维护者在第 3 批决策箱回了「同意」(= 推荐项 D)。裁决文档:https://claude.ai/artifact/N1GCqHkEVMy3kneFmVEM8w 。D 是本席按维护者 2026-10-25 的平台优先规则在正文 A/B/C 之外新增的选项;§03 不动。
鲜度门:正文 2026-09-07T20:19Z;评论一条 2026-09-09T14:35Z(拟稿,建议 C 一次付清——被 D 替代)。复测(
main134707e):contract-version.object.ts:91仍是Field.file({ required: true, storage: { notNull: true } });clm_contract_type.template_file、clm_signature.executed_file、clm_obligation.evidence同属Field.file,同一堵墙。平台侧:packages/runtime/src/seed-loader.ts与packages/spec/src/data没有任何「种子携带文件」的支持;objectstack 自己的 showcase 也撞过(#4891)。objectstack 去重:0。录裁前重读,无变化。为什么不是 C:「按模板」的草稿根本不需要版本行(提交守卫接受类型带模板),所以「模板版本没有附件」的论据不成立;放宽
file只是让版本时间线从「空」变成「300 条没文件的行」,并打开正文自己指出的假 token 窗口。⛔ B(pnpm demo真上传、环境变量塞 id)明确不采纳:种子从声明式变成有运行时依赖,行数随变量条件化。裁后执行
Field.file列可引用应用包内的 fixture 文件,loader 写入存储、铸sys_fileid、按(对象、记录、字段)独占归属、幂等;顺带记录正文第 3 种写法「id 形状的假 token 静默插入」这条平台缺口,lane 在 18.1 上复测它是否已被 ADR-0104 门挡住),回链见下一条评论;本卡Blocked-by它。template_file/executed_file/evidence的种子;十份种子草稿从此可提交。version_count诚实读 0)。⛔ 本席不动标签;lane 席位派发时转标签并带
Ruling-ref:。Generated by Claude Code
zhuangjianguo commentedon Oct 25, 2026
Platform card filed per the D ruling above: objectstack-ai/objectstack#25779 — seed datasets can reference bundled fixture files; the loader stores the bytes, mints the
sys_fileid and refuses a dangling id-shaped token. Class ③, unlabelled, awaiting triage there.Blocked-by: objectstack-ai/objectstack#25779
Generated by Claude Code
objectstack-fleet commentedon Oct 25, 2026
Out of the decision box — Ruling-ref: comment 6396327991 (batch #3 · letter D · maintainer 「同意」).
needs-user-decision→pm:blocked,Blocked-by: objectstack-ai/objectstack#25779(platform seed-file primitive). Interim: 0 seeded versions (README already says so); options B and C rejected.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Unblocked — 2026-10-27
closed2163e80is an ancestor of tag@objectstack/spec@18.2.0mainnow pins@objectstack/*18.2.0 (PR #155, merge21f2319, push CIValidatesuccess), so the fix is installable in this repo. The ruling recorded in the body stands; this card returns to the queue for dispatch. The dev re-measures the premise onmainbefore writing code.State:
pm:blocked→pm:queue.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Claim: PM loop round 17
Ruling-ref: 6396327991
Session:
session_017nzWFRUo2U7evMkPdVniAnAccount:
zhuangjianguo(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-19-seed-filesWorktree:
hotclm-issue-19Domain:
repo:hotclm(single-lane sister repo — nodomain:*)Seat:
repo:hotclm#1File surface:
src/data/**(version seed,template_file/executed_file/evidenceseed columns viaseedFile()) · a small fixture-file folder the seed references (PDFs only, a few KB each) ·README.md(seed counts) ·objectstack.config.tsonly if the 18.2.0 seed registration needs it — stop on breach; explain in the reportContainer & model:
S,mode:subagent,model: opus(TIER_DEFAULT; hand-derived for a sister repo),effort: mediumClause-②: no
Metadata-protocol: none
Responsibility:
this app's demo (seeded contracts carry real version files, so a seeded draft can be submitted and the version timeline is not empty) | objectstack-ai/objectstack#25779 shipped in 18.2.0 (seedFile) | everyone who runs the demoThread-read: 6437406831
Premise: re-measured by the dev on
origin/main(@objectstack 18.2.0, after PR #176) with the declared demo staffSerial constraints cleared: #41 landed (PR #176,
src/data/**). In flight: #43 (backfill capability), the launch wizard (#99, #161, #162), #175 (reminder templates); all on disjoint files.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
os-dev-report
{ "issue": 19, "status": "done", "branch": "claude/issue-19-seed-files", "pr": "https://github.com/objectstack-ai/hotclm/pull/185", "session": "session_017nzWFRUo2U7evMkPdVniAn (subagent dev-19 of the PM seat)", "premise_still_valid": true, "summary": "Premise re-measured on origin/main 351de35 (18.2.0, demo:zh, fresh DB): clm_contract_version total 0, version_count 0 on all 120 contracts, and requester2's submit_contract on a seeded draft answered 422 'Upload a first version, or choose a contract type that carries a template, before submitting.' The PR (src/data/** and README only) ships seven one-page demo PDFs, under 2 KB each, in src/data/fixtures/, each marked 'HotCLM demo document / NOT A REAL CONTRACT'. It seeds them through seedFile(path), with paths relative to the objectstack.config.ts directory. It adds 300 clm_contract_version rows (exactly §10's 300): 30 negotiating contracts with 3-5 versions each (126), 24 negotiated executed contracts with 4-5 including a non-current final_signed copy (108), 48 backfilled contracts with a sole current final_signed copy, and 18 draft/submitted/cancelled contracts with v1. Each contract has exactly one current version (#96 1A 2A), and compile-time asserts check this. It also seeds template_file on 6 own-paper types (SUP/LSE/AMD left empty so both F1 version-1 paths stay live), executed_file on the 24 completed rounds and evidence on the 90 done obligations. is_current, template_file, executed_file and evidence are applyOn:'create'; version file stays 'always' because the platform keeps unchanged files on replay. Measured in zh-CN Chromium: requester2 submitted a seeded LSE draft (no template, so the seeded v1 satisfied the guard), draft→in_review. The version timeline lists and downloads every PDF (200 application/pdf) as requester1, counsel1 and counsel2, and version_count sums to 300 with none at 0. A second pnpm demo:zh on the same DB, after a submit and a counsel-added v6, changed 0 rows and 0 file ids, stored no new sys_file (421→421), and v6 stayed current. Side question: clm_review.reviewer left on the dev admin (not a one-column change, see open_questions).", "tests": "No test suite in this repo; live measurements on 18.2.0 port 3156. Baseline main 351de35: versions 0; requester2 submit → 422 INVALID_STATE (guard message above). Branch 2d9d6b4 and final head 096b2dc, fresh DB: 'Bundling seed files... 8 files (13.1 KB)'; counts versions 300, sys_file 420, contracts with a current version 120 (max 1 each); kinds draft 72, counterparty_redline 72, final_signed 72, internal_redline 42, clean 42; version_count distribution 1x66, 3x6, 4x24, 5x24 (sum 300); templates 6/9; executed_file completed 24/24, sent 0/6; evidence done 90/90, others 0. Browser (zh-CN): requester2 LSE draft, 版本 tab 'v1 · Draft 草稿 我方 ✓ v1-draft.pdf Business Requester 2' → 提交 → status in_review, submitted_at stamped, F2 assigned Legal Counsel 1 (measured on both heads). requester1 MSA in review: 5 rows, each link 200 application/pdf '%PDF-1.4', click opens /api/v1/storage/_local/raw/... 200. counsel1 active MSA: v5 最终签署版 not current, v4 清稿 current, all 5 → 200. counsel2 on final head: 5/5 → 200. F1 template path: requester1 headless launch_contract NDA draft_from_template:true → v1 NDA-template.pdf with a new file id (type kept its own). Second run on the same DB: banner 'Seeds: app.objectstack.hotclm 1130 rows', no seed error; snapshot diff 0 changed across versions/types/rounds/obligations/contracts; sys_file 421→421. Reverse check: misspelt fixture path → CLM_DEMO_SEED=1 pnpm validate exit 1 'seedFile(...) names no file', then restored. NOT MEASURED: a desk-attached executed_file/evidence surviving a re-run (no such edit made); the console wizard's template toggle (only the headless path).", "gates": "Final head 096b2dc, each exit captured before any pipe: pnpm install EXIT=0; pnpm validate EXIT=0; pnpm lint EXIT=0 ('6 suggestion(s)', 0 warnings, unchanged); pnpm typecheck EXIT=0; pnpm lint:i18n-gate EXIT=0 ('COVERAGE : 0 missing keys across 2 locale(s)', 926 keys); CLM_DEMO_SEED=1 pnpm validate EXIT=0. CI check-runs on 096b2dc at report time: 'Validate' completed success (one run), a second 'Validate' in_progress (the pull_request run); not awaited.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2 relay writes — pr_create objectstack-ai/hotclm#185 (fleet-write run 40502651176, body read back identical, assignee zhuangjianguo); this os-dev-report comment on #19 via post-stamped. Plus git push of claude/issue-19-seed-files (not a REST write).", "open_questions": [ { "question": "clm_review.reviewer: move the 60 seeded reviews from Dev Admin to the counsel?", "options": [ "A Leave it on Dev Admin (current). Zero cost; README already tells the evaluator to reassign.", "B A follow-up card owning src/data/keys.ts (export counselFor), negotiation.seed.ts reviewer, scripts/demo.mjs (retire the DEMO_USER priming check, which exists only for this column) and README. It must also decide per stage which account a finance/compliance/business review names, because legalOwnerOf is null on SOW/ORD contracts and on the handed-back one, and reviewer is required." ], "recommendation": "B as its own card, because it is not a one-column change: it spans scripts/demo.mjs, which is outside #19's surface, and needs a per-stage product decision that negotiation.seed.ts records as open." } ], "out_of_scope_findings": [ "class: a · reach: public door — pnpm demo on a loaded box; the server logged 4 'Knex: Timeout acquiring a connection' errors (sqlite) while I signed in during the background seed, refusing the sys_user read; another boot had one 28 s sign-in; main's seed in the same probe: max 1.7 s, 0 refusals. The seed with 420 seedFile stores took ~104 s against ~70 s on main · platform (seed loader holds the connection while storing files) · dedupe words: seedFile, seed loader, connection pool, sign-in timeout, kernel:bootstrapped", "class: b-candidate · reach: REST GET /api/v1/data/clm_contract_type?select=template_file as clm.admin → template_file {id, metadataRefused:true}; the same with id in select → full {name,size,mimeType,url}; platform admin unaffected; console always selects id, so no screen is affected · Seam: runtime:file-field read expansion → consumer: REST callers projecting without id · dedupe words: metadataRefused, file field, select projection, id", "carrier: #157 (child display_name mirrors) · noted, not filed — clm_contract_version display_name reads 'v1 · Draft' in zh-CN (mirror.hook.ts writes English kind labels)", "noted, not filed (承接者:无) — the fixture PDFs are English-only in both locales (no CJK font, to stay under 2 KB); download names are locale-neutral" ], "governed_text_proposal": "None required: §03 is untouched and §10's 300 is met exactly. Optional §10 clm_contract_version row wording if the seat wants it recorded: 「谈判中的合同有 3 到 5 版,含对方红线;文件为 src/data/fixtures/ 下的演示 PDF(seedFile),每份合同恰一个当前版本」." }The demo seeds 300 contract versions with real files (#185)
objectstack-fleet commentedon Oct 27, 2026
Ruling-ref: 6396327991 (letter D)
Landed — PR #185 · 2026-10-27
MERGED(squash onmain), merged at its ACCEPT head096b2dc;Fixes #19closes this cardRelease: the demo now seeds the 300 contract versions §10 asks for, each with a real (demo-marked) PDF, so a seeded draft can be submitted, the version timeline is no longer empty and
version_countreads true. Contract types, signing rounds and done obligations carry their files too. State:pm:dispatchedremoved, assignee cleared.Generated by Claude Code
DESIGN.md §10: seeded version files and review dealing (#19, #186)