You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Package state store: let the host supply where module enable/disable state lives; today it is a file under OS_HOME, which a hosted container loses on replacement (cloud#3636 F2) #30962
Filing gate: ④ coordination, the platform half (F2) of objectstack-ai/cloud#3636. That card's ruling Q2 A is maintainer 「AAAA + 三条验收(推荐)」, record objectstack-ai/cloud#3636 comment 6686669315 (2026-11-06T14:03Z): "the framework's file-only package-state store is a missing host seam, so F2 lands in objectstack and cloud adds only the hosted store." Carrier rule: 「平台的问题应该在平台处理」.
Business reason. HotCRM on hosted cloud must let an admin switch modules off in settings and have that stick. Today a hosted module disable holds only until the container is replaced, and only on that container.
Reader who acts. The lane owning packages/runtime (triage sets lane and grade; cloud suggests p2, inherited). Cloud then implements the hosted store (cloud C3).
Dedupe (open and closed): package-state store host and disabled packages host-injectable → no card.
Measured (pin c50e0dfa, read by the cloud seat's dev reading, comment objectstack-ai/cloud#3636 6685025094)
The disable door writes OS_HOME/package-state/ENV.PROJECT.json (runtime/src/package-state-store.ts, called from domains/packages.ts). A failed write only console.warns.
Boot reads the same file back (runtime/src/app-plugin.ts).
The seed setter it feeds is already on the engine contract (spec/src/contracts/objectql-engine.ts, setInitialDisabledPackageIds).
Ask
Make the store host-injectable for the boot read and for the enable/disable doors. The default stays the file, byte-identical without an injection.
A store write failure is loud (ruling acceptance line 1): the door does not change in-memory state when the host store refuses the write, and it answers an error instead of warning.
Done when
A host-injected store sees every enable/disable write and seeds boot.
A refusing store makes the door fail visibly, with in-memory state unchanged.
The platform half (F2) of objectstack-ai/cloud#3636, under the maintainer's ruling 「AAAA + 三条验收(推荐)」. The package-state store becomes host-injectable. Without an injection it stays the file under OS_HOME, byte-identical. A failed store write is loud and leaves in-memory state unchanged.
Lane domain:server (packages/runtime), followed by repo:cloud. p2, inherited from cloud#3636. A runtime seam with no spec key. pm:queue.
Claim: PM loop round 1 · 2026-11-06T15:39Z
Session: session_01L9qibyvxbrLP4jm4PargoH
Account: os-tesla (the card's assignee)
Branch: claude/project-thread-lzvklr (the card thread's designated branch; dev session session_01L9qibvSvYrx9SiZMbSoehj)
Worktree: objectstack-issue-30962
Domain: domain:server
Seat: domain:server#2
File surface: packages/runtime/src/package-state-store.ts, the boot read in packages/runtime/src/app-plugin.ts, the enable/disable doors in packages/runtime/src/domains/packages.ts (⛔ not the dependent-scan region), the existing runtime option or service seam a host uses to supply the store, their tests, one changeset. ⛔ No packages/spec edit (stop on breach).
Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path mandate), effort: high
Clause-②: yes (widening)
Metadata-protocol: none
Responsibility: the file-only store is ours (packages/runtime, objectstack; cloud#3636 ruling 6686669315: 「平台的问题应该在平台处理」); no host seam covers it today; it reaches every hosted HotCRM admin who disables a module, which reverts when the container is replaced.
Thread-read: 6687790699
Premise: holds. On origin/mainacd190b2package-state-store.ts writes OS_HOME/package-state/… and a failed write warns only.
Serial constraints cleared: PR #30825 (domain:server#4, #30379) edits the disable door's dependent scan in domains/packages.ts; this card stays out of that region and merges origin/main after #30825 lands.
Order: /mnt/project-files/server-seat-2/r2026-11-06/dispatch-30962.md (frame FRAME.md beside it). Clause-②: yes (widening) for the new host seam: the seat's TIER_DEFAULT review of record.
ACCEPT on PR #31008 (head 8e94a195, 6691047045) · 2026-11-06T17:25Z · the seat readies it and arms auto-merge. #30756 merges origin/main after this lands.
Landing · 2026-11-06T18:26Z · PR #31008 MERGED 2026-11-06T18:08Z as d9f8f7fb (Fixes #30962): a host can supply the package-state store, so a disabled module stays disabled when the container is replaced. The card is done; the seat drops pm:dispatched.
Activity
objectstack-fleet commentedon Nov 6, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p2 ·
domain:server· 2026-11-06T14:55Z⛔ Not a claim.
OS_HOME, byte-identical. A failed store write is loud and leaves in-memory state unchanged.domain:server(packages/runtime), followed byrepo:cloud. p2, inherited from cloud#3636. A runtime seam with no spec key.pm:queue.Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
domain:server#2 · os-tesla · session_01L9qibyvxbrLP4jm4PargoH
Claim: PM loop round 1 · 2026-11-06T15:39Z
Session:
session_01L9qibyvxbrLP4jm4PargoHAccount:
os-tesla(the card's assignee)Branch:
claude/project-thread-lzvklr(the card thread's designated branch; dev sessionsession_01L9qibvSvYrx9SiZMbSoehj)Worktree:
objectstack-issue-30962Domain:
domain:serverSeat:
domain:server#2File surface:
packages/runtime/src/package-state-store.ts, the boot read inpackages/runtime/src/app-plugin.ts, the enable/disable doors inpackages/runtime/src/domains/packages.ts(⛔ not the dependent-scan region), the existing runtime option or service seam a host uses to supply the store, their tests, one changeset. ⛔ Nopackages/specedit (stop on breach).Container & model:
M,mode:thread,model: TIER_DEFAULT(dispatch-gates --tier: no path mandate),effort: highClause-②: yes (widening)
Metadata-protocol: none
Responsibility: the file-only store is ours (
packages/runtime, objectstack; cloud#3636 ruling 6686669315: 「平台的问题应该在平台处理」); no host seam covers it today; it reaches every hosted HotCRM admin who disables a module, which reverts when the container is replaced.Thread-read: 6687790699
Premise: holds. On
origin/mainacd190b2package-state-store.tswritesOS_HOME/package-state/…and a failed write warns only.Serial constraints cleared: PR #30825 (
domain:server#4, #30379) edits the disable door's dependent scan indomains/packages.ts; this card stays out of that region and mergesorigin/mainafter #30825 lands.Order:
/mnt/project-files/server-seat-2/r2026-11-06/dispatch-30962.md(frameFRAME.mdbeside it).Clause-②: yes (widening)for the new host seam: the seat's TIER_DEFAULT review of record.objectstack-fleet commentedon Nov 6, 2026
domain:server#2 · os-tesla · session_01L9qibvSvYrx9SiZMbSoehj
os-dev-report
{ "issue": 30962, "status": "done", "branch": "claude/project-thread-lzvklr", "pr": "https://github.com/objectstack-ai/objectstack/pull/31008", "session": "session_01L9qibvSvYrx9SiZMbSoehj", "premise_still_valid": true, "summary": "New packages/runtime/src/package-state-host-store.ts exports PackageStateStore, createPackageStateStorePlugin(store) / PackageStateStorePlugin, PACKAGE_STATE_STORE_SERVICE ('package-state-store') and PACKAGE_STATE_STORE_PLUGIN_NAME; a host adds the plugin to its kernel (the existing seam: createStandaloneStack returns a plugins list the host composes), and AppPlugin lists the plugin name in optionalDependencies so the store is registered before the boot seed reads it. The boot seed reads the host store when registered (a throwing read fails the boot), else the file exactly as before; AppPlugin.start() refuses a boot seeded from the file while a store is registered by then. Every package-door write goes through writePackageState (classified lookup): enable and disable now write the store first and answer 503 SERVICE_UNAVAILABLE with nothing changed when a host store refuses; install and delete stay best-effort and log a host refusal at error; without a host store the file bytes and the warn-only failure are unchanged. Merged origin/main after #30825 landed: its dependent scan runs first, the store write follows.", "tests": "head 8e94a195: pnpm --filter @objectstack/runtime typecheck exit 0 (check:test-typecheck OK); pnpm --filter @objectstack/runtime test: Test Files 551 passed (551), Tests 8827 passed | 19 skipped; new src/package-state-host-store.test.ts 11/11. Ablations (6 legs, node scripts/ablation-replace.mjs, test imports source so no dist leg, taken on 83af516e before the merge, each restored 'blob == HEAD and git diff HEAD is empty'): A1 drop the refusal answer at the disable door -> 'expected { status: 200 ... } to match object { status: 503 }', 1 failed; A2 registry switched before the store write -> 'expected {...} to match object { enabled: true, status: installed }' + unknown-id writes the store, 2 failed; A3 no-injection branch writes no file -> ENOENT on the state file + warn not called, 2 failed; A4 file failure made loud -> 'expected { status: 503 } to match object { status: 200 }', 1 failed; A5 start-time late-store refusal removed -> 'promise resolved instead of rejecting', 1 failed; A6 store plugin dropped from optionalDependencies -> 7 failed. First attempts of A1 (empty --replacement) and A3 (replacement text already present) were refused by the tool before running, then re-run with --delete.", "gates": "dispatch-gates --commands derived 63 families on 8e94a195, plus 8 extra (check:init-service-contract, check:startup-registry-verdict, check:error-code-casing, check:route-ledger-census, check:authz-resolver, check:changeset-fixed, check:filter-alias-parity, check-platform-checklist --changed-from origin/main); all 71 run with stdin from /dev/null, every exit 0 (record: node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0; node scripts/check-adr-0087-registration.mjs --self-test :: exit 0; node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0; node scripts/check-closing-keyword-parity.mjs :: exit 0; node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0; node scripts/check-comment-mask-adoption.mjs :: exit 0; node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0; node scripts/check-comment-mask-corpus.mjs :: exit 0; node scripts/check-dts-emitted.mjs --self-test :: exit 0; node scripts/check-empty-changeset.mjs --base origin/main :: exit 0; node scripts/check-empty-changeset.mjs --self-test :: exit 0; node scripts/check-issue-citations.mjs :: exit 0; node scripts/check-plugin-teardown-shape.mjs :: exit 0; node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0; node scripts/ci/assert-turbo-remote-cache.mjs --self-test :: exit 0; node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0; node scripts/ci/prune-turbo-cache.mjs --self-test :: exit 0; node scripts/ci/snapshot-next.mjs --self-test :: exit 0; node scripts/docs-audit/check-affected-docs.mjs :: exit 0; node scripts/docs-audit/check-drift-comment.mjs :: exit 0; node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0; node scripts/release-pending-publish.mjs --self-test :: exit 0; pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0; pnpm check:changeset-gate-self-tests :: exit 0; pnpm check:ci-filter-parity :: exit 0; pnpm check:closed-ceremony-text :: exit 0; pnpm check:cross-package-test-inputs :: exit 0; pnpm check:dispatcher-error-vocabulary :: exit 0; pnpm check:doc-authoring :: exit 0; pnpm check:driver-memory-census :: exit 0; pnpm check:dts-closure :: exit 0; pnpm check:dual-build-cjs-loads :: exit 0; pnpm check:durability-log-level :: exit 0; pnpm check:engine-double-contract :: exit 0; pnpm check:error-status-conformance :: exit 0; pnpm check:gitlink-declared :: exit 0; pnpm check:issue-citations :: exit 0; pnpm check:keyed-text-bounds :: exit 0; pnpm check:lean-entry-closure :: exit 0; pnpm check:logger-receiver-detach :: exit 0; pnpm check:nul-bytes :: exit 0; pnpm check:objectql-double-limit :: exit 0; pnpm check:org-identifier :: exit 0; pnpm check:page-declaration-shape :: exit 0; pnpm check:platform-object-tenancy-census :: exit 0; pnpm check:published-files :: exit 0; pnpm check:query-options-erasure :: exit 0; pnpm check:refd-timer-probe :: exit 0; pnpm check:registry-log-declared :: exit 0; pnpm check:rest-log-spy-declared :: exit 0; pnpm check:route-envelope :: exit 0; pnpm check:slot-lookup :: exit 0; pnpm check:sourcemap-no-sources-content :: exit 0; pnpm check:stack-collection-maps :: exit 0; pnpm check:swallow-census-controls :: exit 0; pnpm check:system-context-census :: exit 0; pnpm check:test-source-alias :: exit 0; pnpm check:tier-file-adoption :: exit 0; pnpm check:type-check-coverage :: exit 0; pnpm check:type-check-debt :: exit 0; pnpm check:undeclared-dep-imports :: exit 0; pnpm check:watch-hint-literal :: exit 0; pnpm check:where-matcher :: exit 0; pnpm check:init-service-contract :: exit 0; pnpm check:startup-registry-verdict :: exit 0; pnpm check:error-code-casing :: exit 0; pnpm check:route-ledger-census :: exit 0; pnpm check:authz-resolver :: exit 0; pnpm check:changeset-fixed :: exit 0; pnpm check:filter-alias-parity :: exit 0; node scripts/check-platform-checklist.mjs --changed-from origin/main :: exit 0). --ran: '63 derived famil(ies) accounted for — 63 run, 0 NOT-MEASURED'. Pre-merge run: check:test-source-alias exit 1 on the new test (lazy import('@objectstack/metadata') reached in a clocked window), fixed with a module-top side-effect import; check-plugin-teardown-shape --self-test and check:dual-build-cjs-loads exit 3 (prerequisites: pinned commit 621a4876 fetched, full turbo build of ./packages/**), both exit 0 after. eslint packages/runtime --no-inline-config exit 0. CI on PR #31008: in_progress at report time.", "line_budget": "6 files, +681 / -30 (711 changed lines), under the 3,000 human-merge threshold; no governed path; no packages/spec edit.", "files_changed": [ ".changeset/30962-host-package-state-store.md", "packages/runtime/src/app-plugin.ts", "packages/runtime/src/domains/packages.ts", "packages/runtime/src/index.ts", "packages/runtime/src/package-state-host-store.test.ts", "packages/runtime/src/package-state-host-store.ts" ], "deviations": "None against the order. Choices the card did not rule, named in Acceptance notes for the seat: (a) a host store whose boot read throws fails the boot; (b) install/delete stay best-effort on a host refusal, logged at error, since their change has already landed; (c) a start-time refusal of a store registered outside createPackageStateStorePlugin. The harness's assignee/reviewer step was skipped per the frame (no GitHub MCP writes). The designated branch was checked out in the shared checkout; I detached that checkout (clean tree) so the worktree could take the branch. The changeset is patch (Clause-② widening, Metadata-protocol none).", "dogfood_battery": "n/a — no '!' in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "3 — git push (claude/project-thread-lzvklr); relay pr_create (run 42257525533, PR #31008, read-back identical 11146 bytes); this os-dev-report comment via post-stamped", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: seat · noted, not filed: plugin-installation-store.ts (local os plugin disable|enable and the boot-time installed-plugin loader) still reads and writes the file directly, not through the host seam; local-first CLI state, a host-backed variant would be its own card" ] }Posted 2026-11-06T17:01Z.
objectstack-fleet commentedon Nov 6, 2026
domain:server#2 · os-tesla · session_01L9qibyvxbrLP4jm4PargoH
ACCEPT on PR #31008 (head
8e94a195, 6691047045) · 2026-11-06T17:25Z · the seat readies it and arms auto-merge. #30756 mergesorigin/mainafter this lands.objectstack-fleet commentedon Nov 6, 2026
domain:server#2 · os-tesla · session_01L9qibyvxbrLP4jm4PargoH
Landing · 2026-11-06T18:26Z · PR #31008 MERGED 2026-11-06T18:08Z as
d9f8f7fb(Fixes #30962): a host can supply the package-state store, so a disabled module stays disabled when the container is replaced. The card is done; the seat dropspm:dispatched.