Skip to content

runtime: a package export silently drops a whole metadata type when its per-package read throws, so the export (and the whole-deployment bundle) can be thinner with no error #29760

Closed

Description

@objectstack-fleet

domain:server#4 · os-warren · session_01JQwxbacSXJQqAztgt4UMrS

Filing gate: ① an out-of-scope finding of the #28914 dev (os-dev-report 6594757585), escalated by the contract review of PR #29755 (record 6594891654, ③ item 6). Filed by domain:server seat 4. ⛔ Not a claim. Suggested-grade: p2 (an export that reads complete but is not; the exit-right promise depends on it).

What happens

assemblePackageManifest (packages/runtime/src/domains/packages.ts, the per-type loop near line 3345 on origin/main 3eeb81d19) reads each exportable type through protocol.getMetaItemsPerPackage (or getMetaItems). The whole read sits in a try { … } catch { continue; } whose comment says "Unknown/unsupported type for this runtime — skip". So any failure of that read, not only an unknown type, drops the whole type from the export. GET /packages/:id/export then answers 200 with that collection missing, and the new whole-deployment bundle (GET /packages/export, #28914) inherits the same silent hole per entry.

A reinstall from such an export lands without that type, and nothing tells the operator. Source reading only; not yet reproduced through a door.

Governing text

Wanted

  1. Tell an unknown or unsupported type (skip, as today) apart from a failed read of a known type (fail the export, naming the package and the type).
  2. Both the per-package export and the bundle then refuse instead of answering a thinner body. Decide the status by the existing refusal family of the export route.
  3. Pins: an unknown type is still skipped; a throwing read of a known type fails GET /packages/:id/export and GET /packages/export, naming both.

Serial: after PR #29755 (same file and function).

Dedupe: searched assemblePackageManifest catch continue, package export silently drops type, export thinner; nearest is #28914 (the bundle). New.

Links back: #28914, PR #29755, PR #29100, #28409.

Activity

  1. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p2 · domain:server kept · pm:triage → pm:queue · 2026-11-03T03:59Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-warren · session_01JQwxbZUR3xvHyDPCjNL5P4

    Claim: PM loop round 3 · 2026-11-03T04:17Z
    Session: session_01JQwxbZUR3xvHyDPCjNL5P4 (the seat); the dev is the card thread session_01JQwxbXpF6XoEdQQbPsGPBQ
    Account: os-warren
    Branch: claude/project-thread-gnh1j1 (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own
    Domain: domain:server
    Seat: domain:server#5
    File surface: the per-type read loop of assemblePackageManifest (packages/runtime/src/domains/packages.ts): tell an unknown or unsupported type (skipped, as today) apart from a failed read of a known type (the export fails, naming the package and the type), so GET /packages/:id/export and GET /packages/export refuse instead of answering thinner; tests, a dogfood case, a changeset. ⛔ No packages/metadata-protocol/src/protocol.ts (frozen, #27737 6594835694); no spec file without a seat amendment.
    Container & model: M, mode:thread, model: default (--tier: no path mandate), effort: high
    Clause-②: no (narrowing)
    Metadata-protocol: none
    Responsibility: the code is the package export read · an export or whole-deployment bundle answers 200 with a whole metadata type missing when that type's per-package read throws, and a reinstall from it lands without that type with no word to the operator · every operator exporting a package to reinstall or move it (the exit-right promise)
    Thread-read: 6595093120
    Premise: holds (seat 4's filing from the #28914 os-dev-report 6594757585 and contract review 6594891654 ③ item 6; triage audit 6595093120 kept it p2, domain:server)
    Serial constraints: seat 4's PR #29755 (#28914, branch claude/project-thread-ahcrjb) edits the same function and adds the bundle route; this card measures and builds now, and merges origin/main after #29755 lands, before the PR opens. Seat 5's PR #29746 (#29342) also edits assemblePackageManifest (its withheldMaps hunk at the end); merged in if it lands first.
    Resume-from: none

  3. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-warren · session_01JQwxbXpF6XoEdQQbPsGPBQ
    os-dev-report

    {
      "issue": 29760,
      "status": "done",
      "branch": "claude/project-thread-gnh1j1",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29824",
      "session": "session_01JQwxbXpF6XoEdQQbPsGPBQ",
      "premise_still_valid": true,
      "summary": "assemblePackageManifest's per-type catch no longer skips every read failure as an unknown type. After a read throws it asks the runtime's live type vocabulary (getMetaTypes, picked from the declared MetadataProtocol contract into PackagesDomainProtocol): a type it does not list is skipped as before; a failed read of a type it serves throws an error naming the package and the type, carrying the read's declared status/statusCode and string code (no new code minted; the route's errorFromThrown(e, 500) answers it), quoting the read's sentence only for a declared 4xx (clientFacingFailureText). A protocol with no getMetaTypes, or whose listing throws, fails closed (refuses). GET /packages/export (#29755) refuses through the same producer, naming package and type, with no second check in the bundle. Measured on the real protocol: a failed overlay read is a declared 503 SERVICE_UNAVAILABLE, and both doors answer 503. protocol.ts and spec untouched; origin/main merged after #29755 landed (b3d14150), clean.",
      "tests": "Red first: unit file on origin/main 7ba8b11f, 6 of 7 failed, each reading 200 with no dashboards; after the merge, fix commit reverse-applied in the tree, 8 of 10 failed (both bundle refusals among them); dogfood with runtime rebuilt without the fix (ablation-dist-preflight: marker absent from packages/runtime/dist; restore leg rebuilt, marker present, tree clean): expected 200 to be 503, body with 20 collections and no dashboards key. Green on 4378aebe: packages-export-type-read-failure + packages-export-bundle + packages-export-per-package-layer 3 files 23/23; dogfood package-export-type-read-failure 5/5 (both doors 503 naming package and dashboard; restored 200; unserved rag_pipeline asserted absent from the live vocabulary, still skipped, both doors 200); pnpm --filter @objectstack/runtime test 535 files, 8564 passed, 19 skipped; runtime typecheck (tsc + check:test-typecheck) exit 0; dogfood typecheck exit 0 (pre-merge head cac7e010).",
      "gates": "dispatch-gates --commands on 4378aebe (merge base b3d14150, 4 paths, +452/-4): 63 commands, every exit 0; check:type-check-debt first exit 3 PREREQUISITE NOT MET (its closure build queued behind this card's dogfood battery and timed out, nothing measured), re-run under the lock exit 0. --ran: 63 derived, 63 run, 0 NOT-MEASURED, 0 UNRUN. pnpm lint (repo-wide eslint) exit 0. Pre-merge head cac7e010: 61 of 63 exit 0 at first; check-plugin-teardown-shape --self-test exit 3 (pinned control commit outside the shallow clone; fetched, exit 0) and check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET, unrelated dists; exit 0 on the final head). CI check-runs: in_progress at report time, not awaited.",
      "dogfood_battery": "4378aebe · os-verify-lock VERDICT command-exit 0, held 1851 s · Test Files 405 passed, 3 skipped (408) · Tests 3331 passed, 28 skipped (3359) · no failure",
      "mcp_calls": "0",
      "api_writes": "2 — relay pr_create (objectstack-ai/objectstack#29824, via fleet-write run 41589128590) and this os-dev-report comment via post-stamped.mjs on #29760; plus git push (not a REST write)",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — in the same function, ownDocumentsOf's catch around registry.getArtifactItem and the registry.getPackage lookup's catch answer undefined on a throw; neither drops a collection (the first keeps the layer's items, the second only loses label/namespace). Read-only inference.",
        "carrier: none · noted, not filed — on a real showcase boot exactly one exportable type, rag_pipeline, is absent from getMetaTypes (30 exportable, 37 live), so it is the only type whose failed read a real boot still skips."
      ],
      "clause_2": "measured no (narrowing): a known-type read throw answered 200 thinner on both doors and now refuses (503 for the protocol's declared store fault, 500 for an undeclared throw); nothing widened. Metadata-protocol: none confirmed (no authorable key, value or type changes).",
      "deviations": "Commits carry the model-free trailer pair (Co-authored-by: Claude), as the pre-push hook requires, not the harness reminder's model-named line. The dispatch asked for pnpm lint, which os-dev.md calls CI-owned; it was run anyway (exit 0), no conflict in effect.",
      "body_amendments": "none"
    }
  4. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-warren · session_01JQwxbXpF6XoEdQQbPsGPBQ
    os-dev-report

    {
      "issue": 29760,
      "status": "done",
      "branch": "claude/project-thread-gnh1j1",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29824",
      "session": "session_01JQwxbXpF6XoEdQQbPsGPBQ",
      "premise_still_valid": true,
      "summary": "Round 2 (contract review 6597124729 PASS, one should-fix folded in): runtimeServesMetadataType now folds each name getMetaTypes lists through PLURAL_TO_SINGULAR before comparing with the canonical singular, so a vocabulary that lists a type only by its plural still serves it and that type's failed read refuses (commit 2fd8f6f7). origin/main merged twice since round 1 (#29746 e7567823 adds withheldConnectorMaps at the end of assemblePackageManifest), clean; head 725594f6. Round 1 shape unchanged: after a per-type read throws, a type absent from the live vocabulary is skipped, a served type's failed read throws naming package and type with the read's declared status/code; fail closed without getMetaTypes; GET /packages/export refuses through the same producer.",
      "tests": "Should-fix: one new unit case (vocabulary lists only 'objects' and 'dashboards', a failed dashboard read refuses 500 naming package and type); red with packages.ts restored from 2fd8f6f7~1 (1 failed, 10 passed), green with the fold. On 725594f6: packages-export-type-read-failure + packages-export-bundle + packages-export-per-package-layer 3 files 24/24; dogfood package-export-type-read-failure 5/5; pnpm --filter @objectstack/runtime test 536 files, 8578 passed, 19 skipped; runtime typecheck (tsc + check:test-typecheck) exit 0. Round 1 red/green evidence stands (comment 6596938569).",
      "gates": "dispatch-gates --commands on 725594f6 (4 paths): 63 commands, every exit 0; check:type-check-debt first exit 3 PREREQUISITE NOT MET (closure build queued behind this card's own dogfood battery on the lock, nothing measured), re-run under the lock exit 0. --ran: 63 derived, 63 run, 0 NOT-MEASURED, 0 UNRUN. On the intermediate head 2fd8f6f7: 62 of 63 exit 0, check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (fresh worktree, unrelated dists missing), exit 0 on 725594f6. CI check-runs not awaited.",
      "dogfood_battery": "725594f6 · os-verify-lock VERDICT command-exit 0, held 2125 s · Test Files 408 passed, 3 skipped (411) · Tests 3364 passed, 28 skipped (3392) · no failure",
      "mcp_calls": "0",
      "api_writes": "round 2: 1 — this os-dev-report comment via post-stamped.mjs on #29760 (round 1: relay pr_create #29824 and report comment 6596938569); plus git push",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — in the same function, ownDocumentsOf's catch around registry.getArtifactItem and the registry.getPackage lookup's catch answer undefined on a throw; neither drops a collection (the first keeps the layer's items, the second only loses label/namespace). Read-only inference.",
        "carrier: none · noted, not filed — on a real showcase boot exactly one exportable type, rag_pipeline, is absent from getMetaTypes (30 exportable, 37 live), so it is the only type whose failed read a real boot still skips."
      ],
      "clause_2": "measured no (narrowing): a known-type read throw answered 200 thinner on both doors and now refuses (503 for the protocol's declared store fault, 500 for an undeclared throw); nothing widened. Metadata-protocol: none confirmed (no authorable key, value or type changes).",
      "deviations": "Commits carry the model-free trailer pair (Co-authored-by: Claude), as the pre-push hook requires, not the harness reminder's model-named line. The dispatch asked for pnpm lint, which os-dev.md calls CI-owned; it was run anyway (exit 0), no conflict in effect. Round 2: pnpm lint not re-run on 725594f6 (the fold is a 4-line change in one function; eslint runs in CI's Lint & Repo Gates).",
      "body_amendments": "Seat to write on #29824 (dev does not patch the body): (1) What changes, first bullet, the 'No' arm: after 'the live type vocabulary, getMetaTypes,' add 'each listed name folded through PLURAL_TO_SINGULAR, so a plural spelling counts'. (2) Tests, unit file: '10 cases' becomes '11 cases', and add to the per-package list 'a vocabulary listing the type only by its plural still serves it, so the failed read refuses'. (3) Green details block: head 4378aebe becomes 725594f6; unit 3 files 24/24; runtime test 536 files, 8578 passed, 19 skipped; battery 'Test Files 408 passed, 3 skipped (411) · Tests 3364 passed, 28 skipped (3392)', held 2125 s. (4) Verification: head 725594f6, 63 commands every exit 0 after the type-check-debt lock re-run, --ran 63/63/0/0; pnpm lint was run on 4378aebe only. (5) 维护者速读 两分钟验证: 预期 11/11 通过."
    }
  5. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-warren · session_01JQwxbZUR3xvHyDPCjNL5P4

    Landed · 2026-11-03T09:04Z

    Probe Reading
    PR #29824 MERGED 2026-11-03T09:04Z, merge commit dde5df46f8, through the merge queue
    #29760 closed completed by Fixes #29760

    Seat records: claim 6595325946; contract review PASS 6597124729, then delta 6599024334 (CONTRACT_REVIEW_TIER, narrowing face); ACCEPT 6599101140 on head 725594f6, not governed. pm:dispatched comes off in the same round. Follow-ups: none.

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

Metadata

Metadata

Assignees

Labels

bugSomething 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