@kontextmind/kxm 0.7.53 → 0.7.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,7 +11,7 @@
11
11
  "name": "kxm",
12
12
  "source": "./plugins/kxm",
13
13
  "description": "Durable workflows, peer agents, and kxm tui",
14
- "version": "0.7.53",
14
+ "version": "0.7.55",
15
15
  "category": "development",
16
16
  "tags": ["kxm", "multi-agent", "workflows", "mcp"]
17
17
  }
package/CHANGELOG.md CHANGED
@@ -35,6 +35,47 @@ All notable user-facing changes are documented here. The project follows [Semant
35
35
 
36
36
  ### Changed
37
37
 
38
+ - **A Pi producer reply can no longer mint its own success.** `determineOutcome` scanned the
39
+ reply for any declared outcome *word* and, failing that, returned `passed`. So
40
+ `"the gate did not pass, so I would not call this passed"` settled the step as passed — the
41
+ word was all it took — and an empty or prose-only reply was passed by default. Only a declared
42
+ result counts now: a reply that is one JSON object, or prose carrying an explicit
43
+ `{"outcome": "…"}` block, and only when the step declares that outcome. Anything else is
44
+ `failed`; an undeclared value still lands in `outcome_unknown` and terminates as `failed`, so a
45
+ step without a `failed` transition cannot pass on a bad reply either. This matches the rule the
46
+ one-shot producer already enforced, and `docs/contracts/lifecycles.md` now states it where
47
+ `result_recorded` is defined. Three usage-capture fixtures that had been replying in prose now
48
+ declare their result, which is what they were always supposed to do; the new test in
49
+ `test/core/pi-producer.test.ts` covers prose, empty, out-of-vocabulary, and both accepted
50
+ structured shapes. Review of that first cut found two more ways to mint success, both now
51
+ closed: a result block was matched **anywhere** in the reply, so
52
+ `Example: {"outcome": "passed"}. Actual result: {"outcome": "failed"}` returned `passed`;
53
+ a declaration is now a standalone JSON object — the whole reply, or one object on its own
54
+ line, with the **last** such object winning so an illustration cannot outrank the answer, and
55
+ the whole reply settling `failed` when anything after that line still looks like an outcome
56
+ key, because at that point the producer cannot tell which declaration was meant.
57
+ And cancellation fell through to `allowedOutcomes[0]` when a step declared neither
58
+ `cancelled` nor `failed`, so aborting a `passed`-only step reported `passed`; a cancel now
59
+ reports `cancelled` unconditionally and the engine terminates it `failed` when the step
60
+ does not declare that outcome.
61
+
62
+ - **`kxm migrate` is gone, and so is the state that only it could unlock.** Deleting the
63
+ migration lanes left a converter with nothing to convert into: `plugins/kxm/src/migrate.ts`
64
+ (1,848 lines), its 1,598-line suite, the `migrate plan|apply|verify` commands, the
65
+ `kxm.migration-plan.v1` / `-decision.v1` / `-receipt.v1` schemas and their registry
66
+ validators, the receipt reader / self-hash / byte-record helpers, and the
67
+ `.kxm/migration-receipt.yaml` path are all removed. A tree that still holds legacy
68
+ `.kxm/config` JSON now fails closed at load with `legacy_state_unsupported`, one issue per
69
+ legacy file, and no receipt, plan, or option unlocks it — previously a verified receipt made
70
+ a mixed tree loadable, which is exactly the dual-read surface this decision retires.
71
+ `kxm init` classifies such a tree as `mode: "legacy"` (was `"migrate"`), reports
72
+ `legacyInputs`, and writes nothing. `docs/contracts/migration.md` is rewritten as a
73
+ supported/refused matrix instead of a conversion spec, and the packed-install suite now
74
+ builds its trust and run-lifecycle fixture by initialising a project directly, so that
75
+ coverage survived rather than being deleted with the command. A new test asserts
76
+ `kxm migrate` is rejected as an unknown command: a retired verb must fail loudly, not
77
+ resolve to nothing.
78
+
38
79
  - **No schema migration lanes, no legacy stamp tolerance (single-operator tool).** Stepwise
39
80
  schema migration lanes are removed from the hub store and the per-project event store, and
40
81
  the external-effects store no longer runs an in-place `ALTER TABLE ... ADD COLUMN` whose
@@ -42,7 +83,7 @@ All notable user-facing changes are documented here. The project follows [Semant
42
83
  ever fire on an older store; the store has no production caller yet, so this closes the
43
84
  lane rather than fixing a live upgrade).
44
85
  A database stamped behind this build now fails closed with `runtime_schema_outdated` and
45
- a message that says to delete the state file or re-run `kxm init` — and the refusal never
86
+ a message naming the process that recreates the store (`kxm hub start` for hub state, the Runtime for registry/event stores; `kxm init` is project-only) — and the refusal never
46
87
  advances `user_version`, so the store stays identifiably old (WAL sidecars may still be
47
88
  checkpointed by opening the file, so the whole state set remains the backup unit — see
48
89
  [`docs/operations.md`](docs/operations.md)). Relabelling a store it refused to open would
@@ -10,7 +10,7 @@ authority, admit new writers, or replace trusted `.kxm/roster.yaml` policy.
10
10
  | Feature Area | Skill | Commands Covered | Purpose |
11
11
  |---|---|---|---|
12
12
  | Core Routing | `kxm` | — | Select the right suite skill; state universal safety rules and portable CLI convention |
13
- | Project Setup | `kxm-project-setup` | `init`, `migrate`, `trust`, `config`, `completion` | Initialize, migrate, review permission changes, configure, and install shell completion |
13
+ | Project Setup | `kxm-project-setup` | `init`, `trust`, `config`, `completion` | Initialize, review permission changes, configure, and install shell completion |
14
14
  | Harness & Auth | `kxm-harness-auth` | `harness`, `auth`, `update`, `runtime`, `agent` | Inspect authenticated harness capability and operate supported runtimes/workers |
15
15
  | Hub Operations | `kxm-hub-ops` | `hub`, `backup`, `restore` | Run and protect the local hub and its durable SQLite state |
16
16
  | Session Management | `kxm-session` | `session`, `dash`, `studio` | Resume/inspect operator work and use UI capabilities each harness supports |
@@ -273,9 +273,6 @@ The current hub command groups are `agent`, `session`, `workflow`, `gate`, `hub`
273
273
  | Command | Purpose |
274
274
  |---|---|
275
275
  | `kxm init` | Atomically create a provenance-tracked minimal KXM project, validate it without rewriting, resume a pinned interrupted create/repair, apply conflict-free non-authority template updates, or join an existing clone with repeatable `--repository <id=absolute-path>` member bindings stored outside Git. `--dry-run` performs no writes. Provenance-free/ambiguous repair and permission-expanding changes remain planning-only. These configuration slices do **not** activate a KXM Runtime. `kxm init` is project-only; bind a running hub with `kxm hub bind <url>` |
276
- | `kxm migrate plan` | Convert legacy `.kxm/config` JSON (agents, gates, workflow definitions) into a deterministic, secret-free `kxm.migration-plan.v1` report: source/target hashes, decision-requiring ambiguities (terminal status, transition budgets, evidence-policy strengthening, secret drops, narrowed ceilings, foreign producers), hashed unmapped fields, and explicit identity renames. Performs no writes, locks, or staging |
277
- | `kxm migrate apply [--decisions <file>]` | Install a reviewed migration: re-checks the decision binding against current sources, validates the complete target bundle, refuses to overwrite existing paths, installs durably, and writes a self-hashed `kxm.migration-receipt.v1` that keeps legacy inputs read-only. Re-applying is an idempotent no-op. `--dry-run` performs no writes |
278
- | `kxm migrate verify` | Re-check the migration receipt against current legacy sources and the target bundle (self-hash, source hashes, configuration revision, resource bytes). Performs no writes |
279
276
  | `kxm trust diff [--base <rev>]` | Print the structured `kxm.permission-diff.v1` report between a base Git revision (default `HEAD`, materialized into a temporary shadow with a sanitized environment) and the working tree: every authority-bearing field change classified as expansion, narrowing, or neutral with per-field hashes. Performs no project writes |
280
277
  | `kxm trust check [--base <rev>]` | Exit non-zero when any expansion exists, so an authority-bearing change cannot merge without a reviewed Git change. Formatting/description-only changes never require review |
281
278
  | `kxm run <workflow> [prompt]` | Auto-start the KXM Runtime supervisor if needed, then create an immutable run offline: pins `homeRuntimeId` plus config/executor/tool policy revisions and stores only the prompt hash. `--dry-run` prints the plan without creating anything |
@@ -105,6 +105,22 @@ created → accepted → dispatched → executing → result_recorded → termin
105
105
  | `blocked_uncertain` | A dependent effect cannot be reconciled safely |
106
106
  | `terminal` | The logical assignment outcome is final and immutable: passed, failed, or cancelled |
107
107
 
108
+ A producer reply becomes a terminal outcome **only** through a declared result: the reply is
109
+ one JSON object, or it carries a `{"outcome": "…"}` object **on a line of its own**. With more
110
+ than one such line the last one is the answer; if anything after it still looks like an outcome
111
+ key — an inline `Actual result: {"outcome": "failed"}`, a pretty-printed object, a second
112
+ mention — the reply is **ambiguous and settles `failed`**, because guessing which declaration
113
+ was meant is the behaviour this rule removes. Ordinary trailing prose (a sign-off, a token
114
+ count) does not disturb a declared result.
115
+
116
+ Naming an outcome *word* anywhere in a reply is not a result — `"the gate did not pass, so I
117
+ would not call this passed"` must not advance a step — and an empty or unstructured reply is
118
+ never treated as success. A declared outcome outside the step's declared set is not accepted
119
+ either:
120
+ the assignment is recorded `outcome_unknown` and terminates as `failed`, which is also what
121
+ happens when a step declares no `failed` transition. Producers do not guess on the model's
122
+ behalf, and no fallback path mints `passed`.
123
+
108
124
  `assignmentId` remains stable. A retry moves the nonterminal assignment through
109
125
  `retry_pending` to `accepted`, creates a new `attemptId`, and never rewrites or
110
126
  exits the previous attempt's terminal state. The effective
@@ -1,258 +1,50 @@
1
- # Migration and compatibility matrix
2
-
3
- KXM is introduced beside the current v0.5 transport/workflow surfaces.
4
- Presence of KXM documents does not activate new behavior.
5
-
6
- ## Surface matrix
7
-
8
- | Current surface | KXM target | Migration rule |
9
- |---|---|---|
10
- | `.kxm/config/agents.json` aggregate roster | `.kxm/agents/<id>.yaml` individual definitions | Split records, infer ID from filename, preserve unrecognized fields in a migration report rather than silently dropping them |
11
- | `gates.json` descriptive records | Workflow step/gate references plus registered deterministic adapters | Map only implemented gates; report names with no runner |
12
- | `KXM_WEBHOOK_WORKFLOWS` inline JSON | `.kxm/workflows/<id>.yaml` | Materialize secret-free behavior; convert secret fields to references |
13
- | `KXM_WEBHOOK_WORKFLOWS_FILE` JSON array | Individual workflow YAML files | Split definitions and validate typed transitions |
14
- | `.kxm/config/workflows/*.json` including `/fix` | `.kxm/workflows/<id>.yaml` | Preserve typed transitions, immutable reproduction oracle, approved-plan hash, plan-hash requirements, producer policies, and attempt/transition budgets |
15
- | Hub-selected project from environment | Git project identity plus Runtime-local binding | Detect and ask on ambiguity; do not derive durable identity from directory basename |
16
- | Long-lived manually started Pi workers | Runtime-managed run-scoped sessions | Existing worker mode remains available during compatibility release |
17
- | Shared/off workflow Pi history | `{run, agent, instance, scopeEpoch}` sessions | Never import shared conversation history into a narrower run scope |
18
- | Hub-owned workflow state | Home Runtime event log with hub projection | Import completed history as legacy records; active-run cutover requires quiescence |
19
- | SQLite schema v3 `kxm.db` | Runtime registry, per-project event stores, hub registry/project stores | **No in-place schema migration.** A store stamped behind the current build fails closed with `runtime_schema_outdated` and the refusal never advances `user_version` (opening the file may still checkpoint WAL sidecars, so the whole state set is the backup unit); re-init instead. Stepwise lanes were removed 2026-09-20 under the single-operator decision from the hub store, the per-project event store, and the external-effects `ALTER TABLE` add-column; the Runtime registry never carried a stepwise lane (see [implementation-plan.md](../../plans/implementation-plan.md) → Decided) |
20
- | Full peer message bodies in hub DB | Summary-first sync events | Existing bodies remain protected legacy data and are not re-emitted automatically |
21
- | Project tokens/manual environment auth | Runtime enrollment and scoped credentials | Preserve current mode until enrollment is confirmed; never copy tokens into Git |
22
- | `.kxm/config/env.example` | Built-in defaults plus optional scoped env YAML | Import only explicit portable differences; secrets become references |
23
- | Retired product-prefixed init (empty directories) | Unified `kxm init` create/join/migrate/repair | Removed; `kxm init` is the only entry and the old init command fails closed |
24
- | `kxm session start` manifest only | `kxm run` executable run | Do not reinterpret old session manifests as completed or active runs |
25
- | Existing context items and journal | Pinned memory revisions and candidates | Preserve provenance/authority floors; no automatic executable promotion |
26
-
27
- ## Compatibility releases and activation
28
-
29
- > **Scope note (2026-09-20).** This matrix documents the Mesh/v0.5 → KXM cutover. KXM has
30
- > one operator and no external installs, so **schema migration and old-state tolerance are
31
- > out of scope** and the lanes that existed are gone: stores refuse an older stamp rather
32
- > than upgrading, the external-effects store no longer adds a column in place, and the
33
- > coordinator fingerprint no longer recomputes to forgive pre-canonicalisation rows. What
34
- > remains here describes the **project/content** cutover, which the follow-up cut removes
35
- > along with `kxm migrate`. Nothing here promises that the runtime will read an old
36
- > database.
37
-
38
- Local Runtime support may ship publicly before hub KXM, but it remains beside
39
- existing hub contracts and stores. Old command names are not preserved. A project
40
- activates `kxm.*.v1` only by an explicit successful `kxm init`/migration receipt;
41
- file presence alone never activates it. Legacy hub runs continue on the legacy
42
- engine.
43
-
44
- > **Superseded (2026-09-20).** The single-operator decision removes legacy readers
45
- > **without** a compatibility release, so this transition-release list is no longer a plan of
46
- > record. It stays here to name what was given up: no dual-read window, no `mesh_*` shim, and
47
- > no period where legacy JSON stays loadable while KXM writes YAML. Anything still holding
48
- > legacy state is refused rather than served from both shapes.
49
-
50
- When Phase 8 activates hub KXM, at least one hub transition release provides:
51
-
52
- - current `mesh_*` peer tools;
53
- - current hub APIs behind a compatibility adapter;
54
- - legacy JSON configuration read support while KXM writes only YAML;
55
- - current completed workflow history read/export support;
56
- - Runtime-managed KXM runs in new event stores with new identities;
57
- - CLI labels for legacy versus KXM state;
58
- - no implicit movement of active runs between engines.
59
-
60
- Before activation, a repository MUST NOT use legacy and KXM definitions with
61
- the same normalized identity. Validation reports the conflict and requires an
62
- explicit migration choice. After a migration receipt activates the KXM copy,
63
- the matching legacy definition is read-only compatibility input and cannot be
64
- selected for a new KXM run.
65
-
66
- ## Migration commands
67
-
68
- ```text
69
- kxm migrate plan
70
- kxm migrate apply [--decisions <file>] [--project-id <id>] [--name <name>]
71
- kxm migrate verify
72
- ```
73
-
74
- `kxm init` invokes the planning flow when it detects legacy state.
75
-
76
- > **Superseded (2026-09-20).** The single-operator decision removed every schema
77
- > migration lane, so "database/WAL migration … remain later-phase work" below is
78
- > no longer the plan: there will be none. The `kxm migrate` commands described on
79
- > this page are deleted in the follow-up cut, and a tree still holding legacy JSON
80
- > fails closed at load instead of being converted.
81
-
82
- **Implementation status (Phase 1 slice):** the commands above are implemented
83
- for **configuration migration only** — legacy `agents.json`, `gates.json`, and
84
- workflow-definition JSON under `.kxm/config/`. Database/WAL migration,
85
- active-run cutover, session migration, and rollback orchestration remain
86
- later-phase work and are not performed by these commands.
87
-
88
- ### Plan
89
-
90
- Produces a secret-free `kxm.migration-plan.v1` report containing:
91
-
92
- - detected source files with sha256 and byte counts plus a combined
93
- `sourceDigest`;
94
- - target resource paths with their rendered content hashes;
95
- - deterministic ambiguities, each with a stable decision key and the allowed
96
- values: terminal status for legacy `$terminal` edges, per-edge budgets for
97
- unbounded back-edges, missing global transition budgets, evidence-policy
98
- strengthening (`replied` → `passed`), foreign producer identities, secret
99
- field drops, narrowed permission ceilings, and identity normalization;
100
- - unrecognized or unmappable fields preserved as hashed `unmapped` entries
101
- (sensitive values are hashed, never copied);
102
- - old-to-new identity renames;
103
- - the resulting permission changes tied to their decision keys.
104
-
105
- It changes nothing: no writes, no locks, no staging, no local state.
106
-
107
- ### Decisions
108
-
109
- `kxm migrate apply` requires every ambiguity to be resolved. Decisions are
110
- supplied either as a reviewed `kxm.migration-decision.v1` YAML file
111
- (`--decisions <file>`) binding the exact `projectId`, `projectName`, and
112
- `sourceDigest` of the plan, or programmatically. Unknown decision keys and
113
- values outside the plan's allowed set fail closed before any write.
114
-
115
- ### Apply
116
-
117
- 1. Acquire the project mutation lock.
118
- 2. Recompute the plan and re-check the decision binding (project, source
119
- digest, key set, allowed values).
120
- 3. Validate every converted resource against its exact schema and the whole
121
- bundle against semantic rules.
122
- 4. Refuse to overwrite any existing target path.
123
- 5. Install resources with durable writes (fsync + rename).
124
- 6. Load and validate the complete installed bundle.
125
- 7. Write a hash-linked `kxm.migration-receipt.v1` binding source hashes,
126
- decision digest, target configuration revision, and installed resource
127
- hashes; the receipt is self-hashed.
128
- 8. Re-load the mixed tree: legacy inputs remain intact but receipt-pinned
129
- read-only; `loadKxmProject` accepts coexistence only through the
130
- verified receipt.
131
-
132
- Re-applying with the receipt present is an idempotent no-op
133
- (`already-migrated`). Editing a legacy source after the receipt makes both
134
- `loadKxmProject` and `kxm migrate verify` fail closed.
135
-
136
- ### Verify
137
-
138
- `kxm migrate verify` reopens the target, re-checks the receipt self-hash,
139
- re-hashes legacy sources, and compares the target configuration revision and
140
- installed resource bytes against the receipt. It performs no writes.
141
-
142
- ## Database migration
143
-
144
- > **Superseded in part (2026-09-20).** What the code guarantees today is narrower than the
145
- > checklist below and belongs to two different moments:
146
- >
147
- > - **Opening a store** verifies `user_version`, refuses a newer-than-known version, and
148
- > enables WAL. That is implemented.
149
- > - **Backing a store up** is where checkpointing, `-wal` handling, integrity verification,
150
- > and hash recording happen — see the whole-state-set recipe in
151
- > [`docs/operations.md`](../operations.md). Those are **not** properties of an ordinary open.
152
- >
153
- > The legacy-record import paragraphs describe a cutover that will not happen: this build
154
- > migrates no database, and an older stamp is refused outright.
155
-
156
- Before any database operation:
157
-
158
- - verify SQLite `user_version`;
159
- - refuse a newer unknown version;
160
- - checkpoint WAL or copy using the SQLite backup API;
161
- - include `-wal` state correctly rather than copying only the main file;
162
- - verify backup integrity;
163
- - record source and target hashes.
164
-
165
- Current agents, messages, workflow runs, journal entries, and context items are
166
- imported as typed **legacy records**. They are not fabricated into fine-grained
167
- KXM run events whose original ordering was never observed.
168
-
169
- Completed legacy runs remain queryable. A legacy active run must either finish
170
- on the old engine or be explicitly cancelled/exported; it is not resumed as a
171
- KXM run.
172
-
173
- ## Configuration migration
174
-
175
- The implemented converter:
176
-
177
- - reads legacy JSON with byte/depth/node bounds and token-level duplicate-key
178
- rejection; linked files and linked `workflows/` directories are never
179
- traversed for authoritative bytes;
180
- - normalizes case-insensitive identities, records explicit old-to-new renames,
181
- and rejects case-fold collisions and destination-invalid names;
182
- - splits `agents.json` into `.kxm/agents/<id>.yaml` resources and emits one
183
- `.kxm/models/<id>-primary.yaml` profile per agent whose legacy record pinned
184
- a provider/model pair with a thinking level;
185
- - maps roster-only concepts (`ownership`, `host`, top-level `project`) into
186
- hashed `unmapped` report entries rather than dropping them silently;
187
- - maps workflow stages to agent steps, preserves `reproOracle`, `planHash`,
188
- `requirePlanHash`, typed transitions, immutable oracles, and global
189
- transition budgets, and widens evidence-carrying steps into an explicit
190
- assignment pool containing their producers;
191
- - converts legacy peer-reply evidence policies (`acceptedStatuses:
192
- ["replied"]`) into KXM producer policies requiring `passed` only through
193
- an explicit operator decision;
194
- - requires decisions for: every legacy `$terminal` edge's terminal status
195
- (legacy completed the run even on failure outcomes), every unbounded
196
- back-edge's per-edge budget, missing global budgets, foreign producer
197
- identities, secret-field drops, unimplemented gates, and each narrowed
198
- permission ceiling;
199
- - never copies secret values or environment indirections; webhook secret
200
- fields are hashed into the report and dropped by explicit decision;
201
- - records template provenance only for files whose exact generated baseline is
202
- known; migrated files carry no template provenance and are never
203
- retroactively adopted;
204
- - validates the entire target project (exact schemas plus semantic rules)
205
- before installation and shows the Git diff through normal review.
206
-
207
- Unknown data is preserved in the migration report, not placed into a generic
208
- runtime extension map.
209
-
210
- Legacy typed workflows have a global transition budget but may lack KXM
211
- per-back-edge caps. The migrator MUST NOT invent those caps silently. `migrate
212
- plan` lists every affected edge and a proposed bounded value; `migrate apply`
213
- requires the values in an operator-approved migration decision. The committed
214
- KXM `/fix` fixture is one reviewed resolution, not a generic automatic rule.
215
-
216
- Stage IDs, outcome keys, evidence keys, oracle references, plan-hash references,
217
- and eligible producer identities are preserved by default. Any unavoidable
218
- normalization appears as an explicit old-to-new mapping and rewrites all bound
219
- references atomically.
220
-
221
- ## Session migration
222
-
223
- Old shared Pi histories may contain content from broader scopes. They remain
224
- archived under the old worker binding and are never selected for a KXM run.
225
- The first KXM physical session starts clean. Durable facts must come from Git,
226
- workflow evidence, artifacts, or promoted context rather than conversation
227
- history.
228
-
229
- ## Rollback
230
-
231
- Rollback is supported until the operator accepts the migration receipt and
232
- starts a permission-expanding KXM-only run.
233
-
234
- Rollback:
235
-
236
- 1. stop KXM writers;
237
- 2. preserve KXM stores as diagnostic artifacts;
238
- 3. restore the recorded legacy configuration selection and database path;
239
- 4. restart only compatible legacy processes;
240
- 5. verify legacy health and record rollback evidence.
241
-
242
- Events created only by KXM are not reverse-translated into fabricated legacy
243
- workflow history.
244
-
245
- ## Removal gate
246
-
247
- > **Superseded (2026-09-20).** The operator decided removal happens **without** a
248
- > compatibility release, so the list below no longer gates removal — it is kept only
249
- > to record why the gate existed. Legacy readers are being deleted now, and old names
250
- > fail closed by brake rather than alias.
251
-
252
- Legacy readers and command aliases are removed only after:
253
-
254
- - at least one compatibility release;
255
- - migration telemetry shows no material unmapped cases;
256
- - package/install/Windows tests cover KXM;
257
- - operator documentation and rollback paths are proven;
258
- - removal is announced in the changelog.
1
+ # Migration and compatibility
2
+
3
+ **KXM carries no migration path.** The product ships for a single operator, and
4
+ the operator decision (recorded in
5
+ [`plans/implementation-plan.md`](../../plans/implementation-plan.md)) is that
6
+ older state is replaced, not converted. Old names are not accepted; old state
7
+ is refused loudly. This page documents what that means at each boundary so no
8
+ one re-adds a compatibility lane by inference.
9
+
10
+ ## What happens to older input
11
+
12
+ | Boundary | Behaviour |
13
+ |---|---|
14
+ | Project tree with legacy `.kxm/config` JSON | `loadKxmProject` fails closed with `legacy_state_unsupported`, one issue per legacy file. No receipt, plan, flag, or environment variable unlocks it. |
15
+ | `kxm init` on such a tree | Reports `mode: "legacy"`, lists `legacyInputs`, performs **no writes**. Recovery is a fresh project directory plus the YAML definitions worth keeping. |
16
+ | `kxm migrate` | Unknown command. It existed as `plan` / `apply` / `verify` for pre-KXM JSON and was deleted with this decision. |
17
+ | SQLite store stamped with an older `user_version` | Refused with `runtime_schema_outdated`; the refusal never advances `user_version`, so the store stays identifiably old. Delete the state file and let the process that owns it recreate the store (`kxm hub start` for hub state, the Runtime for registry/event stores). `kxm init` is **project-only** and rebuilds no database. Forward-only stamping is prohibited — it turns a clean failure into a later query against a column that does not exist. |
18
+ | Retired product and command names | Rejected by fail-closed brakes (lint + readiness tests), not aliased. |
19
+ | Shared/off-scope Pi history | Never imported into a narrower run scope. A new physical session starts clean; durable facts come from Git, workflow evidence, artifacts, or promoted context. |
20
+ | Historical run records | Never fabricated. Events whose real ordering was not observed stay absent rather than reconstructed into a finer-grained model. |
21
+
22
+ ## What is *not* relaxed by this
23
+
24
+ Deleting conversion code does not soften the guarantees around the state that
25
+ does exist:
26
+
27
+ - **Fresh installs must be complete.** Every table, index, and default that a
28
+ store needs is declared in its current schema definition, so an empty store is
29
+ valid without any upgrade step.
30
+ - **Backups stay whole.** The hub state set is copied as documented in
31
+ [`docs/operations.md`](../operations.md); a single `kxm.db` copy is not a
32
+ backup.
33
+ - **Out-of-range versions refuse without touching the file.** The stamp is read
34
+ before anything that can modify the store, so a database this build refuses —
35
+ older or newer — comes back byte-identical: neither its schema nor its
36
+ `user_version` changes, and it is not converted to WAL as a side effect of being
37
+ rejected. A store ahead of this build is refused without downgrade.
38
+ - **Schema changes are additive-and-replace, not in-place.** Land the new
39
+ definition, delete the local state, and let the process that owns each store
40
+ recreate it — `kxm hub start` for hub state, the Runtime for registry and
41
+ event stores. `kxm init` is project-only and rebuilds no database.
42
+ Nothing in the runtime may rewrite an existing store's shape.
43
+
44
+ ## If this ever changes
45
+
46
+ Re-introducing migration needs a written decision first, because the cost is
47
+ not the converter — it is the permanent dual-read surface (legacy names staying
48
+ loadable, receipts that unlock state, and a test matrix that must keep proving
49
+ both sides). Any such proposal has to name the state it protects and who owns
50
+ it; "someone might have an old directory" is not a reason on its own.
@@ -107,39 +107,21 @@ hard-link support fails safely. Create keeps its same-volume directory rename.
107
107
  A newer process must finish the pinned transaction before planning another
108
108
  template revision.
109
109
 
110
- #### Legacy configuration migration
111
-
112
- `kxm migrate plan|apply|verify` converts legacy `.kxm/config` JSON into
113
- validated KXM resources with an exact receipt:
114
-
115
- - Legacy files are read with byte/depth/node bounds and token-level
116
- duplicate-key rejection. Symbolic links and linked `workflows/` directories
117
- are never traversed for authoritative bytes.
118
- - The deterministic `kxm.migration-plan.v1` binds every source file by
119
- sha256/bytes plus a combined `sourceDigest`, lists target resources with
120
- rendered content hashes, and enumerates every ambiguity as a stable decision
121
- key with its allowed values: terminal status for each legacy `$terminal`
122
- edge (legacy semantics completed the run even on failure outcomes), per-edge
123
- budgets for unbounded back-edges, missing global transition budgets,
124
- evidence-policy strengthening from `replied` to `passed`, foreign producer
125
- identities, secret-field drops, unimplemented gates, and each narrowed
126
- permission ceiling. Unrecognized or unmappable fields are preserved as
127
- hashed `unmapped` entries; sensitive values are hashed, never copied.
128
- Identity normalization that changes a name is an explicit `renames` entry
129
- applied to all bound references; case-fold collisions fail closed.
130
- - Apply requires a reviewed `kxm.migration-decision.v1` (or programmatic
131
- resolutions) binding the exact plan: project ID, project name, and source
132
- digest. Unknown keys and values outside the allowed set fail closed before
133
- any write. The complete target bundle must pass exact-schema and semantic
134
- validation before installation; existing target paths are never overwritten.
135
- - Installation uses durable writes under the project mutation lock and finishes
136
- with a self-hashed `kxm.migration-receipt.v1` binding source hashes, decision
137
- digest, target configuration revision, and installed resource hashes. The
138
- receipt keeps the legacy inputs read-only: `loadKxmProject` accepts mixed
139
- trees only through a verified receipt, and any later legacy-source edit makes
140
- loading and `migrate verify` fail closed. Re-apply is an idempotent no-op.
141
- - `plan`, `verify`, and every `--dry-run` path perform no writes, locks,
142
- staging, backups, or Runtime-local state creation.
110
+ #### Legacy configuration is refused, not migrated
111
+
112
+ This build carries **no** legacy conversion path. A tree that still holds
113
+ `.kxm/config` JSON fails closed:
114
+
115
+ - `loadKxmProject` rejects it with `legacy_state_unsupported` per legacy file, and
116
+ no receipt, plan, or option unlocks it any more.
117
+ - `kxm init` classifies the tree as `mode: "legacy"`, reports the discovered
118
+ `legacyInputs`, and performs **no writes** — it never converts on the side.
119
+ - `kxm migrate` is not a command; invoking it is an unknown-command error.
120
+
121
+ The operator decision behind this is recorded in
122
+ [`plans/implementation-plan.md`](../../plans/implementation-plan.md): single
123
+ operator, no backwards compatibility. Recover by initialising a fresh project
124
+ directory and copying the YAML definitions worth keeping.
143
125
 
144
126
  `--dry-run` may parse and classify a transaction but MUST NOT create the writer
145
127
  mutex, state directories, staging, backups, temporary files, or cleanup. Live
@@ -13,6 +13,7 @@ npm run verify
13
13
 
14
14
  | Feature | Automated evidence |
15
15
  |---|---|
16
+ | Structured-result settlement only: outcome words in prose, empty replies, and outcomes outside the step's declared set all fail closed; a declared JSON object and a JSON result block inside prose both settle, and the engine records `outcome_unknown` and terminates `failed` | `test/core/pi-producer.test.ts`, `test/core/engine.test.ts` |
16
17
  | Health, readiness, metrics, request IDs, security headers | `test/core/hub-api.test.ts` |
17
18
  | Shared and per-project authentication, project isolation | `test/core/hub-api.test.ts` |
18
19
  | Registration, discovery, presence, stale detection, identity resumption | `test/core/hub-api.test.ts`, `test/core/hub.test.ts` |
@@ -56,7 +57,7 @@ npm run verify
56
57
  | Package and marketplace version consistency | `scripts/check-versions.mjs` |
57
58
  | Planned KXM schemas, restricted YAML fixtures, cross-resource semantics, and sync-safe rejection | `test/core/contracts.test.ts` |
58
59
  | Production KXM restricted loader, deterministic bundle hashing, Git discovery, fail-closed semantics, init classification, provenance-tracked atomic creation, exact three-way repair, authority-change blocking, pinned crash resumption, shadow validation, explicit join, Runtime-local bindings, CLI isolation, and idempotence | `test/core/project-config.test.ts`, `test/core/cli.test.ts`, `test/core/package-install.test.ts` |
59
- | Bounded legacy JSON migration: exact duplicate-key rejection, deterministic plans, decision binding (project/source/values), schema+semantic target validation, durable install, self-hashed receipts, tamper/drift detection, link refusal, CLI and packed-consumer round trips | `test/core/migrate.test.ts`, `test/core/cli.test.ts`, `test/core/contracts.test.ts`, `test/core/package-install.test.ts` |
60
+ | Legacy state is refused, never converted: a tree with `.kxm/config` JSON fails project load with `legacy_state_unsupported`, `kxm init` classifies it `mode: "legacy"` without writing, `kxm migrate` is an unknown command, and an older stamped store is refused without advancing `user_version` | `test/core/project-config.test.ts`, `test/core/cli.test.ts`, `test/core/e6-backup-restore-migrations.test.ts` |
60
61
  | Permission-diff trust workflow: structured authority projections, conservative lattice classification (access, network, budgets, quorums, snapshots, secrets, transitions, shapes), prose neutrality, Git base shadowing, CLI diff/check gating, and packed-consumer round trips | `test/core/permission.test.ts`, `test/core/cli.test.ts`, `test/core/contracts.test.ts`, `test/core/package-install.test.ts` |
61
62
  | Event-sourced local Runtime: supervisor singleton with stable logical identity, immutable home bindings, append-only per-project event stores, idempotent acceptance/cancel, projection rebuild equivalence, token-authenticated local API, auto-start, SIGKILL crash recovery, offline CLI, packed consumer | `test/core/runtime.test.ts`, `test/core/cli.test.ts`, `test/core/package-install.test.ts` |
62
63
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextmind/kxm",
3
- "version": "0.7.53",
3
+ "version": "0.7.55",
4
4
  "description": "KXM local-first multi-agent orchestration and operator dashboard",
5
5
  "type": "module",
6
6
  "author": "KontextMind",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "kxm",
4
4
  "displayName": "KXM",
5
- "version": "0.7.53",
5
+ "version": "0.7.55",
6
6
  "description": "Headless multi-agent orchestration, durable workflows, and a live operator dashboard for Pi and Claude Code",
7
7
  "author": {
8
8
  "name": "KontextMind",