Repository navigation
feat(spec,metadata-protocol,service-storage,runtime,cli)!: a seed record can carry a file the package ships, seedFile(path) - #26244
Conversation
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF
…undling Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF
… rows store nothing Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF
…ctness-ledger row for seed-file.zod.ts Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF
…mance, counts) Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF
…ap for the seed file type aliases Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF
📓 Docs Drift CheckThis PR changes 5 package(s): 73 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 17 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 158 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 4f2c6a2f9b431afdf4088ddca718bf4c8feeb535 && git checkout 4f2c6a2f9b431afdf4088ddca718bf4c8feeb535
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 6390fe52cecd263f09225d0d6d9b74412d111a67 8f07f5cb1cd03b0fc37c03c192fb7b081a38f3ab && git checkout -B drift-repro 6390fe52cecd263f09225d0d6d9b74412d111a67 && git merge --no-ff 8f07f5cb1cd03b0fc37c03c192fb7b081a38f3ab
node scripts/docs-audit/affected-docs.mjs --json 6390fe52cecd263f09225d0d6d9b74412d111a67
|
Regenerated the deferred spec artifacts from the merged tree: the strictness-ledger counts, api-surface, authorable-surface and export-origins for data. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF
…test record names no error code The ledger gained two entries and 26 dropped-refinement sites (the seed record value's refinement) without its measured totals; they now read 247 and 866. A bundle test's record field named code read as an error-code literal to the casing guard; it is a name. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF
…l-1 description pin counts seed-file.zod.ts Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF
Contract reviewServed-tier: Inputs: card #25779 (body + all 7 comments, including the claim 6415670720, the claim amendment 6421695515 and both dev reports), PR #26244 (body, 55-file list, net diff against ① Derived judgmentsAccept-set and public-surface changes the diff implies, each judged against the cited code:
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
维护者速读 — PR #26244 at
|
Takes main's plugin-hono-server skipLibCheck fix. Two conflicts, resolved by keeping both sides: - metadata-protocol protocol.ts imports: main dropped the unused ALL_CONVERSIONS import; this branch keeps its IFieldFileService and FIELD_FILE_SERVICE imports. - the ADR-0122 isomorphic pin count: main's NowAnchorSchema pin is 789 -> 790, so this branch's SeedFilePathSchema pin becomes 790 -> 791 (assertion, title and header). Regenerated the deferred spec artifacts from the merged tree: json-schema manifest, authorable-surface, export-origins, declaration-map and api-surface for data, the strictness-ledger counts and the references index. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF
Requested by Steedos · project thread
Fixes #25779
Clause-②: yes (narrowing)
Metadata-protocol: narrowed
维护者速读
改了什么
file: seedFile('fixtures/nda-v1.pdf')。os build在构建时读出这些文件,把内容打进产物。所以os dev、os serve、已发布的包、产物 URL 这几种启动方式都带着文件,运行时不用再读磁盘。os validate做同样的路径检查,找不到文件会在校验阶段就报错。为什么改
file字段保持必填。风险与代价(含回滚)
sys_metadata里多存一份。kernel:bootstrapped时执行,和已有的demoStaff一样,这样文件会写进部署实际使用的存储。Clause-②: yes和Metadata-protocol: added,本 PR 和 changeset 照抄了。实测这是收窄,应写作yes (narrowing)和narrowed,详见下方 Acceptance notes,由席位修正认领。两种写法的发布级别都是 minor,版本号不受影响。seedFile的应用需要改回去,因为 revert 之后这个函数就不存在了。席位意见
建议批准。契约复核在本 head 通过(PR 评论 6425043305,CONTRACT_REVIEW_TIER):新增的
seedFile写法与「查不到文件的 id 形值整行拒绝」两处接受集变化都判定正确,changeset 的收窄声明、BREAKING 说明与 ADR-0087 标记与实际发布内容一致。本仓库没有任何种子受这条收窄影响。唯一未测量的是类型检查,它因 tsc 内存溢出(exit 134,不是类型错误)失败,根因已立卡 #26288,与本 PR 无关,需要重跑。你要做的
skills/**的一行生成内容,改动又超过 3000 行(含生成物),所以需要人工批准。What it does
file/image/avatar/video/audiofield with a file the package ships:file: seedFile('fixtures/nda-v1.pdf'). This is the hotclm#19 ruling D: the platform's seed loader carries the bundled fixture file, and the app keepsfilerequired.seedFile(path)writes{ $file: path }into the record.os build/os compilereads the file, relative to the directory that holdsobjectstack.config.ts, and embeds it in the dataset's newfilesmap as base64 with its size and SHA-256. Every boot path then has the bytes with no filesystem access at runtime:os dev,os serve, a published package, or an artifact URL.os validateruns the same gate (collectSeedFiles), so it refuses the pathsos buildrefuses: a missing file, a path that climbs out of the package, or an unknown type. Onlyos buildwrites the bytes (placeSeedFiles).os serve/os devbooting a config (not an artifact) mirrors the collection, as it already mirrors package docs. Without that mirror a config boot carried the reference and not the bytes, and refused every such row. The boot test's negative control measured exactly that: 0 rows with the mirror removed, 2 with it.sys_metadata.field-filesservice (IFieldFileService, registered by@objectstack/service-storage) as apendingsys_filein the row's organization.pending, so the existing pending-upload retention reclaims it.unowned_reference.examples/app-showcase's seed docblock names it.Readiness: why the inline seed of an app with seed files moves to
kernel:bootstrappedfield-filesservice is registered at the storage plugin'sinitand resolves the engine per call, so it can serve a seed that runs in a plugin'sstart().kernel:ready, once settings are read. An AppPlugin inline seed whose datasets carry seed files therefore defers tokernel:bootstrapped, as one withdemoStaffalready does, so its files land in the store the deployment serves from.claimFilesthen only commits it. When they are not armed yet, the loader's explicit claim is the ownership. Either way a file has exactly one owner.Files touched
packages/spec/src/data/seed-file.zod.ts(new:seedFile,SeedFileReferenceSchema,SeedFileContentSchema,SeedFilePathSchema),seed.zod.ts(filesmap, record-value refinement,defineSeedrefusesseedFilein a non-file field),data/index.tspackages/spec/src/contracts/storage-service.ts(FIELD_FILE_SERVICE,IFieldFileService, its input and output types)packages/services/service-storage/src/field-file-service.ts(new),storage-service-plugin.ts(registersfield-files),file-reference-lifecycle.ts(onlyexportadded toreleaseOwnershipandownedBySlot)packages/metadata-protocol/src/seed-files.ts(new),seed-loader.ts,protocol.ts,protocol-publish-batch.ts,index.tspackages/runtime/src/app-plugin.ts,packages/runtime/src/domains/packages.ts(pass thefield-filesservice to everySeedLoaderService)packages/cli/src/utils/bundle-seed-files.ts(new:collectSeedFilesgate,placeSeedFilesassembly),commands/compile.ts,commands/validate.ts,commands/serve.ts(config-boot mirror); the gate-parity and call-site ledgers intest/validate-build-gate-parity.test.tsandtest/normalized-call-sites.test.tsclassify bothcontent/docs/data-modeling/seed-data.mdx(new section "File Fields —seedFile(path)")data/seed-filepage), skill references, strictness-ledger counts plus a hand-written triage row forseed-file.zod.ts(both sites strict from birth),dropped-refinements.baseline.json(the record-value refinement, by site), livenessseed.json+ countsGoverned path. The diff touches one governed path,
skills/objectstack-data/references/_index.md. It is a single generated line fromgen:skill-refs(the newdata/seed-file.zod.tsreference), andcheck:skill-refsregenerates it byte-exact. The twoskills/**readings, in lines:SKILL.mdsummed): 4383 before, 4383 after. NoSKILL.mdchanges.Overlap with #25801 (PR #26134). That PR opened first, and the two diffs share no file. This PR's only edit near #25801's area is
packages/services/service-storage/src/file-reference-lifecycle.ts, where it adds theexportkeyword to two existing functions and changes no logic.Tests
packages/spec/src/data/seed-file.zod.test.ts: the path rule's accept and refuse tables, the reference shape,SeedSchemawith refs and bytes, the malformed-reference path, anddefineSeed's refusal.packages/spec/src/contracts/storage-service.test.ts: thefield-filesslot and a fake round trip.packages/services/service-storage/src/field-file-service.test.ts: real ObjectQL on sqlite. It covers:kernel:ready;isolatedposture;multiplefield.packages/metadata-protocol/src/seed-loader-seed-files.test.ts. It covers:multiplefields, a file per row, and the self-reference path;packages/cli/src/utils/bundle-seed-files.test.ts: bundling, package bodies, the gate writing nothing, a declared type winning over the extension, and refusals (missing file, unknown type, a path that climbs out).packages/cli/test/build-seed-files-artifact.e2e.test.ts(nightly tier): the realos buildwrites the bytes beside the reference,loadArtifactBundlereads them back, and bothos buildandos validaterefuse a path that names no file.packages/cli/test/serve-config-boot-seed-files.e2e.test.ts(nightly tier) is the card's acceptance, end to end.os serve --devboots a project whoseclm_version.fileis required and seeds two versions from one fixture. It then checks:GET /storage/files/:fileIdreturns the fixture's bytes, so the file is stored, committed and owned.serve.tsmirror removed, the same boot seeds 0 rows.Local verification
The head is
2d0dd7dd, which merges cleanly with currentmain. It differs fromb8fe94f8only by the changeset's two declaration lines, with no code change.b8fe94f8.dispatch-gates --commandsderives 140 commands for this diff, and 139 of them exit 0.check:dual-build-cjs-loadsexits 3 because it needs a full workspace build, so it is left to CI.dispatch-gates --ranreconciles all 140, with 0 unrun.2d0dd7ddand exit 0:check-adr-0087-registration --base origin/main,check-changeset-no-major --base origin/main,check-empty-changeset --base origin/mainandcheck:changeset-gate-self-tests.b8fe94f8(packages/qa/dogfood): 296 files passed and 3 skipped; 2523 tests passed and 18 skipped.@objectstack/metadata-protocol: 267 files; 21554 tests passed and 19 skipped.@objectstack/service-storage: 66 files; 1206 tests passed.@objectstack/runtime: 457 files; 8352 tests passed and 19 skipped.@objectstack/cli: 506 files, 0 failed tests.a7fc798d. The commits after it touch no CLI file, and their only source changes are type-level: an annotation in the storage plugin and type aliases inseed-file.zod.ts.b8fe94f8.OS_TEST_TIERS=nightly: 3 tests pass;seed-file.zod, the storage contract): 51 tests pass.The full gate list with exit codes is in the dev report on #25779.
Acceptance notes
.changeset/25779-seed-files.md, are copied verbatim from the Claim.pr-automation.ymlsays to name the kind highest in breaking-ness. By that rule the lines should readClause-②: yes (narrowing)andMetadata-protocol: narrowed.minor, so the release level does not change.not-required (no-migration-prescription)) and a "What to do" line either way.os validateand theos serveconfig-boot mirror;packages/runtimecallers that hand the loader thefield-filesservice;packages/spec/src/contracts/storage-service.ts.packages/runtime/src/seed-loader.tsis not touched.🤖 Generated with Claude Code
https://claude.ai/code/session_012eJQ8dtut5bZsnhFE3XGHF