Skip to content

A writable package created via POST /api/v1/packages is registered in memory only — it does not survive a restart, and leaves its published metadata orphaned #17676

Description

@yinlianghui

Blocked-by: #20071

⚠️ State banner, written by the domain:engine execution PM seat at PR #19385's landing (2026-09-20T16:25Z).

What LANDED — PR #19385 (squash fade3da23e, parent count 1, verified on origin/main with a content reading and a negative control), delivering ruling A′ item 3 (the service-ABSENT composition in makeImpl(), four new pins, a service-present control) and item 2's documentation half. ⛔ It carried Part of, never a closing reference, so this card did not close and was not meant to.

What is NOT delivered, and why this card is blocked rather than queued — ruling A′ item 5 (three HTTP probes agreeing across a restart of a booted composition) ⛔ cannot be met by anything until the resolver half lands. 'package-registry' is on PLATFORM_ALWAYS_ON_CAPABILITIES and serve force-appends it, but Serve.CAPABILITY_PROVIDERS has no such key, and the no-provider branch warns only when declaredRequires.has(cap) && !PLATFORM_CAPABILITY_TOKENS.includes(cap) — a force-appended in-vocabulary token fails ⛔ both conjuncts and hits a bare continue. ⇒ the always-on mount is silently inert and a stock boot still takes the in-memory branch. That half is #19387.

⚠️ This Blocked-by: line is in the BODY deliberately. The unlock scan reads the body's line; a card carrying it only in a comment is structurally invisible to that instrument however often it runs — which is why this very card sat blocked for seven days after its blocker discharged. ⛔ Do not move this line into a comment.

⚠️ Also corrected on this card: the dispatch order's assumption that ruling item 1 landing discharged item 2 was the seat's own error, not the dev's reading (comment 5750658581). A landed spec half is not a landed runtime half.


What happens

POST /api/v1/packages returns 201 and the package is fully usable — you can publish object drafts into it, the runtime serves them, the REST endpoints work. But the server logs:

[protocol.installPackage] no 'package' service — '<ns>' registered in-memory only (will not survive a restart)

After restarting objectstack dev, the state is split three ways:

Probe Result
Studio → MY PACKAGES (WRITABLE) No writable packages yet
GET /api/v1/data/<ns>_<obj> 404 Object '<ns>_<obj>' is not registered
GET /api/v1/meta/object/<ns>_<obj>/published 200 — the published object metadata is still there

So the published metadata outlives both the package and the runtime registration. Re-creating the package and re-publishing does recover (the orphaned metadata does not block it), but the intermediate state is inconsistent and Studio gives no signal that anything is wrong — it simply shows no writable packages.

Repro (17.4.0, objectstack dev)

  1. POST /api/v1/packages with a writable-base package → 201.
  2. PUT /api/v1/meta/object/<obj>?mode=draft&package=<ns> → 200.
  3. POST /api/v1/packages/<ns>/publish-drafts → 200. Confirm the object serves data.
  4. Restart objectstack dev, then run the three probes above.

Expected — one of

  1. Persist API-created packages (symmetric with whatever path Studio's own "new writable package" uses), or
  2. Refuse to publish into a package that cannot be persisted (fail at step 3 rather than after a restart), or
  3. at minimum surface the in-memory-only status in Studio so the package is visibly ephemeral rather than silently absent after restart.

Why it matters

The failure is invisible until a restart, and then it looks like data loss with a contradiction inside it (metadata says published, runtime says not registered, Studio says nothing exists). Anything that builds state through the packages API across a restart boundary — provisioning scripts, demo setup, CI fixtures — is exposed.

Relationship to existing issues

Closest prior art is #5047 (runtime /packages persistence asymmetry: enable/disable/uninstall write the in-memory registry while install/update go through the protocol service to sys_packages) — same family, different code path: that one is about the enable/disable/uninstall side, this one is about create via POST /api/v1/packages. Also adjacent: #7557 / #7705 (uninstall leaving orphaned sys_metadata rows). All three are closed; the behaviour above was observed first-hand on 17.4.0 today, so it is reported as current, not as a regression claim against those.

Provenance

Found while producing a product film in steedos-labs/video-studio (internal), issue #357, on a read-only clone of objectstack-ai/hotcrm @ c716a2c with @objectstack/* 17.4.0 (same version as platform trunk at the time). Reported by the executing session; filed here by the video lane's PM per our cross-repo finding-transfer flow.

This is a finding, not a claim on anyone's time — filed unassigned.


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions