Skip to content

ADR-0025 M1 — local T0 install loop for first-party, self-signed plugins: os plugin install (signature + integrity, materialize, record), boot-time loader with the tier dispatch point, disable/uninstall, Stripe sample as acceptance #27123

Open

Description

@objectstack-fleet

Ruled: 6467932167 · letter B′ · 2026-10-28T11:35Z

Part of #27108 (M1). Filing gate: ③ maintainer-directed — ruling 6461953053 on objectstack#26553 (「插件包分发 同意,应该立专题卡吧?」) and ADR-0025 v2 §3.5 / §4 (PR #27118, merged). Filed by the director seat (session_01KrKXQVvgYk2AJ4VkqMobyb, ledger objectstack#12708). ⛔ Not a claim. ⛔ No domain:*: the work spans packages/cli and packages/core / packages/runtime; triage grades and sets the lane(s) and may split this card by lane. Dedupe: #17757 (closed design card), #13457 (closed, F4 registration); no open card carries the install loop.

维护者速读

本地安装闭环,只限首方/自签插件(T0,node):os plugin install ./x.osplugin → 校验整包 Ed25519 签名与逐文件 integrity → 落盘 <OS_HOME>/plugins/<env>/<id>/<version>/ → 写安装记录 → 下次启动加载器扫描、dynamic import dist/index.mjs、走现有 plugin-loader 的依赖排序,带 tier 分派点(本期只接 node)→ 禁用/卸载复用包的 disable-state store。验收:cloud 的 plugins/connector-stripe 样例装得上、跑得起、禁得掉。⛔ 不上任何市场面;T0 = 宿主进程内跑作者代码。

What lands (ADR-0025 v2 §3.5 M1, §3.3, §3.6)

  1. os plugin install ./x.osplugin (packages/cli/src/commands/plugin/install.ts): read the archive (readTarGz, today publish-only); verify the whole-artifact signature from the .sig sidecar against the host's trusted keys via verifyPluginArtifact (packages/core/src/security/plugin-artifact-signature.ts, first production caller); re-verify every file against integrity at unpack; refuse on any mismatch; --trust-unsigned as the explicit dev override, logged loudly. Materialize to <OS_HOME>/plugins/<env>/<id>/<version>/. Write the installation record (sys_package_installation shape, v2 §3.8) to the local store (ADR-0016 §9.7 package-state-store.ts pattern).
  2. Loader (packages/core / packages/runtime): at boot, scan installed plugins, dynamic-import dist/index.mjs, reuse plugin-loader.ts dependency ordering and health checks; a tier dispatch point that M1 wires for runtime:'node' only and that refuses sandbox / worker with a clear message until M3 (no silent in-process fallback). Load-time signature check becomes a real verification (today format-only, plugin-loader.ts:512–535).
  3. Disable / uninstall through the package disable-state store; uninstall removes the materialized dir on next boot.
  4. Retire the build-side manifest-deps half (build.ts:159–207; Q6) and add the native-addon refusal to os plugin build (v2 §3.3).
  5. Delete the self-descriptions as they stop being true: manifest.zod.ts integrity "NOT RE-VERIFIED AT UNPACK… there is no os plugin install", PluginRuntimeSchema "nothing dispatches on the tier" (replace with the M1 wording: node dispatched, others refused until M3).
  6. Acceptance: an e2e that builds, signs (test key), installs and boots the cloud plugins/connector-stripe sample on a standalone stack, exercises one of its tools, disables it, and asserts the tamper cases (bad signature, bad integrity, sandbox tier) are refused.

Not in M1

  • Cloud download route, os plugin install <id>@<version> — M2.
  • Per-plugin SecurePluginContext enforcement — M2 (M1 loads first-party code with the enforcer registered, as today).
  • T1 / T2 tiers, publish scans, secret-refs — M3.
  • Any marketplace listing of installed plugins.

Acceptance

  • os plugin install + loader + disable work end to end on the Stripe sample (e2e in CI).
  • Tamper cases refused with one diagnostic each; --trust-unsigned logs the override.
  • The listed self-descriptions are deleted in the same PRs; no new "NOT ENFORCED" prose is added.
  • ADR-0025 v2 §3.5 M1 bullet becomes a ✅ line in a one-line docs follow-up (Tier H).

Size: L (two or three PRs; triage may split by lane: cli install command · core/runtime loader · build retirements). Clause-②: no (no authorable key changes; PluginPackagingSchema narrows to bundled — if that is judged a spec narrowing, the lane declares the arm). Metadata-protocol: none.

Related

#27108 (epic, Q1–Q3, Q6), ADR-0025 v2 §3.3 / §3.5 / §3.6, ADR-0016 §9, #26553 ruling 6461953053, cloud plugins/connector-stripe.

Activity

  1. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Triage: p1 kept · lane domain:server · area:devpath · 2026-10-28T07:59Z

    ⛔ Not a claim.

    • Read fresh. ADR-0025 M1, maintainer-directed (ruling 6461953053): the local T0 install loop for first-party, self-signed plugins (os plugin install, signature and integrity, the boot loader with the tier dispatch point, disable and uninstall).
    • Lane: packages/cli, packages/core and the runtime loader, all in domain:server. No cloud step: M1 is local-only, so the cloud routing rule (pm-dispatch(triage + lanes): any card that involves cloud is routed to the cloud PM (domain:cloud + status:parked), never to an objectstack lane #26762) does not apply. M2 and M3 do.
    • ⛔ The signature check is the first production caller of verifyPluginArtifact. A failed or absent signature refuses the install; there is no "unsigned with warning" arm.
    • domain:server, area:devpath.

    Generated by Claude Code

  2. added
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Oct 28, 2026
  3. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 5 · card thread · slice 1 of 3 · lane refill under the shared cap of 4
    Session: session_0186vfjHHMsRXC9EUT9hTFMo (the seat); the card thread is session_01FEkQ5nwY7dd2EmDhaAqt2j
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-7vyd1w (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#2
    Ruling-ref: triage 6463804227 (p1 kept, area:devpath: "⛔ The signature check is the first production caller of verifyPluginArtifact. A failed or absent signature refuses the install; there is no 'unsigned with warning' arm"), under ruling 6461953053 on #26553 (M1 local T0 install loop, Q2 local first, Q3 T0 only). Seat slicing, under the card's "triage may split" line: ① os plugin install verify, materialize, record (this claim); ② boot loader, tier dispatch point, real load-time signature check, disable and uninstall, Stripe e2e; ③ build-side manifest-deps retirement and native-addon refusal. Slices ② and ③ get their own claims.
    File surface: packages/cli/src/commands/plugin/install.ts (new) and its command registration, packages/cli/src/utils/osplugin.ts (reader reuse only), a local installation-record store beside the ADR-0016 §9.7 package-state-store.ts pattern, the manifest.zod.ts integrity prose that this slice falsifies, tests, and changesets per package the diff publishes from. ⛔ No loader, no tier dispatch, no os plugin build edit, no cloud download route
    Container & model: L, mode:thread, default model and effort (set at thread open)
    Clause-②: no (expected; the dev measures and declares the arm, incl. a first-reader spec shape for the record if one is needed)
    Metadata-protocol: none
    Responsibility: the local T0 plugin install command (slice 1 of #27123)
    Thread-read: 6463804227
    Premise: holds (read 2026-10-28T08:59Z at origin/main b15b2fcd: card open, unassigned, pm:queue with its triage line; packages/cli/src/commands/plugin/ holds only build.ts, publish.ts, sign.ts; verifyPluginArtifact has no production caller); the dev re-measures it first, and a refutation is a premise_still_valid: false hand-back
    Resume-from: none — fresh from origin/main
    Serial constraints cleared: yes — open PRs touching packages/cli/src/commands/plugin/** or plugin-artifact-signature.ts at this read: none known; the dev re-measures before the first edit and before pr_create

    State: pm:queue → pm:dispatched, assigned to os-project-manager, in this act. The card stays open across the three slices; each PR says Part of #27123.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 27123,
    "status": "needs_decision",
    "branch": "claude/project-thread-7vyd1w",
    "pr": null,
    "session": "session_01FEkQ5nwY7dd2EmDhaAqt2j",
    "premise_still_valid": true,
    "summary": "Slice 1 of 3 (os plugin install) stopped before the first edit on the order's first stop-and-report line: the host has no trusted-key source a local install can read, and ADR-0025 v2 section 7 defers designing one to M3 ('the host's trusted root set and its rotation / revocation are designed with the T1 tier'). The rest of the premise holds at origin/main 38490db: packages/cli/src/commands/plugin/ holds only build.ts, publish.ts, sign.ts; verifyPluginArtifact has no production caller (git grep finds only its definition outside tests); no open PR touches the claimed surface. The second stop line does not fire: the record is writable locally (see open question note). No code, no commits, no PR.",
    "tests": "none run: stopped before any edit (order stop line 1). Measurements only, all on origin/main 38490db in the card-thread worktree.",
    "gates": "none run: no diff.",
    "dogfood_battery": "n/a: no diff",
    "mcp_calls": "0",
    "api_writes": "1: POST repos//issues/27123/comments (this report, via scripts/pm/post-stamped.mjs)",
    "open_questions": [
    {
    "status": "needs_decision",
    "question": "Where does os plugin install read the trusted publisher keys that verifyPluginArtifact checks the .sig against? MEASURED, what exists: (1) the SIGN key: os plugin sign --key takes the publisher's Ed25519 PKCS#8 private PEM from a path and --key-id (default 'default') is embedded in the signature as ed25519:KEYID:B64; the public half is never written anywhere. (2) The CLOUD keys: cloud verifies the publisher signature at publish and counter-signs with the platform key at approval (publish.ts header, ADR section 3.4); both the publisher-key registry and the platform key live in objectstack-ai/cloud, unreachable from this session and not readable by a local host. (3) CONFIG: none that a host reads. verifyPluginArtifact takes keys only from its caller (platformPublicKey, getPublisherPublicKey) and has no caller; PluginSignatureVerifier.trustedPublicKeys (core, RS256/ES256, a different contract) has no production construction site; spec PluginSecurityPolicy codeSigning.allowedSigners is identities, not keys, with zero readers; no env var, stack-config key or OS_HOME file names a trusted key. ADR-0025 says 'Host ships trusted root keys' (section 3.7) and 'publisher key or an explicit --trust-unsigned dev override' for local artifacts (section 3.5 local-first parity), but section 7 defers the host root set to M3.",
    "options": [
    "A. Operator names the key on the command: os plugin install ./x.osplugin --public-key ./publisher.pub.pem --key-id ID (key-id defaults to 'default', mirroring os plugin sign). The trusted set for this install is exactly that one key. Diagnostics stay distinct: no .sig = no signature; signature keyId differs from --key-id = untrusted key; bytes fail = bad signature. The record stores keyId plus the SPKI fingerprint, and the materialized dir keeps the original .osplugin and .sig so slice 2 can re-verify at load. Cost: about the same as the order's slice (one flag pair). Invents no persistent host store; M3 designs the root set freely.",
    "B. A local trusted-key ring under OS_HOME (e.g. OS_HOME/trusted-keys/KEYID.pem, populated by hand or a new os plugin trust add command), read by install now and by the slice-2 loader at boot. Cost: plus a store, its file format and maybe a command; it pre-empts the M3 root-set and rotation design that section 7 defers, and M3 must migrate or retire it.",
    "C. A stack-config key (defineStack plugins trustedKeys map). Cost: a new authorable spec surface (Clause-2 and Metadata-protocol both move, first reader D5), keys inside project metadata, and the same M3 pre-emption as B.",
    "D. M1 ships only --trust-unsigned (no verification arm). Contradicts triage 6463804227 ('the first production caller of verifyPluginArtifact'); listed only to rule it out."
    ],
    "recommendation": "A. Four axes. Real business need: the only M1 consumer is a first-party developer installing their own self-signed Stripe sample on their own machine (ruling Q1, Q3); they hold the key pair in hand, and nobody yet needs a persistent multi-key ring (that pull arrives with M2 cloud fetch and the platform key). Long-term soundness: A adds no host store, so M3 designs the root set and rotation without a legacy store to migrate; B and C create exactly the surface section 7 deferred. Preventing AI mistakes: A is explicit per install and refuses loudly (missing key = refusal naming --public-key or --trust-unsigned), with no default or fallback source an author could misconfigure silently; C would put trust material into metadata an AI writes. Startup focus: A is the smallest surface that makes verifyPluginArtifact's first caller real; B/C expand capability without pull. Trade-off stated honestly: with A the slice-2 boot check re-verifies against the key recorded at install, so it proves the materialized files are the signed bytes, not that the key is still trusted; a revocation story is M3's either way."
    }
    ],
    "out_of_scope_findings": [
    "class: none, noted only, for the seat's slice planning: the record shape is recordable locally without a new schema. sys_package_installation is a cloud-owned row (spec retired cloud/PackageInstallation in v18, #16325); its v2 section 3.8 fields are env_id, version_id, granted_permissions, status. Locally there is no sys_package_version row, so version_id has to be a derived local id (e.g. ID@VERSION), and granted_permissions equals the declared set per v2 section 3.5 ('there is no partial grant'). The writer (cli) and the slice-2 reader (runtime) share the shape, so it should live beside package-state-store.ts in runtime (internal, like that store) rather than in spec. carrier: none",
    "class: none, noted only: integrity re-verification can reuse core's existing verifyIntegrity / formatIntegrityViolation (already called by os plugin publish), and OS_HOME resolves through runtime's resolveObjectStackHome (OS_HOME env, else ~/.objectstack), which the cli already imports in serve.ts. carrier: none"
    ]
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    待裁:本地安装插件时,用哪把公钥验签

    domain:server 席位 2 · session_0186vfjHHMsRXC9EUT9hTFMo · 2026-10-28T09:06Z · 来源:切片 1 的 os-dev-report 6464930591(needs_decision,未写代码、无 PR)。

    一句话问题: M1 要求 os plugin install ./x.osplugin 先验签再安装,但宿主今天没有任何地方存放"信任哪把公钥",ADR 又把这个信任根的设计推到了 M3。所以安装命令拿不到可以验签的公钥。

    背景与 Governing text

    ADR-0025 v2(docs/adr/0025-plugin-package-distribution.md)有两处相关规定:

    • §3.5 Local-first parity(L281–283): "signature verification is still performed (publisher key or an explicit --trust-unsigned dev override)"。
    • §3.5 M1 段(L297–302): "verify the whole-artifact Ed25519 signature against the host's trusted keys … --trust-unsigned as the explicit dev override"。

    但 §7(L629–631)写着:"Key management & rotation — deferred to M3 (publisher keys stay with the publisher; the host's trusted root set and its rotation / revocation are designed with the T1 tier)"。

    另有两条在先裁决:

    • 分诊 6463804227: "⛔ The signature check is the first production caller of verifyPluginArtifact. A failed or absent signature refuses the install; there is no 'unsigned with warning' arm"。
    • 裁决 6461953053: Q1 首个消费者是首方 Stripe 样例,Q3 规定 M1 只做 T0。

    协议声明: 选 A、B 都不改 spec。选 C 会新增可编写的 spec 面,Clause-② 与 Metadata-protocol 都会变。

    前提(每条带 re-check 命令)

    1. verifyPluginArtifact 的公钥只由调用方传入,且仓内没有生产调用方。
      re-check:git grep -n "verifyPluginArtifact(" origin/main -- packages ':!*.test.ts',预期只有定义处 1 行。
    2. os plugin sign 只读私钥 PEM 与 --key-id,公钥不落盘。
      re-check:git grep -n "key-id\|publicKey" origin/main -- packages/cli/src/commands/plugin/sign.ts。
    3. 宿主没有任何可读的信任公钥来源(env、stack 配置、OS_HOME 文件都没有),spec 里的 codeSigning.allowedSigners 读者为 0。
      re-check:git grep -n "allowedSigners" origin/main -- packages ':!packages/spec',预期 0 行。
    4. 发布者公钥登记表与平台副签钥都在 cloud 仓,本地宿主读不到。来源是 publish.ts 文件头与 ADR §3.4,未在 cloud 仓实测。

    选项 × 真实代价 × 工作量

    选项 做什么 客户可感知后果 工作量
    A 每次安装由操作者点名公钥:--public-key ./pub.pem --key-id ID(与 os plugin sign 对称)。本次安装只信这一把。安装记录存 keyId 与 SPKI 指纹,落盘目录保留原 .osplugin 与 .sig,供切片 2 在启动时复验 开发者装自己的插件时多带一个参数。缺钥匙会响亮拒绝,并提示 --public-key 或 --trust-unsigned server 车道 · 仍是 3 个 PR,切片 1 加一对参数,与原令相当 · 无先例
    B 在 OS_HOME/trusted-keys/ 下建本地钥匙环,手放或新增 os plugin trust add 命令,安装与启动都读它 一次登记,以后都不用带参数 server 车道 · 切片 1 加一个存储、一种文件格式,可能再加一个命令 · 无先例;M3 设计信任根时要迁移或退役它
    C 在 stack 配置里加 plugins.trustedKeys 公钥写进项目元数据 跨 spec 与 server · 新增 spec 面,首个读者 D5 · 无先例;同样抢跑 M3
    D M1 只做 --trust-unsigned,不验签 没有真实验签 最小,但违反分诊 6463804227,只为排除而列

    业务含义直译

    • A: 像 gpg --verify 时手里拿着对方给的公钥,当场核对。
    • B: 像在本机建一个 known_hosts,先登记,后免问。
    • C: 像把信任的签名人写进项目代码仓。
    • D: 不核对签名。

    四维分析(业务立场)

    • ① 长远合理性(领起): 两年后,平台的信任根应该是"宿主内置平台根钥,加上 cloud 副签的发布者链"。这正是 §3.7 写的 "Host ships trusted root keys",与 VS Code、JetBrains 插件市场的做法一致,由 M3 统一设计。
      • A 不留下任何持久的宿主存储,M3 可以从零设计,没有遗留要迁。
      • B、C 恰好造出了 §7 推迟的那块面,M3 必须迁移或删除。
    • ② 业务拉动: M1 唯一的消费者是首方开发者,在自己机器上装自己签的 Stripe 样例。他们手里就有密钥对,今天没有人需要持久的多钥匙环。这个拉动要到 M2 云端下载、平台钥出现时才会来。
    • ③ 防 AI 犯错: 出错时谁看到什么?
      • A 每次显式点名,缺钥匙、钥匙不对、字节不对各有一条响亮拒绝。
      • C 把信任材料放进 AI 会编写的元数据,一旦写错就静默信任。
      • B 的默认来源也可能被悄悄配错。
    • ④ 不扩散: A 是让 verifyPluginArtifact 首个调用真实成立的最小面。B、C 在没有拉动时扩张能力面。

    只看①选 A;②③④ 是否翻转:否。

    os-decision-facets

    • ① 项目长远合理性:A 不新增宿主信任存储,M3 设计信任根时无遗留;B、C 抢跑 §7 推迟的面,扩大契约。
    • ② 实际业务拉动:今天只有首方开发者装自签样例,钥匙在手;持久钥匙环零拉动,所以 defer。
    • ③ 防 AI 犯错:A 显式点名,三类失败各自响亮拒绝;C 让 AI 写的元数据承载信任,错了是静默信任。
    • ④ 创业阶段不扩散:A 只加一对 CLI 参数;B、C 各是永久义务(存储格式、命令或 spec 键)。

    Prior rulings read: trusted key|trust-unsigned|root set|allowedSigners in AGENTS.md, docs/adr, packages/spec/src → ADR-0025 L281–283 / L297–302 / L347 / L629–631, spec codeSigning.allowedSigners; ruling 6461953053, triage 6463804227; thread: 1 (6464930591)

    推荐:A

    置信缺口: 选 A 后,切片 2 在启动时用安装时记录的钥匙复验,证明的是"落盘文件就是当初签名的字节",不证明"这把钥匙至今仍可信"。吊销属于 M3,四个选项在这点上都一样。

    不取其余选项的理由:

    • B: 造一个 M3 必须迁移的存储。
    • C: 让信任材料进入元数据。
    • D: 违反分诊。

    裁后执行

    裁 A 后,席位按原切片计划重派切片 1,在令中写入这几条:

    • 增加 --public-key 与 --key-id(缺省 default)。
    • 缺钥匙且未带 --trust-unsigned 时拒绝。
    • 安装记录存 keyId 与 SPKI 指纹,落盘目录保留 .osplugin 与 .sig。

    dev 先验证上面的前提 1–3,任何一条不成立就报 fork,⛔ 不悄悄改走 B 或 C。切片 2、3 不变。


    Generated by Claude Code

  6. 26 remaining items

  7. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Triage: retriage answer · cross-domain exception granted, one PR · 2026-10-29T14:01Z

    ⛔ Not a claim. The R743 grade named a remedy without checking its lane boundary, and that is triage's miss. Answered here:


    Generated by Claude Code

  8. added and removed
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Oct 29, 2026
  9. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-sales · session_01L6bhgUCizoYWQVJWjhdR6F

    Claim: PM loop round 2 · card thread · slice 3 (server half) under ruling B′
    Session: session_01L6bhgUCizoYWQVJWjhdR6F (the seat); the card thread is session_01L6bhgWLCWkh3MaLj1qTLCe
    Account: os-sales
    Branch: claude/project-thread-c3umeu (the card thread's harness-pinned branch, from origin/main 4a00b2b7; it names no issue, so this claim is the identity record)
    Worktree: objectstack-issue-27123 in the card thread's own container
    Domain: domain:server
    Seat: domain:server#2
    Ruling-ref: 6467932167 (letter B′); cross-domain exception 6498767357 (triage)
    File surface: packages/cli/src/commands/plugin/build.ts (the manifest-deps forks; the native-addon refusal), packages/cli/src/utils/osplugin.ts (wording); cross-domain, declared under 6498767357: packages/spec/src/kernel/manifest.zod.ts (PluginPackagingSchema → bundled) and packages/spec/liveness/manifest.json (the packaging row); generated reference pages regenerated, never hand-edited (stop on breach; explain in the report)
    Container & model: L, mode:thread, model: default (dispatch-gates --tier: no path-derived mandate), effort: xhigh (p1)
    Clause-②: no (narrowing — owes one contract-review-tier review before the queue)
    Metadata-protocol: narrowed
    Responsibility: n/a — not a defect card
    Thread-read: 6498767357
    Premise: corrected 6498767357 (owed item 2 already done by slice 1; #27569 and #27570 split out; owed item 5 serial behind PR #27246 and not in this slice)
    Serial constraints cleared: none on packages/cli/src/commands/plugin or manifest.zod.ts (no open PR); i18n-extract.config.ts left alone (PR #27246)
    Resume-from: none (Release 6496079064: slice 3 starts from main)

  10. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-sales · session_01L6bhgUCizoYWQVJWjhdR6F

    Claim amendment to 6499525158 (slice 3) · 2026-10-29T14:36Z · File surface increment, declared

    The ADR-0087 disposition triage 6498767357 requires for this narrowing is registered (the repo's precedents for narrowing a published authorable enum value, including the same manifest's manifest-permissions-string-list-removed; not-required (no-migration-prescription) cannot hold because the BREAKING changeset names a FROM → TO). That disposition needs files outside the declared surface, so the claim's File surface adds, under the same cross-domain exception:

    • packages/spec/src/conversions/registry.ts (one D2 conversion stripping packaging: 'manifest-deps' from manifest and packages[].manifest)
    • packages/spec/src/migrations/entries/semantic/ (one D3 semantic entry, the current 18.x file)
    • packages/spec/src/migrations/registry.ts.template (one STEP18_RATIONALE fragment)
    • packages/spec/src/shared/retired-key-removal-version.pin.test.ts (one JOIN row)
    • one new retirement pin test under packages/spec/src/kernel/
    • docs/qa/platform-checklist/areas/cli.json (the checklist item that exercises the manifest-deps fork; it turns false with this change)

    Triage may object here; the thread builds the build.ts half meanwhile. Everything else in the claim is unchanged.

  11. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-sales · session_01L6bhgUCizoYWQVJWjhdR6F

    Claim amendment to 6499525158 (slice 3) · 2026-10-29T16:56Z · File surface increment, declared

    The new kernel retirement pin packages/spec/src/kernel/manifest-packaging-retirement.test.ts (declared in amendment 6499637007) carries a tree-wide absence scan that reads files outside packages/spec, so the derived gate check:cross-package-test-inputs requires it on the spec package's repo-test list. The claim's File surface adds, under the same cross-domain exception:

    • packages/spec/vitest.repo-tests.json (one alphabetically placed entry for that test; the scan's glob is already declared in scripts/cross-package-test-inputs.mjs and turbo.json, as for the precedent package-upgrade-family-retirement.test.ts)

    Everything else in the claim is unchanged.

  12. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-sales · session_01L6bhgUCizoYWQVJWjhdR6F
    os-dev-report

    {
      "issue": 27123,
      "slice": "3 of 3, server half (claim 6499525158; increments 6499637007, 6503048893)",
      "status": "done",
      "branch": "claude/project-thread-c3umeu",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27679",
      "head": "b0bfccdd74d06f63a04a92bfc6350d26c8e42218",
      "base": "origin/main efa2915e (one merge, b3b4af13)",
      "session": "session_01L6bhgWLCWkh3MaLj1qTLCe",
      "premise_still_valid": true,
      "summary": "spec: PluginPackagingSchema narrowed to bundled; manifest-deps is a retired value refused with its prescription at every manifest door (ManifestSchema, defineStack manifest, ArtifactPackageEntrySchema, the install body) and out of the TS input type. D2 conversion manifest-packaging-manifest-deps-removed (toMajor 18, retiredAfter 18.2.0, order 80), D3 entry manifest-packaging-manifest-deps-retired with its STEP18 fragment (order 114), the removal-version JOIN row; liveness packaging row live to planned (one-member precedent), the manifest count shard regenerated. cli: os plugin build loses both manifest-deps forks and refuses a native addon before writing the artifact (a .node module in the esbuild graph with its importers, a bundled package with binding.gyp / gypfile true / a shipped .node, a .node under assets/), every hit named, exit 1, no artifact. Checklist item cli.plugin-manifest-build-contract revision 4; five reference pages regenerated by gen:docs; one changeset (spec minor, cli patch, registered disposition).",
      "tests": "Red on df778ab4 with the fix reverted: spec pin 8 failed / 7 passed (15); cli pin 7 failed / 2 passed (9), the two bundled controls green. Green: spec pin 15/15 (repo project, final head), cli pin 9/9 after a spec rebuild. spec --project local full on the fix: 751 files passed, the 24 failures all in check-liveness.test.ts (stale manifest shard), then gen:liveness-counts and scripts/liveness 12/12 files 359/359; spec test:repo on the final head 87/87 files 1448/1448; merged-head spec pins 81/81 files 2321/2321. cli --project unit 350/350 files 5063/5063; cli integration serve-installed-plugins + plugin/install + schema-migrate.one-shot-family 3/3 files 153/153 (a whole-package cli run hit the 30-minute background limit and was stopped, not counted). spec and cli typecheck with check:test-typecheck exit 0. Ablation A (native-addon refusal disabled, build.ts): cli pin 6 failed / 3 passed, exactly the six addon cases; restored, blob f5cb8ec5 == HEAD, git diff HEAD empty. Ablation B (manifest-deps put back as a live enum member, manifest.zod.ts): spec pins 6 failed / 68 passed; spec rebuilt, ablation-dist-preflight marker present in 2 built files; cli pin 1 failed / 8 passed, exactly the manifest-deps case; restored, blob ed95910f == HEAD, git diff HEAD empty; rebuilt, --absent marker gone from all 580 built files, tree clean. Heavy runs under os-verify-lock slot issue-27123, every cited VERDICT command-exit 0 except the ablation legs (expected 1).",
      "gates": "dispatch-gates --commands: 111 derived, the same list on b3b4af13 and on the final head. First run: 108 exit 0; check:cross-package-test-inputs exit 1 (new pin missing from vitest.repo-tests.json, fixed in b0bfccdd under increment 6503048893), check-plugin-teardown-shape --self-test exit 3 (pinned fixture commit absent from the shallow clone, fetched), check:dual-build-cjs-loads exit 3 (six packages unbuilt, built); all three rerun exit 0 on the final head, with check-changeset-no-major, check-adr-0087-registration and check-empty-changeset. --ran: 111 derived, 111 run, 0 NOT-MEASURED, 0 UNRUN. check-changeset-no-major with the PR body as the event payload: LEVEL AXIS ok (spec minor). pnpm lint repo-wide exit 0; eslint packages/cli packages/spec exit 0; check-nul-bytes OK; check-platform-checklist full OK; check:generated: only the references were stale, regenerated. PR check-runs not read yet: the PR was just opened.",
      "dogfood_battery": "merged tree b3b4af13 (the final head differs by one line in packages/spec/vitest.repo-tests.json) · os-verify-lock VERDICT command-exit 0, held 37m38s · Test Files 351 passed, 3 skipped (354) · Tests 2822 passed, 20 skipped (2842) · no failure; closure built with turbo --filter=@objectstack/dogfood^... (68/68 tasks), no OS_TEST_SHARD",
      "metadata_protocol": "narrowed: Clause-② no (narrowing); the changeset carries the BREAKING banner and the ADR-0087 registered disposition naming both new ids",
      "size": "19 files, +929/-77 (generated included): under 3000, not Tier H by size",
      "merge_tree": "no open PR changes a file this PR changes; 41 of 43 open heads merge clean, 27246 and 27623 conflict with origin/main itself in files this PR does not touch",
      "mcp_calls": "10 GitHub MCP read calls: issue_read x3, pull_request_read x4, list_pull_requests x1, search_pull_requests x2; no write tool (subscribe_pr_activity on 27679 is a harness call)",
      "api_writes": "2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches): pr_create 27679 (draft, no assignees, no labels, no review request; read back 17702/17702 bytes identical, assignees none) and this os-dev-report comment. Two branch pushes, not counted.",
      "open_questions": [],
      "out_of_scope_findings": [
        "ledger drift, not a/b/c: docs/qa/platform-checklist/areas/cli.json item cli.plugin-manifest-build-contract still carries the two negatives saying nothing re-verifies integrity at unpack and nothing dispatches on runtime, both made false by slices 1-2; left untouched in revision 4 and named in its history row · carrier: server seat 2 (os-sales) · noted, not filed",
        "observation: ui/packages/app-shell/src/console/marketplace/marketplaceApi.ts types cloud listing packaging as bundled or manifest-deps in a comment; docs/design/plugin-distribution.md and ADR-0025 still mention manifest-deps (the ADR edit is the Tier H half) · carrier: server seat 2 (os-sales) · noted, not filed",
        "observation: packages/spec/liveness/README.md manifest notes cell says Dead 19 while the generated shard says dead 13; pre-existing, the cell names no packaging set, left alone (outside the claim) · carrier: none · noted, not filed"
      ]
    }

    Generated by Claude Code

  13. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-sales · session_01L6bhgUCizoYWQVJWjhdR6F

    Claim amendment to 6499525158 (slice 3) · 2026-10-29T17:48Z · File surface increment, declared

    The contract review of PR #27679 (6504145955, should-fix 1) names three files in the diff that the claim and its amendments 6499637007 / 6503048893 do not list by name. Each is a mechanical companion of a declared file. The claim's File surface adds them:

    • packages/cli/test/plugin-build-bundled-only.test.ts (the pin for the declared packages/cli/src/commands/plugin/build.ts)
    • .changeset/27123-plugin-packaging-bundled-only.md (the changeset the change owes)
    • packages/spec/liveness/state-counts/manifest.md (the generated shard of the declared liveness row)

    Everything else in the claim is unchanged.

  14. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-sales · session_01L6bhgUCizoYWQVJWjhdR6F

    ACCEPT → PR #27679 (slice 3) comment 6504287105 · head b0bfccdd · 2026-10-29T17:54Z · landing sent (contract review PASS 6504145955). Follow-ups filed: #27684 (ADR-0025 edits, Tier H; this card's owed docs follow-up), #27685 (prose leftovers), #27686 (os plugin install manifest validation). This card stays open for #27684 and the split cards #27569 / #27570.

  15. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-sales · session_01L6bhgUCizoYWQVJWjhdR6F

    Release: session_01L6bhgUCizoYWQVJWjhdR6F · partial landing: slice 3 (the server half, claim 6499525158) merged in PR #27679, and the seat is signing off by maintainer order · pm:queue, so the card's remainder can be claimed
    Resume-from: none (the slice-3 branch merged; nothing of this seat's is unpushed)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:serverDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpm:queuepriority:p1High: required for production / M2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions