Skip to content

QA run · release-18.3.0-w5-export (1/1) · 589049b0 · 2026-11-03 · 0 PASS / 0 PARTIAL / 1 FAIL / 0 BLOCKED / 0 NOT-RUN #29870

Open

Description

@objectstack-fleet

domain:devx#1 · os-warren · session_01JQwxbYeYDjwmf7geACxC5Z

18.3.0 pre-cut re-check, wave 5, card W5-EXPORT: a targeted check of the whole-deployment export and its re-install (#28914 / PR #29755, #29342 / PR #29746, ADR-0146 D8 item 3). Sweep anchor: #27377. Wave-4 comparison: none (new surface, no ledger item covers it).

Environment fingerprint

  • Framework: objectstack-ai/objectstack main @ 589049b023d82c94508bf9fce752ea19069279e5, checked out detached (ui/ the same commit; no console build: every leg is api/cli).
  • Subject CI: push run 41600797636 re-read at 08:58Z: completed / success.
  • Build: pnpm exec turbo run build --concurrency=2 under scripts/pm/os-verify-lock.sh, exit 0, 21m32s (08:27:34Z to 08:49:06Z); check-dev-prereqs green (106 artifacts).
  • Boots, each from its own scratch copy of examples/app-showcase (node_modules symlinked), own OS_HOME, upload root and file DB: OS_PORT=P node packages/cli/bin/run.js dev --ui --seed-admin --no-watch -p P -d file:RUN/data.db
    • source: port 41510, booted 08:49Z;
    • target 1 (re-install by os package install): port 41520, fresh DB;
    • target 2 (re-install by POST /marketplace/install-local, plus probes): port 41530, fresh DB.
  • Personas: seeded admin admin@objectos.ai; a member minted by POST /auth/admin/create-user (+ change-password), holding neither studio.access nor setup.access; anonymous.
  • install-local ledgers landed in each scratch copy's .objectstack/installed-packages/; the tree's examples/app-showcase/.objectstack/ does not exist after the run.
  • Run executed sequentially by one runner (no subagents: one targeted check, one ontology).

Scope

Selector release-18.3.0-w5-export: one targeted check, no ledger item (so no revision to pin). Surfaces: GET /api/v1/packages/export, client.packages.exportAll(), os package export [--out DIR], withheldMaps per entry, POST /api/v1/marketplace/install-local naming incomplete maps, ADR-0146 D8 (a pair's export is GET /packages/X.custom/export).

Ontology built on the source boot:

package how content
com.qa.w5export POST /packages (source authored), ns w5export object w5export_item (title, amount), flow w5export_probe, connector w5export_erp with providerConfig.headers {X-W5-Tenant: …}; all drafted with ?package= and published (publish-drafts 3 published / 0 failed)
com.example.showcase.custom POST /packages/com.example.showcase/ensure-customization (201, ns showcase_custom) object_extension showcase_task adding w5_region__c, published
com.qa.w5local POST /marketplace/install-local (source marketplace) object w5local_thing, flow w5local_probe
com.qa.w5off POST /packages, dependencies: {com.qa.w5export: ^0.1.0} object w5off_note, published, then PATCH /packages/com.qa.w5off/disable (200, enabled: false)

Per-clause verdicts

# clause verdict evidence (text oracle)
E1 as admin, GET /packages/export answers every non-code package once, the disabled one included, code-registered excluded pass 200; order com.qa.w5export, com.example.showcase.custom, com.qa.w5local, com.qa.w5off; GET /packages holds 33 rows, exactly those 4 are not source: code; no id repeated; com.example.showcase and the 28 platform packages absent
E2 dependencies first; a pair after its base pass com.qa.w5off (depends on com.qa.w5export) after it. The pair's base com.example.showcase is code, so the pair is exported alone, as ADR-0146 D8 item 3 (PR #29830 wording) and the bundle docblock say ("A pair of a code base is still exported")
E3 each entry byte-equal to GET /packages/:id/export pass JSON.stringify of each bundle entry equals the per-package data for all 4
E4 withheldMaps names the connector's map, and no header name or value travels pass com.qa.w5export.withheldMaps = [{type: connector, name: w5export_erp, path: providerConfig.headers}]; connector exported as providerConfig: {baseUrl}; the bundle text contains neither X-W5-Tenant nor its value; no other entry carries the key
E5 the disabled package's entry carries its content fail com.qa.w5off entry is {id, name, version, namespace, dependencies} with no objects, while its sys_metadata row object/w5off_note is active. Re-enable: the entry carries objects: [w5off_note]; disable again: empty again. See repro R1
E6 any query parameter is refused 400 VALIDATION_ERROR naming it pass ?foo=1, ?package=…, ?version=1 each 400 VALIDATION_ERROR, The "foo" query parameter is not supported by this endpoint… (each names its own parameter)
E7 a member without studio.access/setup.access → 403; anonymous → 401 pass member 403 PERMISSION_DENIED "Reading packages requires the studio.access or setup.access capability." (per-package export the same); anonymous 401 UNAUTHENTICATED; admin 200 (control)
E8 client.packages.exportAll() answers the bundle pass built @objectstack/client dist, admin token: same 4 ids, JSON.stringify equal to the REST data; an anonymous client throws httpStatus 401, code UNAUTHENTICATED
E9 os package export --out DIR: one numbered directory per package, in dependency order pass exit 0, 01-com.qa.w5export … 04-com.qa.w5off, each objectstack.json equal to bundle entry N; the same --out again refused exit 1 "already holds files"
E10 fresh boot: installing each directory in order lands objects, fields, flows and the pair's extension, served pass target 1, os package install DIR/NN/objectstack.json ×4, all exit 0: w5export_item meta 200 + POST /data 201 + list 200; flows w5export_probe, w5local_probe 200; connector 200 (providerConfig: {baseUrl}); showcase_task serves w5_region__c "W5 Region"; w5local_thing 200. (w5off_note 404: it was never in the export, E5)
E11 the install answer names each withheld map as incomplete, and logs a warn pass target 2, POST /marketplace/install-local {manifest: entry}: com.qa.w5export answers 200 with withheldMaps: [{connector, w5export_erp, providerConfig.headers}], the other three none; boot log WARN [MarketplaceInstallLocal] installed com.qa.w5export managed with 1 connector map(s) the package export withheld whole, each now absent: connector 'w5export_erp' providerConfig.headers… (target 1 logged the same line). The CLI's own output names nothing: see the probe line
E12 re-reading GET /packages/export on the new boot matches the first, modulo withheld values fail target 1: same 4 ids in the same order; com.qa.w5local and com.qa.w5off byte-equal; com.qa.w5export differs only by withheldMaps (expected: the map is absent on the target); com.example.showcase.custom lost objectExtensions although the target still serves w5_region__c and GET /packages/com.example.showcase/customizations still lists it. See repro R2

Reproduction rules

R1 (E5): a disabled package exports as an empty shell. Fresh showcase boot, admin bearer token.

  1. POST /api/v1/packages {"manifest":{"id":"com.qa.w5off","name":"W5 disabled","version":"0.1.0","type":"app","namespace":"w5off"}} → 201.
  2. PUT /api/v1/meta/object/w5off_note?mode=draft&package=com.qa.w5off {"name":"w5off_note","label":"W5 Note","sharingModel":"private","fields":{"body":{"type":"text","label":"Body"}}} → 200; POST /api/v1/packages/com.qa.w5off/publish-drafts {} → 200 published 1.
  3. GET /api/v1/packages/com.qa.w5off/export → 200 with objects: [w5off_note] (control).
  4. PATCH /api/v1/packages/com.qa.w5off/disable → 200 enabled: false.
  5. GET /api/v1/packages/com.qa.w5off/export and GET /api/v1/packages/export.
  • Expected: the entry still carries objects: [w5off_note] (the bundle declaration: "Enabled or not, every such package is exported … an install of the bundle installs every entry enabled").
  • Actual: 200 {"id":"com.qa.w5off","name":"W5 disabled","version":"0.1.0","namespace":"w5off"}, no objects; the sys_metadata row stays state: active. Re-enable → content back. Reproduced three times on the source boot. Installing that entry elsewhere installs an empty package, so the object is lost from the deployment copy with no error.

R2 (E12): an export omits the objectExtensions of a package installed through install-local. Fresh showcase boot, admin bearer token.

  1. POST /api/v1/marketplace/install-local {"manifest":{"id":"com.qa.r2base","namespace":"r2base","name":"r2 base","version":"1.0.0","type":"app","objects":[{"name":"r2base_account","label":"Account","sharingModel":"private","fields":{"title":{"type":"text","label":"Title"}}}]}} → 200.
  2. POST /api/v1/marketplace/install-local {"manifest":{"id":"com.qa.r2ext","namespace":"r2ext","name":"r2 ext","version":"1.0.0","type":"app","dependencies":{"com.qa.r2base":"^1"},"objectExtensions":[{"extend":"r2base_account","fields":{"r2ext_code":{"type":"text","label":"Billing code"}}}]}} → 200.
  3. GET /api/v1/meta/object/r2base_account → fields.r2ext_code.label = "Billing code" (the extension is served).
  4. GET /api/v1/packages/com.qa.r2ext/export.
  • Expected: the entry carries objectExtensions: [{extend: r2base_account, fields: {r2ext_code: …}}], as the export of a pair whose object_extension was authored does (the source pair's export carried objectExtensions: [showcase_task + w5_region__c]).
  • Actual: 200 {"id":"com.qa.r2ext","name":"r2 ext","version":"1.0.0","namespace":"r2ext","dependencies":{"com.qa.r2base":"^1"}}, no objectExtensions. Reproduced on target 2 (this shape), and on the source boot and target 1 with a second package extending w5local_thing. In the round trip: the source pair com.example.showcase.custom exported its extension; installed on target 1 by os package install, it serves w5_region__c, but its re-export has no objectExtensions, so a second export → install hop drops the customization with no error.

Derived verdict

Targeted check: fail (E5, E12 fail; E1–E4, E6–E11 pass).

Off-clause probes (RUNNER rule 8)

About 12 minutes, admin and member personas, on the source and target 2 boots. Boundary classes: missing dependency, out-of-order install, malformed input, failure inside assembly, the CLI install path.

  • Ordering with a missing dependency: POST /packages declaring a dependency on a not-yet-created package → 422 DEPENDENCY_MISSING, nothing installed; installing the dependent export entry (04-com.qa.w5off) before its dependency through install-local → 422 DEPENDENCY_MISSING naming com.qa.w5export ^0.1.0; installing in the served order then succeeds. Holds.
  • Malformed withheldMaps (path: providerConfig.secret) on install-local → 400 PLUGIN_MANIFEST_INVALID naming the allowed positions. Holds.
  • A package whose assembly throws → whole bundle refused: not reached live. Deleting the stored connector row of a published authored package under a running boot left the served read 200 (registry-held), so the export did not throw. The branch is pinned only at the dispatcher-over-stub layer: packages/runtime/src/domains/packages-export-bundle.test.ts 10/10 passed at the subject (incl. both whole-or-absent cases), packages/cli/test/package-export.test.ts 6/6. The per-type silent skip inside assembly is 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 (fix PR fix(runtime)!: a package export refuses when the read of a type the runtime serves fails, naming the package and the type #29824 open).
  • Found: os package install DIR/NN/objectstack.json, the command os package export prints for each directory, says nothing about an incomplete connector map: for 01-com.qa.w5export it printed "Package installed into the running kernel" and the cache path, while the install-local answer it received carried withheldMaps (seen on target 2 through the same door). Extracted, see the close-out.

Fixture gaps / notes for #27377

Reported in the runner's final report for the anchor (proposed ledger item, and three observations), not here.

Activity

  1. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#1 · os-warren · session_01JQwxbYeYDjwmf7geACxC5Z

    Close-out. Both FAILs are product defects (the export breaks its own declared contract), each extracted; the off-clause probe finding is extracted too. No security finding. Checklist-accuracy notes and the proposed ledger item go to #27377 through the runner's final report.

    Extracted: #29871 · release-18.3.0-w5-export · E5
    Extracted: #29872 · release-18.3.0-w5-export · E12
    Extracted: #29873 · release-18.3.0-w5-export · observed beside the clauses
    
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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions