From cda900353763526749cdf5d5ad78cb17be996a72 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 8 Sep 2026 08:02:50 +0000 Subject: [PATCH 1/2] docs(cli,core): name the future runtime loader as the unpack-time integrity re-verification owner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Five source comments still said unpack-time `manifest.integrity` re-verification was the cloud control plane's obligation. That attribution was corrected in `packages/spec/src/kernel/manifest.zod.ts`, so the repo stated both things at once. Swap the owner clause at all five sites to the future runtime loader (ADR-0025 §3.5 steps 4-7), keeping the `#11331` pointer and the true build/preflight half. Comment prose only: no accept set, export, signature or runtime behaviour moves. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_015QE8qk46e5CHJxyQEUjbf8 --- ...npack-reverification-owner-runtime-loader.md | 17 +++++++++++++++++ packages/cli/src/commands/plugin/publish.ts | 5 +++-- packages/cli/src/utils/osplugin.ts | 12 +++++++----- packages/core/src/security/index.ts | 5 +++-- .../src/security/plugin-artifact-integrity.ts | 11 ++++++----- 5 files changed, 36 insertions(+), 14 deletions(-) create mode 100644 .changeset/unpack-reverification-owner-runtime-loader.md diff --git a/.changeset/unpack-reverification-owner-runtime-loader.md b/.changeset/unpack-reverification-owner-runtime-loader.md new file mode 100644 index 0000000000..6500bbb7e9 --- /dev/null +++ b/.changeset/unpack-reverification-owner-runtime-loader.md @@ -0,0 +1,17 @@ +--- +"@objectstack/cli": patch +"@objectstack/core": patch +--- + +Five source comments in `@objectstack/cli` and `@objectstack/core` stop attributing unpack-time `manifest.integrity` re-verification to the cloud control plane and name the owner this repo has already ruled: the **future runtime loader** (ADR-0025 §3.5 steps 4–7). The enforce leg stays tracked on #11331. + +`packages/spec`'s `manifest.zod.ts` was corrected to that owner in an earlier change, and these five sites were left behind — so the repo stated both things at once. A comment that names the wrong owner costs nobody a build, but it teaches a reader (and a reading AI) to expect a verification that no component performs and that ADR-0025's own status line records as unimplemented. + +- `packages/cli/src/utils/osplugin.ts` — the `.osplugin` packaging docblock, and the `sriDigest` TSDoc. +- `packages/cli/src/commands/plugin/publish.ts` — the integrity-preflight comment. +- `packages/core/src/security/index.ts` — the `verifyIntegrity` export comment. +- `packages/core/src/security/plugin-artifact-integrity.ts` — the verifier's own module docblock, which had explained the module's byte-for-byte portability *by* the wrong owner. It now explains it by the leg itself: the module stays portable to whatever runs unpack-time re-verification. + +**What does NOT change.** The other half of every one of these comments — the digest map is computed by `os plugin build` and self-checked by the `os plugin publish` preflight — is true and is kept verbatim. No accept set, export, signature or runtime behaviour moves; the diff is comment prose only. + +**What moves for consumers, measured on the built output.** `@objectstack/cli` ships `dist/`, and the `sriDigest` TSDoc rides into `dist/utils/osplugin.d.ts`, so an editor's hover on `sriDigest` stops naming the control plane. `@objectstack/core`'s two sites do **not** reach its published bundle — a module docblock and a line comment above an `export {}` are both dropped from `dist/index.d.ts` — so nothing in that package's shipped bytes moves. It is declared here anyway because the pre-correction attribution is quoted in `packages/core/CHANGELOG.md`, a generated record that may not be hand-edited; a changeset naming the package is the only way the correction reaches that published record. diff --git a/packages/cli/src/commands/plugin/publish.ts b/packages/cli/src/commands/plugin/publish.ts index 6d353c0133..ddf94382c3 100644 --- a/packages/cli/src/commands/plugin/publish.ts +++ b/packages/cli/src/commands/plugin/publish.ts @@ -113,8 +113,9 @@ export default class PluginPublish extends Command { // bytes against the manifest's own declared per-file digests before // upload. Absent map = permissive by contract (the field is // `.optional()`; artifacts built before integrity computation stay - // publishable). Unpack-time re-verification remains the cloud control - // plane's obligation (#11331) — this preflight does not discharge it. + // publishable). Unpack-time re-verification is owned by the future + // runtime loader (ADR-0025 §3.5 steps 4–7), not by the cloud control + // plane (#11331) — this preflight does not discharge it. const declaredIntegrity = manifest.integrity; if ( declaredIntegrity !== undefined && declaredIntegrity !== null diff --git a/packages/cli/src/utils/osplugin.ts b/packages/cli/src/utils/osplugin.ts index 7e7ab77413..a5f79b4d06 100644 --- a/packages/cli/src/utils/osplugin.ts +++ b/packages/cli/src/utils/osplugin.ts @@ -16,9 +16,10 @@ * The control plane (cloud) stores this blob opaquely. The per-file * `integrity` map is computed here at build time and self-checked by the * `os plugin publish` preflight; re-verification at install/load-time - * unpack (ADR §3.5 step 5) is the cloud control plane's obligation and is - * not implemented in this repo (#11331). This module owns the two - * contracts the runtime and cloud must agree on byte-for-byte: + * unpack is not implemented in this repo and is owned by the future + * runtime loader (ADR-0025 §3.5 steps 4–7), not by the cloud control + * plane (#11331). This module owns the two contracts the runtime and + * cloud must agree on byte-for-byte: * * 1. The integrity digest STRING FORMAT — Subresource-Integrity style * `sha256-` (matches ADR-0025 §3.2's example). See @@ -43,8 +44,9 @@ export interface ArchiveFile { * Subresource-Integrity-style digest of `bytes`: `sha256-`. * This is the canonical per-file integrity string written into the * compiled manifest's `integrity` map and checked back at the - * `os plugin publish` preflight (unpack-time re-verification is the - * cloud control plane's obligation, #11331). + * `os plugin publish` preflight (unpack-time re-verification is owned + * by the future runtime loader — ADR-0025 §3.5 steps 4–7 — not by the + * cloud control plane, #11331). */ export function sriDigest(bytes: Uint8Array): string { return 'sha256-' + createHash('sha256').update(bytes).digest('base64'); diff --git a/packages/core/src/security/index.ts b/packages/core/src/security/index.ts index d8691e426f..f0258c3ac0 100644 --- a/packages/core/src/security/index.ts +++ b/packages/core/src/security/index.ts @@ -36,8 +36,9 @@ export { // Per-file artifact integrity verification (ADR-0025 §3.2) — pure and // portable like the signature contract above; consumed by the -// `os plugin publish` preflight. Unpack-time re-verification stays the -// cloud control plane's obligation (#11331). +// `os plugin publish` preflight. Unpack-time re-verification is owned by +// the future runtime loader (ADR-0025 §3.5 steps 4–7), not by the cloud +// control plane (#11331). export { verifyIntegrity, formatIntegrityViolation, diff --git a/packages/core/src/security/plugin-artifact-integrity.ts b/packages/core/src/security/plugin-artifact-integrity.ts index 329b3c123f..a3989a4013 100644 --- a/packages/core/src/security/plugin-artifact-integrity.ts +++ b/packages/core/src/security/plugin-artifact-integrity.ts @@ -7,11 +7,12 @@ * `integrity` map (artifact-relative path → SRI-style `sha256-` * digest, the format `os plugin build` writes). Like its sibling * `plugin-artifact-signature.ts`, this module is pure and dependency-free - * (node:crypto only) so it stays byte-for-byte portable to the cloud - * control plane, which owes the unpack-time re-verification leg - * (ADR-0025 §3.5 step 5 — tracked on #11331, NOT discharged by this - * module). The framework caller is the `os plugin publish` preflight: the - * publisher self-checks its own artifact before upload. + * (node:crypto only) so it stays byte-for-byte portable to whatever runs + * the unpack-time re-verification leg — the future runtime loader + * (ADR-0025 §3.5 steps 4–7), not the cloud control plane (tracked on + * #11331, NOT discharged by this module). The framework caller is the + * `os plugin publish` preflight: the publisher self-checks its own + * artifact before upload. * * Verdict semantics: * - absent map (`undefined` / `null`) → ok, `skipped: true` — the field From 43cc17869e7defa0d5949f878853812669dc2506 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 8 Sep 2026 08:27:30 +0000 Subject: [PATCH 2/2] docs(cli,core): keep the corrected owner phrase on one line at every site MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two of the five rewritten comments wrapped `future runtime loader` across a line break, which re-creates the exact hazard this change is about: a line-matching grep for the phrase answers "3 sites", and "none left" is indistinguishable from "already fixed". Pure re-wrap of lines this branch already rewrote; no wording changes. The re-check is now double-anchored — `11331` finds 7 lines (5 source + 2 generated CHANGELOG records) and `future runtime loader` finds all 5 source sites on their own lines. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_015QE8qk46e5CHJxyQEUjbf8 --- packages/cli/src/commands/plugin/publish.ts | 6 +++--- packages/cli/src/utils/osplugin.ts | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/commands/plugin/publish.ts b/packages/cli/src/commands/plugin/publish.ts index ddf94382c3..edfef0169b 100644 --- a/packages/cli/src/commands/plugin/publish.ts +++ b/packages/cli/src/commands/plugin/publish.ts @@ -113,9 +113,9 @@ export default class PluginPublish extends Command { // bytes against the manifest's own declared per-file digests before // upload. Absent map = permissive by contract (the field is // `.optional()`; artifacts built before integrity computation stay - // publishable). Unpack-time re-verification is owned by the future - // runtime loader (ADR-0025 §3.5 steps 4–7), not by the cloud control - // plane (#11331) — this preflight does not discharge it. + // publishable). Unpack-time re-verification is owned by the + // future runtime loader (ADR-0025 §3.5 steps 4–7), not by the cloud + // control plane (#11331) — this preflight does not discharge it. const declaredIntegrity = manifest.integrity; if ( declaredIntegrity !== undefined && declaredIntegrity !== null diff --git a/packages/cli/src/utils/osplugin.ts b/packages/cli/src/utils/osplugin.ts index a5f79b4d06..d988177d8a 100644 --- a/packages/cli/src/utils/osplugin.ts +++ b/packages/cli/src/utils/osplugin.ts @@ -16,10 +16,10 @@ * The control plane (cloud) stores this blob opaquely. The per-file * `integrity` map is computed here at build time and self-checked by the * `os plugin publish` preflight; re-verification at install/load-time - * unpack is not implemented in this repo and is owned by the future - * runtime loader (ADR-0025 §3.5 steps 4–7), not by the cloud control - * plane (#11331). This module owns the two contracts the runtime and - * cloud must agree on byte-for-byte: + * unpack is not implemented in this repo and is owned by the + * future runtime loader (ADR-0025 §3.5 steps 4–7), not by the cloud + * control plane (#11331). This module owns the two contracts the + * runtime and cloud must agree on byte-for-byte: * * 1. The integrity digest STRING FORMAT — Subresource-Integrity style * `sha256-` (matches ADR-0025 §3.2's example). See