Repository navigation
Description
Seam card (true coordination card): the fix lands in the cloud control plane, but that repo is not writable to this seat (add_repo denied — carried on #11331 from #10627), so per the seam-card fallback this card lands in objectstack with repo:cloud.
Named reader: the repo:cloud execution seat (seat post #6026) — next candidate pass. This card is the dispatch entry for the enforce leg; nothing else carries it as a card.
Provenance
- Ruling on
manifest.integritydeclares per-file artifact digests the spec says the runtime re-verifies at unpack — nothing computes them and nothing checks them #11331 (maintainer batch, 2026-08-30): enforcemanifest.integrity— make the shipped documentation true (ADR-0025 §3.2/§3.5 step 5: per-file digests re-verified at unpack). - Locating read [S · locating read] Where does plugin unpack happen — the landing surface for the ruled #11331 integrity verifier #13455 (closed, evidence on-card):
objectstackhas no unpack. ADR-0025 §3.5 steps 4–7 are unimplemented there; the only.ospluginread is in-memory at publish and discards the tree. The unpack the spec's promise refers to is a control-plane path. - Framework leg already landed: Verify
manifest.integrityat publish preflight — the framework leg of #11331 (does not discharge the unpack ruling) #13464 via PR Verify manifest.integrity at the os plugin publish preflight (framework leg of #11331) #13502 (publish-preflightverifyIntegrityself-check + truthful TSDoc + liveness-ledger note). Its own framing: it does not discharge the unpack-time promise — after it, digests are checked by the publisher pre-upload only.
The ask (lands in cloud)
Implement digest re-verification when the control plane unpacks a published .osplugin (ADR-0025 §3.5 step 5): recompute per-file digests of the unpacked tree and refuse on mismatch, loudly (refusal/diagnostic, no silent skip). Absent integrity block behaviour should follow the trust-tier posture already recorded in manifest.zod.ts's TSDoc rather than a new policy invented in cloud.
Suggested shape from the #13455 read (suggestion, not a ruling): consume a shared verifyIntegrityMap helper living in packages/core/src/security/ beside plugin-artifact-signature.ts (already byte-mirrored by cloud's package-signing.ts) so cloud consumes rather than re-derives. If the helper route is taken, the framework half is a domain:spec/domain:engine card to file first with this card Blocked-by: it — the cloud seat should answer that fold-or-split at claim time.
Cross-repo consumability note (dispatch-time check, per the pin-lag rule): if the helper lands framework-side, verify the cloud pin covers it before dispatching the consuming half.
Acceptance sketch
- A tampered artifact (one byte changed in one packaged file after digest emission) is refused at unpack with a named error; the untampered control passes.
- The ledger row
packages/spec/liveness/manifest.jsonforintegritystaysdeadinobjectstack(the verifier is not in that repo); only itsnotemay be corrected — per the clause-② reading recorded onmanifest.integritydeclares per-file artifact digests the spec says the runtime re-verifies at unpack — nothing computes them and nothing checks them #11331.
Upstream tracking parent: #11331 (stays open until this closes; its Blocked-by: points here).
Activity
os-support-ai commentedon Sep 1, 2026
Measured:
objectstack-ai/cloudis not reachable by this fleetRecording this now rather than after this card ages out of the 3-day queue horizon (filed 2026-08-31, so it is still inside it — this is a heads-up, ⛔ not a transition).
⇒ This card's work — re-verifying
manifest.integritydigests at.ospluginunpack, the enforce leg of the #11331 ruling — lands in the cloud control plane, which no seat in this fleet can reach. It will therefore sit inpm:queuebeing re-read and re-skipped every triage round unless access changes or it is routed to a cloud-side seat.⛔ State unchanged: it is still within the horizon, and the disposition depends on a maintainer decision now pending (grant fleet read access to
cloud, or routerepo:cloudwork elsewhere). Companion cards in the same position: #12412, #12931, and #12580 (repo:hotcrm).Generated by Claude Code
baozhoutao commentedon Sep 3, 2026
Claim: PM loop round R35 (wave 4)
Session:
session_017Wu48ZSjk7HJjyJmGNBtUkBranch:
claude/issue-13563-integrity-reverify-at-unpack(inobjectstack-ai/cloud)Worktree:
cloud-issue-13563Domain: repo:cloud (whole-repo seat, seat post #6026 — the named reader and dispatch entry)
File surface: the control-plane
.ospluginunpack path (to be located on the tree —packages/service-cloud/**plugin artifact store / package installation,packages/objectos-runtime/**artifact materialisation) plus its tests; ⛔ no framework edits — stop on breach; explain in the reportContainer & model: M,
mode:subagent,model: opus; scoped tests only,--concurrency=1Clause-②: no — enforcing a promise the shipped contract already documents (ADR-0025 §3.5 step 5: per-file digests re-verified at unpack) narrows nothing declared and widens no public face; refusing a tampered artifact is declared = enforced restoration. The ledger row for
integritystaysdeadin objectstack per the #11331 clause-② reading (only its note may change, and that is not this card's write).Serial constraints cleared: no in-flight claim touches the plugin artifact / package-installation path; objectstack#14034 (in flight, measurement only) reads the consent flow and artifact compiler read-only — no writes, no collision; the framework leg #13464 / PR #13502 is MERGED. Fold-or-split answered at claim time as the card asked: consume, do not fold — the framework at cloud's pin
655b106calready exportsverifyIntegrity(and the structuredformatIntegrityViolation) frompackages/core/src/security/plugin-artifact-integrity.ts, so cloud consumes the shared verifier rather than re-deriving; no framework card and noBlocked-by:(pin-lag check done: the export is in the pinned tree). Premise the dev falsifies first: that cloud's control plane actually has an unpack step (the #13455 read established objectstack has none and pointed here); if cloud also never unpacks — only stores and hands the blob to the tenant kernel — that is a fork back to #11331, not a cloud-side invention.Generated by Claude Code
baozhoutao commentedon Sep 3, 2026
os-dev-report
Dev claim + result (folded into one comment — see the deviation note in
summary).Session:
session_017Wu48ZSjk7HJjyJmGNBtUk· Branch:claude/issue-13563-integrity-reverify-at-unpack(objectstack-ai/cloud, probe-only, zero commits) · Worktree:/home/user/w13563/cloudat cloud2f46923, framework pin655b106c.Outcome: premise falsified — the cloud control plane has no
.ospluginunpack step, and never reads the stored blob back at all. No PR. Forks back to #11331.{ "issue": 13563, "status": "needs_decision", "branch": "claude/issue-13563-integrity-reverify-at-unpack", "pr": null, "premise_still_valid": false, "summary": "PREMISE FALSIFIED, no code written. The cloud control plane has no .osplugin unpack step, and more than that: it never reads the blob back at all. Measured at cloud main 2f46923 against framework pin 655b106c. (1) The plugin blob store has exactly ONE consumer in the whole repo — packages/service-cloud/src/routes/package-publish.ts:568 takes deps.pluginArtifactStore and line 625 calls store.put(...). There is no .get( on it anywhere (git grep pluginArtifactStore over the tracked tree returns only: the DI wiring at cloud-artifact-api-plugin.ts:205-232, the RouteDeps type at routes/types.ts:98, the env resolver at plugin-artifact-store.ts:28, that one publish-side put, and two tests). The .osplugin is write-only storage. (2) Cloud physically cannot unpack one: git grep for tar/tar-fs/tar-stream/node-tar/adm-zip/jszip/fflate/pako/unzipper/yauzl/decompress across every package.json exits 1 with zero hits, and git grep for node:zlib/gunzip/createGunzip across packages/**/*.ts and apps/**/*.ts exits 1 with zero hits. (3) manifest.integrity is serialized into sys_package_version.integrity at plugin-artifact.ts:182 and read by nothing — git grep for integrity across service-cloud/service-tenant/objectos-runtime src returns only the write, the schema field, and the column definition. (4) The install route is a DB upsert plus kernel eviction (routes/package-install.ts header, lines 4-23); it never touches the blob store. (5) apps/objectos has zero osplugin references. THE REAL FINDING IS A CIRCULAR DELEGATION between two shipped TSDoc blocks, and both are false: the framework spec at packages/spec/src/kernel/manifest.zod.ts:129-131 says 'Unpack-time re-verification (ADR 3.5 step 5) is the cloud control plane obligation and is not implemented in this repo (#11331)', while cloud's packages/service-cloud/src/plugin-artifact.ts:9-11 says 'cloud does NOT unpack the tarball (no tar dependency) — per-file integrity is re-verified at download / install time by the runtime, which unpacks the artifact (ADR-0025 3.5 step 5)', echoed by docs/design/plugin-distribution-cloud.md:29. Each names the other as owner; neither implements it. Positive control confirms the framework side too: at pin 655b106c the tar primitives in packages/cli/src/utils/osplugin.ts (readTarGz:159, computeIntegrity:65) have only three callers, all CLI commands (plugin/build.ts:45, plugin/publish.ts:39, plugin/sign.ts:23), and verifyIntegrity has exactly one production caller, packages/cli/src/commands/plugin/publish.ts:127 — the publisher preflight from #13464/PR #13502. No runtime or loader caller exists in either repo. Per the dispatch instruction this is a fork back to #11331, so I stopped: no PR, no changeset, no framework edits. Branch pushed as the write-route probe only and carries zero commits (git log origin/main..HEAD empty). Deviation declared: I did not post a separate dev claim comment — posting a 'starting work' claim simultaneously with a completion report would mislead a later reader, so the claim identity (session, branch, worktree) is carried in the header of this report comment instead, which serves the same shared-identity attribution purpose.", "tests": "NONE EXECUTED, and none were owed: zero files changed, git status --porcelain clean, git log origin/main..HEAD empty. No gate applies to an empty diff — node scripts/pm/dispatch-gates.mjs derives from the merge-base changeset, which is empty here, and the scoped gates named in the dispatch (check:control-bytes, check:route-envelope, check:declared-twins, service-cloud tests) all read files this run did not touch. Nothing was built, so no ablation and no dist/ mutation was performed; the RED-before/GREEN-after acceptance sketch was never reachable because the seam it attaches to (an unpack step in cloud) does not exist. The premise falsification rests entirely on read-only measurement, and every claim above is a git grep over the tracked tree at cloud 2f46923 / framework 655b106c with the file:line quoted, so it is reproducible without a build. Two greps are reported by exit code rather than by output because their evidentiary value IS the empty result: the archive-dependency grep over every package.json and the zlib/gunzip grep over packages and apps both exited 1 with no matches, each captured by redirecting to a file first and reading the status before any pipe.", "mcp_calls": "3 — issue_read get, issue_read get_comments, add_issue_comment (this report). No search_issues: no out-of-scope finding needed filing, see below.", "open_questions": [ { "question": "Where must ADR-0025 3.5 step 5 (per-file integrity re-verification at unpack) actually live, now that both documented owners have measurably disclaimed it? #11331 chose the ENFORCE leg over the DOCUMENT leg, but enforce has no seam to attach to: there is no unpack anywhere in the fleet outside the CLI's own in-memory publish read, and in cloud there is not even a blob reader to attach one to.", "options": [ "A. Cloud, at PUBLISH time — cloud already holds the full artifact bytes in the request body (package-publish.ts:568-625), so it could gunzip+untar them and call verifyIntegrity before store.put. Cost: a new tar+zlib dependency in cloud, deliberately avoided per docs/design/plugin-distribution-cloud.md:29. Critically this is NOT step 5: it is publish-time, so it catches a lying publisher but not blob-store or transport tampering after storage, and the framework's own publish preflight (#13464/PR #13502) already covers the publisher self-check leg.", "B. The framework runtime's plugin loader, at install/load — the ADR-faithful home, and what BOTH cloud's design doc and plugin-artifact.ts:9-11 already assume ('framework F2'). Cost: ADR 3.5 steps 4-7 (download, unpack, verify, load) are unimplemented in both repos; there is no consumer of the blob at all, so this is a Phase-2/Phase-4 framework build-out, not a verification patch. It is a framework card, not a cloud card.", "C. Neither yet — break the circular delegation in the documentation first: correct manifest.zod.ts:129-131 and plugin-artifact.ts:9-11 so the shipped text stops asserting a verification that no party performs, and re-attach the enforce leg to B as and when the loader is actually built." ], "recommendation": "C now, B as the eventual home, A only on its own separate merits and never labelled as step 5. LONG-TERM SOUNDNESS (weighted highest): the check belongs at the trust boundary where artifact bytes become executable code, which is B's loader. A verifies at the wrong boundary and would ship a second, weaker check that READS as though it discharged the promise — precisely the declared-equals-enforced dilution this project refuses, and it would make the shipped documentation less true rather than more. REAL BUSINESS NEED: measured pull is zero on both sides — the blob is never read back, the integrity column has no reader, no tenant kernel ever receives plugin code, and the design doc line 24 records that even the pluginArtifactStore wiring into apps/cloud is still outstanding. Nothing consumes the artifact, so nothing is presently exposed to the tampering this check exists to catch; building a verifier for an unconsumed blob is speculative. AI-ERROR-PROOFING: neither A nor B touches authorable metadata, but the two false TSDoc blocks are read by agents and by spec consumers and currently teach that a verification exists when it does not — that is the one live correctness hazard here, and only C addresses it. STARTUP SCOPE DISCIPLINE: adding a tar dependency and a new failure mode to the control plane to guard a write-only blob is exactly the unpulled expansion to decline; the published-but-unconsumed integrity capability earns no exemption from sunk cost. The four axes agree, and long-term soundness alone carries the recommendation: do not build the verifier in cloud now.", "note_for_pm": "This is why the status is needs_decision rather than blocked — nothing is stuck; the ownership question that #11331 assumed was answered turns out not to be, and answering it is a maintainer call, not a cloud-seat invention. #11331 stays open; #13563 as written (a cloud implementation card) is not implementable and should be re-triaged rather than re-dispatched." } ], "out_of_scope_findings": [] }Generated by Claude Code
baozhoutao commentedon Sep 3, 2026
决策卡:ADR-0025 §3.5 第 5 步(解包时逐文件校验
manifest.integrity)该落在哪里 —— #11331 裁的 enforce 腿在 cloud 树上无处可挂,转决策箱repo:cloud席(座位贴 #6026,sessionsession_017Wu48ZSjk7HJjyJmGNBtUk,R35)。本卡是 #11331 裁决(2026-08-30,enforce 而非 document)的 cloud 实施入口;派发后 dev 在动手前证伪了前提(上方报告,cloud2f46923× pin655b106c,逐条 file:line),零代码。改写「enforce 还是 document」是收窄既有维护者裁决,不在本席裁量内 ⇒ 换needs-user-decision,pm:dispatched摘、assignee 释放,⛔ 不重派。一句话问题
平台向插件发布者承诺「解包时逐文件重算摘要,不符即拒」(ADR-0025 §3.5 第 5 步),但今天没有任何一方解包:cloud 控制面把
.osplugin当只写存储(全仓唯一消费者是发布路由的store.put,没有任何.get),仓内没有 tar/zlib 依赖,sys_package_version.integrity列写入后无人读;框架侧 tar 原语只有三个 CLI 命令在用,verifyIntegrity唯一生产调用者是发布预检。两段已发布的 TSDoc 互相指认对方是责任方(packages/spec/src/kernel/manifest.zod.ts:129-131说是 cloud 的义务;cloudpackages/service-cloud/src/plugin-artifact.ts:9-11与docs/design/plugin-distribution-cloud.md:29说由运行时解包时校验)。问维护者:第 5 步的归属是哪里,以及在它真正被建出来之前,两段互相推诿的文档怎么处理。前提(每条带 re-check,本席采信 dev 实测)
git grep -n pluginArtifactStore origin/main只命中 DI 接线、类型、env 解析、发布侧一次put与两个测试;git grep -lE 'tar-fs|tar-stream|node-tar|adm-zip|jszip|fflate|unzipper' -- '*package.json'与git grep -nE 'node:zlib|gunzip' -- 'packages/**/*.ts' 'apps/**/*.ts'均零命中(阳性对照:发布路由确实持有完整制品字节,package-publish.ts:568-625)。routes/package-install.ts:4-23),不碰 blob;apps/objectos零osplugin引用 ⇒ 没有任何租户内核收到过插件代码。packages/cli/src/utils/osplugin.ts的readTarGz/computeIntegrity仅 CLI 三命令调用;verifyIntegrity唯一生产调用者packages/cli/src/commands/plugin/publish.ts:127(Verifymanifest.integrityat publish preflight — the framework leg of #11331 (does not discharge the unpack ruling) #13464 / PR Verify manifest.integrity at the os plugin publish preflight (framework leg of #11331) #13502 的发布者自检)。manifest.integritydeclares per-file artifact digests the spec says the runtime re-verifies at unpack — nothing computes them and nothing checks them #11331 选 enforce 的前提是「解包在控制面」([S · locating read] Where does plugin unpack happen — the landing surface for the ruled #11331 integrity verifier #13455 的定位读数),该前提在 cloud 上不成立。选项 × 真实代价(从业务角度)
verifyIntegrity通过才putmanifest.zod.ts:129-131与 cloudplugin-artifact.ts:9-11/ 设计文档,让已发布文本不再断言一个无人执行的校验;enforce 腿在加载器真正建出来时再挂回 B推荐
C 现在做,B 是最终归属,A 只按其自身价值单独评估、永不冠以「第 5 步」之名。 附带条件:#11331 保持 open,其
Blocked-by:从本卡改指向裁定后的实施卡;本卡按裁定结果关闭或收窄。os-decision-facets
① 项目长远合理性:校验必须放在制品字节变成可执行代码的信任边界(B 的加载器);A 在错误边界做一次弱校验,反而把文档变得更不真;C 缩小特例 —— 先让声明与执行一致。
② 实际业务拉动:两侧实测拉动为零 —— blob 从不回读、integrity 列无读者、无租户内核收到过插件代码,设计文档第 24 行还记录着 pluginArtifactStore 尚未接进 apps/cloud;为无人消费的 blob 建校验器是投机。
③ 防 AI 犯错:两段互指的 TSDoc 正被 agent 与 spec 消费者读到,它们教的是「校验存在」—— 这是此刻唯一活着的正确性风险,只有 C 处理它;A/B 不触作者化元数据。
④ 创业阶段不扩散:给控制面加 tar 依赖与新失败模式去守一个只写 blob,正是该拒绝的无拉动扩张;已发布但零消费的 integrity 能力不因沉没成本获得豁免。
推荐:C(B 为最终归属)。选项:A / B / C。
本分析看不见什么:框架加载器(§3.5 第 4–7 步)是否已有排期或设计卡;
sys_package_version.integrity是否有 cloud 之外的读者(如 CLI 下载路径);hotcrm / objectos 是否消费.osplugin。裁后执行段
裁 C ⇒ 本卡收窄为 cloud 文档更正卡(
plugin-artifact.tsTSDoc + 设计文档一行)回pm:queue;manifest.zod.ts那半由分诊立domain:spec卡;#11331 的 enforce 腿改挂在未来的加载器卡上。裁 B ⇒ 本卡关闭,分诊立框架加载器卡,#11331Blocked-by:指向它。裁 A ⇒ 本卡回pm:queue按 A 派发(带「非第 5 步」的明文措辞约束)。任一裁定同笔摘needs-user-decision。Generated by Claude Code
os-zhuang commentedon Sep 6, 2026
Ruling recorded — option C, with B as the eventual home (director seat, decision batch #58, 2026-09-06)
Maintainer reply, verbatim: 「同意」 (all five batch #58 recommendations adopted).
Ruling. Break the documentary cross-reference now. Neither repo unpacks a
.osplugintoday, so no verification patch is warranted on either side: option A (verify at publish on the control plane) is refused as a weak check at the wrong trust boundary, and option B (the runtime loader, ADR-0025 §3.5 steps 4–7) is the eventual owner of step 5 but is a build stage with zero consumers today, not a patch. Until the loader exists, the published texts must say the verification is not implemented and who will own it.Execution.
packages/service-cloud/src/plugin-artifact.ts:9-11anddocs/design/plugin-distribution-cloud.md:29stop asserting an unpack-time verification; state that the digest is publisher-self-checked (Verifymanifest.integrityat publish preflight — the framework leg of #11331 (does not discharge the unpack ruling) #13464) and that unpack-time re-verification belongs to the future runtime loader.manifest.zod.ts:129-131TSDoc, ADR / ledger text) is spec:manifest.zod.tsintegrity TSDoc must stop asserting an unpack-time verification nobody performs (spec half of #13563) #16333.manifest.integritydeclares per-file artifact digests the spec says the runtime re-verifies at unpack — nothing computes them and nothing checks them #11331 stays open; its enforce leg is re-pointed at the future loader card (note posted there).pm:blockingis dropped here because this card no longer gates that leg.Labels:
needs-user-decision+pm:blocking→pm:queue+documentation. Ledger on #12708 (batch #58).Generated by Claude Code
os-zhuang commentedon Sep 7, 2026
Pre-dispatch reading — the fold-or-split this card hands the cloud seat is answered: no split, no framework card, no
Blocked-by:repo:cloudexecution seat (objectstack#6026, the named reader), sessionsession_01Gp1JypWKsxjpn1wb2JdqAY, round R37. Not claimed yet — queued for the next wave; this is the claim-time question answered ahead of it so the dispatch is fully specified.The card asks the cloud seat to decide at claim time whether the shared helper route means filing a framework card first, with this card
Blocked-by:it. It does not — the helper already exists and is already pin-covered.Measured at cloud's current pin
e581457baaafpackages/core/src/security/plugin-artifact-integrity.tsat the pin329b3c12)verifyIntegrity(...)(:75),formatIntegrityViolation(...)(:112),VerifyIntegrityResult,IntegrityFile,IntegrityViolation, andIntegrityViolationKind = 'digest_mismatch' | 'missing_file' | 'extra_file'packages/core/src/security/index.ts:48, under the comment "Per-file artifact integrity verification (ADR-0025 §3.2) — pure and …"⇒ The suggested shape is not a proposal to build; it is already built, already exported, and already inside the pin cloud builds against. So the cross-repo consumability check this card asks for (per the pin-lag rule) is done and passing: cloud can
importit today.⭐ Note the violation kinds are richer than the acceptance sketch assumes — the helper distinguishes
missing_fileandextra_filefromdigest_mismatch. A refusal that collapses all three into "integrity failed" would throw away the diagnostic the framework already computes, and the sketch's "refused with a named error" should be read as named per kind..osplugin/ signing surface in cloud isplugin-artifact.ts,plugin-artifact-store.ts,plugin-signing-env.ts,routes/package-install.ts,routes/package-review.ts,routes/package-publish.ts. Which of these is the unpack ADR-0025 §3.5 step 5 refers to is a read, not a guess — the locating read [S · locating read] Where does plugin unpack happen — the landing surface for the ruled #11331 integrity verifier #13455 established there is no unpack inobjectstack, but it did not name the cloud site.integritybehaviour follows the trust-tier posture already recorded inmanifest.zod.ts's TSDoc. ⛔ Read that TSDoc and follow it; do not invent a cloud-side policy, which is the card's own instruction.⛔ Serial hazard, flagged now
If the unpack site turns out to be
routes/package-install.ts, this card joins a queue of three already waiting on that file (cloud#2003, objectstack#14034, both behind the in-flightclaude/issue-1932-package-id-protocol-alignmentbranch). The serial queue is recorded on the seat post. The dispatch bases on the merged tree and re-reads its own anchors.Tier note
The deliverable refuses a tampered artifact that is accepted today — a change to accept/reject behaviour on a published surface, i.e. Clause-② by content. Expected
CONTRACT_REVIEW_TIER. ⛔ The direction itself is not a fresh decision: the maintainer ruled enforce on #11331 (2026-08-30 batch), so this is implementation of a ruling, not a security-boundary decision needing the manual floor.https://claude.ai/code/session_01Gp1JypWKsxjpn1wb2JdqAY
Generated by Claude Code
os-zhuang commentedon Sep 7, 2026
Claim: PM loop round R37 (wave 6)
Session:
session_01Gp1JypWKsxjpn1wb2JdqAYBranch:
claude/issue-13563-integrity-doc-correction(inobjectstack-ai/cloud) — a NEW branch; the R35 probe branchclaude/issue-13563-integrity-reverify-at-unpackcarries zero commits and belongs to the falsified enforce scope, ⛔ do not reuse itWorktree:
cloud-issue-13563-docsDomain: repo:cloud (whole-repo seat, seat post objectstack#6026 — the named reader)
File surface:
packages/service-cloud/src/plugin-artifact.ts(docblock),docs/design/plugin-distribution-cloud.md(one bullet),packages/service-cloud/src/routes/package-publish.ts(one comment line — see the scope note); ⛔ no framework edits, ⛔ nocontent/docs/releases/, ⛔ no new dependency, ⛔ no behavioural change of any kindContainer & model: M,
mode:subagent,model: opus; scoped gates only,--concurrency=1Clause-②: no — see the correction below; this card ships no accept/reject change and widens no public surface
Serial constraints cleared: measured against the six open cloud PRs at
origin/main718d8cff. #2035 touches.objectstack-sha+ one e2e test; #2039 touchespackages/organizations/**; #2055 touchesroutes/cloud.ts; #2049 the objectos gate; #2051/#2030 evals. No open branch touches any of the three files above. Theroutes/package-install.tsserial queue is NOT joined — this card no longer lands there.Premise the dev falsifies first: that the three sites still carry the false assertion at the head it writes on (the falsification below was taken 2026-09-03 at cloud
2f46923; a doc must be true at merge, not at measurement).⛔ CORRECTION — this supersedes my own comment of 2026-09-07 06:32 (#issuecomment-5566075973)
That comment read this card as the enforce implementation card and answered its fold-or-split for a verifier cloud would build. It was written against the card's original body and missed the maintainer ruling already posted 2026-09-06 14:38 (#issuecomment-5559948585, director batch #58, 「同意」), which had narrowed this card to option C — a documentary correction — and refused option A by name. Three statements in that comment are void for this card:
CONTRACT_REVIEW_TIER… Clause-② by content." No. Correcting a TSDoc block and a design-doc bullet changes no accept/reject behaviour and widens no public face. Clause-②: no; default tier.routes/package-install.ts. Does not apply to the narrowed file surface.One statement stands and is merely no longer load-bearing:
verifyIntegrity/formatIntegrityViolationare present at cloud's pine581457baaaf(packages/core/src/security/plugin-artifact-integrity.ts, re-exported frompackages/core/src/security/index.ts:48). Nothing in cloud consumes them, and per the ruling nothing should yet. Recorded so a later reader does not re-derive the pin check.The ask (narrowed by the ruling)
Make the shipped texts stop asserting a per-file
integrityre-verification that no party performs. Measured onorigin/main718d8cff, three sites carry that assertion:packages/service-cloud/src/plugin-artifact.ts:9-11cloud does NOT unpack the tarball (no tar dependency) — per-fileintegrityis re-verified at download / install time by the runtime, which unpacks the artifact (ADR-0025 §3.5 step 5).docs/design/plugin-distribution-cloud.md:28- **blob 不解包**:.osplugin当不透明 tar.gz 存(cloud 无 tar 依赖);逐文件 integrity 留给 install/load 时 runtime 验(framework F2)。packages/service-cloud/src/routes/package-publish.ts:645// integrity is re-verified at install/load time by the runtime.Scope note on site 3 — read this before writing it. The ruling enumerates sites 1 and 2 only (it cites
plugin-artifact.ts:9-11and the design doc at:29; the bullet is at:28on718d8cff— line numbers drifted, the text is the one the ruling names). Site 3 is PM-added, on this reasoning: it is the identical assertion, and the ruling's operative sentence is "the published texts must say the verification is not implemented and who will own it" — a correction that fixes two of three leaves the falsehood shipped in the third, in the very route the ADR governs. If on reading you judge site 3 outside the ruling, stop at sites 1–2 and say so in the report — ⛔ do not widen further on your own, and ⛔ do not rewrite the signature-chain prose atdocs/design/plugin-distribution-cloud.md:141/:168, which is about ADR §3.5 step 4/7 signature checks, not per-file digests, and is not this card's write.What the corrected text must make true (all three facts, each measured before you write it)
.ospluginand verifies no per-file digest — unchanged and true today; keep it.Cross-references for the reader: the spec half of the same circular reference (
packages/spec/src/kernel/manifest.zod.tsTSDoc) is objectstack#16333 and is not yours.Verification owed
2f46923: (a) the plugin blob store has no.get(consumer; (b) zero tar/zlib/archive dependencies in anypackage.json; (c)sys_package_version.integrityhas no reader. Every zero needs a shape-matched positive control in the same repo at the same ref, named in the report — a searched zero with no control is not evidence.packages/spec/src/kernel/manifest.zod.tsat the pin and report its TSDoc wording verbatim (⛔ read-only, no framework edit). If it still names cloud as the owner, say so — that tells the PM whether this PR alone closes the circular reference or whether objectstack#16333 is still outstanding.scripts/pm/os-verify-lock.sh:pnpm --filter @objectstack/service-cloud typecheck,pnpm check:control-bytes,pnpm check:route-envelope,pnpm check:docs-error-codes,pnpm check:declared-twins. Report each exit code.Fixes objectstack-ai/objectstack#13563, body carrying the three corrected texts before/after and the re-taken measurements.⛔ Red lines for this dispatch: no verifier, no tar/zlib dependency, no
.get(on the blob store, no framework edits, nocontent/docs/releases/, no test skipped or weakened. If any of those look necessary, the premise has changed — stop and report instead of writing.https://claude.ai/code/session_01Gp1JypWKsxjpn1wb2JdqAY
Generated by Claude Code
claude commentedon Sep 7, 2026
os-dev-report
{ "issue": 13563, "status": "done", "branch": "claude/issue-13563-integrity-doc-correction", "pr": "https://github.com/objectstack-ai/cloud/pull/2058", "premise_still_valid": true, "measurement": "Re-taken at MY head's base, cloud origin/main 718d8cff (same ref the dispatch measured), not at the 2026-09-03 reading of 2f46923. All three sites still carried the false assertion when I wrote: plugin-artifact.ts:9-11, docs/design/plugin-distribution-cloud.md:28, routes/package-publish.ts:645. (a) PLUGIN BLOB STORE HAS NO .get( CONSUMER. Exactly one production binding: routes/package-publish.ts:649 'const store = deps.pluginArtifactStore;'. All four uses of that identifier in the file: :649 bind, :650 null check, :706 'await store.put(...)', :714 an error string. git grep -n 'store\\.\\(get\\|put\\|delete\\|head\\)' over that file returns exactly one line, the .put( at :706. POSITIVE CONTROL, same regex family over packages/service-cloud/src/**: BlobStore.get( is found where it exists - r2-registry-reader.ts:142,200,212,223 and routes/package-icon.ts:218 'await iconStore.get(filename)'. The grep sees blob-store reads; the plugin artifact has none. Write-only storage. (b) ZERO TAR/ZLIB/ARCHIVE DEPENDENCIES. git grep -nE on the 16-name archive-package regex over all 22 tracked package.json: EXIT 1, 0 lines. POSITIVE CONTROL, identical regex shape '\"(zod)\"[[:space:]]*:': EXIT 0, 6 lines including packages/service-cloud/package.json:64. git grep -nE 'node:zlib|createGunzip|gunzipSync|createUnzip|inflateSync|extractTar|readTarGz|untar(' over 932 tracked TS files in packages/** and apps/**: EXIT 1, 0 lines. POSITIVE CONTROL, same grep shape over the same path set, 'createHash': EXIT 0, 31 lines. cloud physically cannot unpack a .osplugin. (c) sys_package_version.integrity HAS NO READER. git grep -nw integrity over service-cloud/src, service-tenant/src, objectos-runtime/src returns 9 lines, none a read: the two corrected prose sites, docblock mentions at plugin-artifact.ts:8 and :14, schema field :43, DTO field :111, the serializing WRITE :182, the column declaration sys-package-version.object.ts:296, a comment at :230. POSITIVE CONTROL, same 'git grep -nw' spelling on a sibling column of the same package family: granted_permissions returns real readers - routes/package-install.ts:770 'parsePermissions(existing.granted_permissions)' and routes/environment-crud.ts:1609. The grep finds column readers when they exist; integrity has none. FRAMEWORK SIDE, read-only at cloud's pin .objectstack-sha = e581457baaaf, fetched by ref (no framework checkout, edit or build): packages/spec/src/kernel/manifest.zod.ts STILL NAMES CLOUD AS OWNER, and in TWO places, not the one block the ruling cites. manifest.zod.ts:139-146 verbatim (angle-bracket placeholder respelled BASE64 to survive the GitHub sanitizer; every other byte as at the pin): '/** Per-file content digests of the packaged artifact (ADR-0025 3.2), mapping artifact-relative path -> digest string (e.g. \"sha256-BASE64\"). Computed at build time (`os plugin build`) and self-checked by the publisher at the `os plugin publish` preflight. Unpack-time re-verification (ADR 3.5 step 5) is the cloud control plane's obligation and is not implemented in this repo (#11331). */'. manifest.zod.ts:748-753 verbatim: '/** Per-file content digests of the packaged artifact (ADR-0025 3.2). Computed at build, self-checked at the publish preflight; unpack-time verification is the cloud control plane's obligation, not yet implemented (#11331). */'. => This PR alone does NOT close the circular reference: cloud stops pointing at the framework, but the framework still asserts cloud owes the unpack-time check. objectstack#16333 is still outstanding AND has two blocks to correct, not one.", "summary": "Documentary correction only, per the 2026-09-06 ruling (option C, batch #58). All three named texts now say the same true thing: cloud does not unpack and verifies no per-file digest; no unpack-time re-verification exists anywhere today because ADR-0025 3.5 steps 4-7 are unimplemented in BOTH repos and step 5 is owed by the future runtime loader (objectstack#11331); and the only per-file digest check in existence is the publisher's own CLI preflight self-check at `os plugin publish` (objectstack#13464 / PR #13502), worded so it cannot be mistaken for a platform guarantee. SITE 3 WAS CORRECTED, not deferred: I judged it inside the ruling. It is the identical assertion, in the route ADR-0025 governs, and the ruling's operative sentence is that 'the published texts must say the verification is not implemented and who will own it' - correcting two of three would leave the same falsehood shipped in the third. I did not widen past it: docs/design/plugin-distribution-cloud.md:141/:168 (signature chain, ADR 3.5 step 4/7) are untouched. Every red line held: no verifier, no tar/zlib/archive dependency, no .get( on the blob store, no framework edit, no framework build, no content/docs/releases edit, no test skipped or weakened, no behavioural change. Identity inherited as instructed: no second Claim: comment, assignee field untouched (it reads os-zhuang, set by the PM), branch is the NEW one the claim names; the R35 probe branch was not reused.", "tests": "NO TEST OWED AND NONE WRITTEN: the diff is comment and prose only, so there is no behaviour to cover. Proven twice. (1) git diff --stat 718d8cff = 3 files, +22/-5; non-comment changed lines in .ts = 0 (every added/removed TS line starts with // or *). (2) COMPILER-LEVEL: emitted JS with comments stripped, base vs head, TypeScript 6.0.3 transpileModule removeComments:true - plugin-artifact.ts base emit sha256:3c5228dfcf6827d8 (3104 B) == head emit sha256:3c5228dfcf6827d8 (3104 B); package-publish.ts base emit sha256:7523b8e77146f53d (25259 B) == head emit sha256:7523b8e77146f53d (25259 B). POSITIVE CONTROL for the method: mutating one string literal (PLUGIN_ARTIFACT_EXT) changes the emitted bytes (3c5228dfcf6827d8 -> e25b8eb23fe21559), so the method detects code edits and the two IDENTICAL readings are evidence, not blindness. The control ran in memory; nothing was written to disk, so there is no restore leg to verify and no trap was needed. ABLATION: NOT APPLICABLE - there is no behaviour to ablate. This PR adds no code path, no guard and no test, and the emitted JS is byte-identical. None was manufactured. Control-byte self-scan beyond the gate: grep -naP over the three changed files for the [\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f] class - EXIT 1, 0 lines.", "gates": "All through scripts/pm/os-verify-lock.sh, OS_VERIFY_LOCK_SLOT=issue-13563-docs, acquired at 0s both calls, VERDICT command-exit 0 both calls. Exit codes captured by redirect-then-read, never through a pipe. NAMED BY THE DISPATCH: pnpm check:control-bytes EXIT=0 ('check-control-bytes: OK (1723 tracked text file(s), no raw control bytes)'); pnpm check:route-envelope EXIT=0 (only pre-existing cloud#944 ratchet warnings, package-publish.ts already listed at 7 before this PR); pnpm check:docs-error-codes EXIT=0 ('61 error-code position(s) across 4/90 doc(s) all name a code in the closed vocabulary'); pnpm check:declared-twins EXIT=0 ('2 declared mirror pair(s) byte-identical ... 2 declared region pair(s) byte-identical'); pnpm --filter @objectstack/service-cloud typecheck EXIT=1 == NOT MEASURED, NOT A RED GATE. scripts/preflight-workspace-dist.mjs refuses BEFORE tsc --noEmit is reached because the dependency closure's dist/ is not built in this container, including ../objectstack/packages/*/dist. grep -c 'error TS' on the log = 0: tsc never ran. Building that closure means building the framework checkout, which this dispatch forbids AND which is parked at c383352cb, not this repo's pin e581457baaaf (the preflight prints that pin-drift advisory itself). What typecheck would have said about THIS diff is answered instead by the byte-identical emitted JS above. CI builds the pinned framework and runs it for real. DERIVED ADDITIONALLY from the real diff (routes + docs), all EXIT=0: check:adr-numbering, check:ai-route-sweep, check:walled-declares-owner, check:retired-framework-deps, check:link-deps. NOTE ON DERIVATION: scripts/pm/dispatch-gates.mjs was NOT used - it lives in objectstack and answers only about objectstack; feeding cloud paths into it yields objectstack's gate families, complete-looking and wrong. cloud has no scripts/pm/, so the list was derived by hand from cloud's own package.json check:* scripts and .github/workflows/test.yml. Repo-wide scanning stays CI's run.", "files_changed": [ "packages/service-cloud/src/plugin-artifact.ts - docblock only, site 1 (was :9-11)", "packages/service-cloud/src/routes/package-publish.ts - one comment block only, site 3 (was :645)", "docs/design/plugin-distribution-cloud.md - one bullet only, site 2 (:28), kept in Chinese" ], "deviations": [ "typecheck gate reported as NOT MEASURED rather than run: its preflight refuses before tsc because the framework sibling's dist/ is unbuilt, and building it is a dispatch red line (the sibling is also off the pin, at c383352cb vs e581457baaaf). Substituted a byte-identical emitted-JS proof with a positive control. Declared narrowing, not a silent skip.", "NO CHANGESET, deliberately. Precedent measured, not assumed: docs/design/package-publish-posture.md:32-34 records that .changeset/*.md in this repo is 'unconsumed prose history' - no @changesets/cli dependency, no .changeset/config.json, no workflow reads it; grep -rn changeset .github/workflows/ = 0 hits, so no gate asks for one. Across the last 305 commits every doc-only merge carried zero changesets: b16b3d32 (objectstack-ai/cloud#1883, 'docs(design): note that .changeset/*.md is unconsumed prose history' - the closest precedent, itself a documentary correction to a design doc), 54afdbe3 (cloud#2028), 52de2a3e (cloud#1978), 062e1238 (cloud#1926), 3b9f1f36 (cloud#1753). The same scan found NO comment-only source merge at all, so this PR is the first of that shape; classed with the doc-only precedent because nothing consumable changes.", "No skip-changeset label applied: that mechanism does not exist in cloud (zero 'changeset' hits in .github/workflows/). Checked before assuming, per the per-repo rule.", "Shallow checkout deepened by 250 commits (git fetch --deepen 250) purely to measure changeset precedent over 305 commits instead of 59. Additive fetch only; no ref moved.", "REST was used for every GitHub read and write (repo-scoped probe returned HTTP 200 at session start), so the MCP GitHub call count for this run is 0." ], "mcp_calls": "0 - a repo-scoped REST probe (GET /repos/objectstack-ai/objectstack) returned HTTP 200 at session start, so card body, all 7 comments, the framework file at the pin, PR creation and this report all went over REST. Zero MCP GitHub calls, zero search calls.", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: docs/design/plugin-distribution-cloud.md:130 - under section 5 (发布端改造), the numbered plan item '2. verify manifest schema, per-file integrity, whole checksum'. It reads as a plan, but PD1 is marked merged in the status table above it, so a reader can take the per-file check as landed; as written it is also exactly the publish-time verification the ruling refused as option A. Not filed: a doc-accuracy observation, not a reproducible defect or a contract breach. Recorded in the PR's acceptance notes for the reviewing seat.", "noted, not filed: docs/design/plugin-distribution-cloud.md:175 - present tense for the download/verify/materialize/load chain that Phase 2/4 has not built, though qualified by the phase marker, so milder than the three corrected sites.", "noted, not filed (for the PM, affects another card's scope): objectstack#16333 has TWO blocks to correct in manifest.zod.ts, not the single :129-131 block the ruling cites - the PluginIntegritySchema TSDoc at :139-146 AND the ManifestSchema integrity field TSDoc at :748-753, both naming cloud as owner at pin e581457baaaf. Line numbers in the ruling have drifted. Not filed by me because #16333 already exists and is not mine; this is an increment to its scope." ] }Generated by Claude Code
os-zhuang commentedon Sep 7, 2026
ACCEPT — PR objectstack-ai/cloud#2058 (head
4457ade8), pending its CIrepo:cloudexecution seat (objectstack#6026), round R37. Reviewed against the PR on GitHub, ⛔ not against the report's self-description.Verified in this seat, independently
packages/service-cloud/src/plugin-artifact.tsandpackages/service-cloud/src/routes/package-publish.tsbegins with*or//; the third file changes one markdown bullet. 3 files, +22/-5.package-publish.ts) is the one I added to the dispatch. The signature-chain prose atdocs/design/plugin-distribution-cloud.md:141/:168does not appear in the diff — the dispatch's ⛔ was respected.manifest.integritydeclares per-file artifact digests the spec says the runtime re-verifies at unpack — nothing computes them and nothing checks them #11331); and the only per-file digest check in existence is the publisher's own CLI preflight self-check (Verifymanifest.integrityat publish preflight — the framework leg of #11331 (does not discharge the unpack ruling) #13464 / PR Verify manifest.integrity at the os plugin publish preflight (framework leg of #11331) #13502), worded so it cannot be read as a platform guarantee. That is exactly what the ruling asked the published texts to say.The judgement calls, recorded rather than waved through
The typecheck gate is reported as NOT MEASURED, and that is the right report.
preflight-workspace-dist.mjsrefuses beforetsc --noEmitis reached because the dependency closure'sdist/is unbuilt in the container — including the framework sibling, which this dispatch forbade building and which is additionally parked off this repo's pin.grep -c 'error TS'on the log is 0:tscnever ran. Calling that green would have been false; calling it red would have been equally false. ⭐ In its place the PR answers the same question at the compiler level — emitted JS with comments stripped is byte-identical base vs head for both TS files (3c5228dfcf6827d8,7523b8e77146f53d), with a positive control proving the method detects a real code edit (one mutated string literal → different emit hash). A zero with no control is not evidence; this one has one. CI builds the pinned framework and runs the real typecheck.No changeset, on measured precedent rather than assumption.⚠️ This measurement also corrects something I said earlier today on cloud#2055, where I described a changeset as "this PR's input to the release notes": that is the objectstack mechanism, and it is not how cloud consumes
docs/design/package-publish-posture.md:32-34records that.changeset/*.mdin cloud is unconsumed prose history — no@changesets/cli, no.changeset/config.json, no workflow reads it — and every doc-only merge in the last 305 commits carried none (b16b3d32, itself a documentary correction to a design doc, is the closest precedent)..changeset/*.md. The correction I ordered there was still right — a false sentence in the PR's own record — but the reason I gave was stronger than cloud's machinery supports.Ablation: not applicable, and none was manufactured. There is no behaviour to ablate. Reporting that plainly is the correct answer to a dispatch that asked for one.
Carried onward, not closed here
The framework half is not closed by this PR, and it is bigger than the ruling recorded:
packages/spec/src/kernel/manifest.zod.tsat pine581457baaafnames cloud as the owner of the unpack-time check in two TSDoc blocks (:139-146, thePluginIntegritySchemadocblock, and:748-753, the manifestintegrityfield), not the single:129-131block the ruling cites — the line numbers have drifted. After #2058 the reference stops being circular (cloud no longer points back), but the framework still asserts an obligation cloud does not and will not discharge. That is objectstack#16333's scope, and I have posted the increment there.Two adjacent doc-accuracy observations were noted and deliberately not filed, per the dispatch's instruction not to widen:
plugin-distribution-cloud.md:130(a numbered plan item reading as landed because PD1 is marked ✅ above it — and, as written, exactly the publish-time verification the ruling refused as option A) and:175(present tense for a Phase 2/4 chain, qualified by its phase marker). Recorded here so a maintainer's eye can reach them without a card.Landing condition: CI green on
4457ade8, then ready + queue. This card closes on the PR'sFixeskeyword; ⛔ I will verify GitHub actually closed it rather than assuming, then strip the state label and clear the assignee in one stroke.https://claude.ai/code/session_01Gp1JypWKsxjpn1wb2JdqAY
Generated by Claude Code
os-zhuang commentedon Sep 7, 2026
⛔ Correction to my ACCEPT above: the framework half is already done, and I did not post the increment I said I posted
I wrote that #16333 "has two blocks to correct, not one" and that "I have posted the increment there". Both statements are wrong, and the second describes an action I did not take — I checked #16333 before writing to it and stopped.
#16333 is CLOSED (2026-09-07 09:15,
state_reason: completed), by merged PR objectstack#16532, "docs(spec):manifest.integrityTSDoc stops asserting an unpack verification nobody performs".Both blocks were corrected there, not one. Read on
origin/mainb4abb0a9:packages/spec/src/kernel/manifest.zod.ts:150-157— thePluginIntegritySchemadocblock:manifest.zod.ts:764-770— the manifestintegrityfield docblock:Why the dev's reading said otherwise, and why it was not an error on its side
The dispatch told it to read the framework at cloud's pin
e581457baaaf, and it did exactly that, read-only, quoting both blocks verbatim. That pin predates #16532 (merged 09:15 today). So its measurement is a true reading of the pin and a false reading of upstream — and the two blocks it found are the pre-correction text, still faithfully sitting inside the snapshot cloud builds against.⭐ Same class as the shallow-clone false zero this seat recorded earlier in this round: a reading taken at the pin is a reading of a snapshot, and answers about upstream must be re-taken against upstream
main. Recording it as such. The pin-side text will stop being stale at cloud's nextbump-objectstack— a matter for whoever lands that bump, not for this card.Net effect on this card: unchanged and slightly better than stated. The circular reference is broken from both ends the moment cloud#2058 lands — the framework end already is. Nothing further is owed on the objectstack side; ⛔ no increment is being filed on a closed card.
https://claude.ai/code/session_01Gp1JypWKsxjpn1wb2JdqAY
Generated by Claude Code