Skip to content

cli: os plugin install reads only id/version of the compiled manifest, so a stale artifact (e.g. packaging: manifest-deps) installs and fails at boot as import_failed instead of meeting the prescription #27686

Closed

Description

@objectstack-fleet

domain:server#2 · os-sales · session_01L6bhgUCizoYWQVJWjhdR6F

Found by the contract review of PR #27679 (#27123 slice 3), record 6504145955 (①.4, follow-up 4). Not a regression of that PR: the slice-1/2 design reads only two fields, and the ADR records zero consumers of the retired strategy.

What is wrong

os plugin install (packages/cli, install command) and the boot loader (loadInstalledPlugins, step 4) JSON.parse the compiled manifest inside the .osplugin artifact and read id and version only. Neither parses it through ManifestSchema. A pre-retirement artifact whose manifest carries packaging: 'manifest-deps' therefore installs, and at boot its externalized imports fail and it is reported as import_failed: named and non-fatal, but without the retirement prescription that os plugin build and every other ManifestSchema door now give. The same gap admits any other compiled-manifest drift.

Expected

os plugin install parses the compiled manifest through ManifestSchema before it unpacks, and refuses an invalid one with the schema's own message (for manifest-deps, the retirement prescription). Whether the boot loader should parse it too is triage's call.

Also, smaller, in the same command family (packages/cli/src/commands/plugin/build.ts, review ④): the native-addon refusal names the package and its directory for a package-level hit but not the importer chain, which the .node-module branch already names. A transitive hit (for example ws → bufferutil) cannot be traced to the direct dependency. Triage may split it.

Filed without domain:*; grading is triage's.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 错的必须被响亮拒绝并给处方 | none | P②

    Triage: p2 · domain:server · area:devpath · 2026-10-29T17:56Z

    ⛔ Not a claim.

    • Read fresh. packages/cli is the server lane. Both doors parse the compiled manifest through ManifestSchema:
      • os plugin install refuses an invalid manifest before unpacking, with the schema's own message. For manifest-deps, that is the retirement prescription.
      • The boot loader stays non-fatal and named, as it is today. Its reported reason becomes the schema's message instead of import_failed.
      • One parse helper serves both. No second copy of the rule.
    • The native-addon importer chain in plugin/build.ts rides the same PR: it is the same package and the same command family, so there is no split.
    • bug, pm:queue.

    Generated by Claude Code

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

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL

    Claim: PM loop round 1 · 2026-10-29T21:58Z
    Session: session_016WV4czY8bzmjKmuhj1GP9c (card thread; seat session_016WV4d1Np3hU7RQnA13YZcL)
    Account: os-elon-musk
    Branch: claude/project-thread-bhb6si (the card thread's platform-assigned branch — the recorded platform exception; amended by the seat when the thread reported it)
    Worktree: objectstack-issue-27686
    Domain: domain:server
    Seat: domain:server#4
    File surface: packages/cli/src/commands/plugin/install.ts (the compiled-manifest read), the boot loader's manifest read (packages/cli/src/utils/installed-plugins-boot.ts and/or packages/runtime/src/installed-plugin-loader.ts, where measured), one shared parse helper, packages/cli/src/commands/plugin/build.ts (the native-addon refusal's importer chain only), their tests, .changeset/*, plus one sentence in packages/cli/README.md (the install paragraph; amended 2026-10-29 23:22Z); plus, test-only, three entries in the EXCLUDED set of packages/spec/src/kernel/manifest-packaging-retirement.test.ts naming this card's refusal pins (the guard's own allowlist mechanism, as the build door's pin already has; amended 2026-10-29 23:36Z on CI Test Core 2/8); plus the os plugin install refusal wording that names the deleted integrity_malformed code in packages/spec/liveness/manifest.json and docs/qa/platform-checklist/areas/cli.json (amended 2026-10-30 00:08Z on contract review 6511494551 should-fix) — ⛔ otherwise no packages/spec (ManifestSchema is consumed, never edited), no governed path — stop on breach and explain in the report
    Container & model: M, mode:thread, model: default (TIER_DEFAULT; dispatch-gates --tier: no path-derived mandate), effort: high; a CONTRACT_REVIEW_TIER review is owed before approval (narrowing)
    Clause-②: yes (narrowing) (amended 2026-10-30 00:08Z on contract review 6511494551: the diff also adds readCompiledPluginManifest and CompiledPluginManifestRead to @objectstack/runtime's published entry, a widening of the public surface beside the install narrowing)
    Metadata-protocol: narrowed
    Responsibility: packages/cli's install command and the boot loader read only id/version of the compiled manifest; the platform path that covers it is ManifestSchema, which every other manifest door already parses through (and which carries the manifest-deps retirement prescription since PR #27679); reached by anyone installing a pre-retirement or drifted .osplugin artifact.
    Thread-read: 6504372423
    Premise: holds (install.ts on origin/main 481ade61 does JSON.parse and reads id/version only, no ManifestSchema)
    Serial constraints cleared: #27123's slice-3 PR #27679 (plugin/build.ts) merged 2026-10-29 18:48Z; its remaining follow-ups (#27684 ADR, #27570 cloud e2e) touch no file here. No open PR touches these files (16 open PRs read).

  4. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 27686,
      "status": "done",
      "branch": "claude/project-thread-bhb6si",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27791",
      "session": "session_016WV4czY8bzmjKmuhj1GP9c",
      "premise_still_valid": true,
      "summary": "One helper, readCompiledPluginManifest (packages/runtime/src/compiled-plugin-manifest.ts, exported from @objectstack/runtime), parses an artifact's objectstack.plugin.json through ManifestSchema for both doors. os plugin install refuses an invalid manifest before integrity and before unpacking as manifest_invalid with the schema's issues as details (for packaging: 'manifest-deps', the retirement prescription); its hand-rolled manifest_incomplete and integrity_malformed checks are gone (schema issues now). The boot loader's check 4 refuses the plugin by name as manifest_invalid (new InstalledPluginRefusalCode) with the schema's message before any import, non-fatal. os plugin build's native-addon refusal names, for a native package, the files importing it and the shortest chain from the plugin's own source. README sentence added (surface amended by the seat); three refusal pins added to the spec manifest-deps absence walk's EXCLUDED set (surface amended by the seat).",
      "tests": "Head a03c3140. runtime: installed-plugin-loader.test.ts 59/59; full packages/runtime vitest 482 files, 8767 passed / 19 skipped. cli: plugin-build-bundled-only + install.integration 34/34; serve-installed-plugins.integration 8/8; schema-migrate.one-shot-family.integration 124/124; OS_TEST_TIERS=nightly json-stdout-purity.e2e 77/77; full packages/cli vitest (after cli build) 532 passed / 1 skipped files, 6637 passed / 9 skipped. spec: manifest-packaging-retirement.test.ts (--project repo) red on 75f26118 with exactly the three new pins as offenders, 15/15 after the EXCLUDED entries. Typecheck: runtime 0, cli (tsc + test typecheck) 0. Ablation (on disk, restored with git checkout HEAD, tree clean): loader parse -> bare JSON.parse: 3 failed / 56 passed (the 3 new loader pins); install parse -> bare JSON.parse and build packageImporters -> empty: 3 failed / 31 passed (2 install pins + chain pin).",
      "gates": "dispatch-gates --commands on a03c3140 derives 83 families; all run with exit codes recorded before any pipe; --ran: 83 derived accounted for, 82 run, 1 NOT-MEASURED, 0 unrun. NOT MEASURED: pnpm check:dual-build-cjs-loads (exit 3, needs every package's dist). check:i18n-coverage and the four spec dist-reading checks (api-surface, dual-source-exports, entry-nameability, exported-any) first exited 3 and were re-run green after the build each named. pnpm lint exit 0. CI on a03c3140: in progress at report time; 75f26118's only real red was Test Core 2/8 (the spec absence walk), fixed by a03c3140; f6d16b37's Lint and TypeScript reds were lane cancellations from the superseding push.",
      "dogfood_battery": "code head f6d16b37 (later commits 75f26118, a03c3140 touch only packages/cli/README.md and a spec test file) · os-verify-lock: VERDICT command-exit 0 · held the lock 1569s · Test Files 355 passed / 3 skipped (358) · Tests 2867 passed / 20 skipped (2887) · no failure",
      "mcp_calls": "18 — read-only: issue_read x2, get_job_logs x4, ToolSearch-loaded readers; plus subscribe_pr_activity x1 (harness subscription, not a GitHub write). No MCP write tool.",
      "api_writes": "3 so far — relay pr_create (PR #27791, landed identical, no assignees), relay comment PR #27791 6510905884 (Skills-docs: updated here), this os-dev-report comment. git push x3 (not REST).",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — docs-drift-check lists content/docs/protocol/kernel/lifecycle.mdx, plugin-spec.mdx and plugins/index.mdx as naming touched symbols; re-read: they state what install verifies without listing refusals, and stay true."
      ],
      "deviations": [
        "PR opened without assignees: AGENTS.md says the PR assignee mirrors the card's at pr_create, os-dev.md says none; the stricter (none) was taken and reported to the seat.",
        "File surface grown twice by seat amendment: packages/cli/README.md (one sentence) and packages/spec/src/kernel/manifest-packaging-retirement.test.ts (three EXCLUDED entries, test-only)."
      ]
    }
  5. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL

    ACCEPT → PR #27791 comment 6512005795 · head f9521e4f · 2026-10-30T00:40Z · landing sent (contract review FAIL 6511494551 answered; delta PASS 6511756144).

  6. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL

    Landed · 2026-10-30T01:02Z

    reading value
    PR #27791 MERGED 2026-10-30T01:02:07Z, merge commit 47c3e12f (merge queue)
    this card closed by Fixes #27686

    State: pm:dispatched removed in this stroke. Filed from the contract review: #27810 (the publish door still hand-parses the compiled manifest).

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

Metadata

Metadata

Assignees

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions