@kontextmind/kxm 0.6.0
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.
- package/.claude-plugin/marketplace.json +19 -0
- package/.kxm/README.md +14 -0
- package/.kxm/assets/README.md +5 -0
- package/.kxm/assets/retrospectives/README.md +5 -0
- package/.kxm/config/README.md +5 -0
- package/.kxm/config/agents.json +43 -0
- package/.kxm/config/env.example +56 -0
- package/.kxm/config/update.example.yaml +9 -0
- package/.kxm/config/workflows/fix.json +160 -0
- package/.kxm/config/workflows/jira-development.json +116 -0
- package/.kxm/config/workflows/provenance-quorum.json +150 -0
- package/.kxm/config/workflows/v04-dogfood.json +72 -0
- package/CHANGELOG.md +465 -0
- package/LICENSE +21 -0
- package/README.md +306 -0
- package/SECURITY.md +72 -0
- package/docs/README.md +48 -0
- package/docs/agent-communication-envelopes-and-gates.md +553 -0
- package/docs/architecture.md +242 -0
- package/docs/assignment-runner.md +241 -0
- package/docs/configuration.md +361 -0
- package/docs/continuous-improvement.md +114 -0
- package/docs/getting-started.md +253 -0
- package/docs/kxm-handbook.md +1090 -0
- package/docs/operations.md +205 -0
- package/docs/provenance-gates.md +291 -0
- package/docs/skills.md +45 -0
- package/docs/templates/README.md +95 -0
- package/docs/templates/adr.md +88 -0
- package/docs/templates/architecture.md +120 -0
- package/docs/templates/bug-fix.md +109 -0
- package/docs/templates/feature.md +108 -0
- package/docs/templates/handoff.md +72 -0
- package/docs/templates/postmortem.md +77 -0
- package/docs/templates/research.md +100 -0
- package/docs/templates/review.md +85 -0
- package/docs/templates/runbook.md +73 -0
- package/docs/templates/test-plan.md +87 -0
- package/docs/templates/test-report.md +72 -0
- package/docs/test-matrix.md +121 -0
- package/docs/troubleshooting.md +249 -0
- package/docs/vnext/README.md +62 -0
- package/docs/vnext/architecture.md +185 -0
- package/docs/vnext/effects-and-recovery.md +172 -0
- package/docs/vnext/lifecycles.md +235 -0
- package/docs/vnext/migration.md +220 -0
- package/docs/vnext/routing.md +184 -0
- package/docs/vnext/synchronization.md +172 -0
- package/docs/vnext/terminology.md +240 -0
- package/docs/vnext/validation.md +335 -0
- package/docs/webhook-workflows.md +240 -0
- package/docs/workflow-guide.md +1150 -0
- package/examples/README.md +102 -0
- package/examples/provenance-workflow.json +40 -0
- package/examples/requester.ts +30 -0
- package/examples/reviewer-agent.ts +29 -0
- package/examples/roundtrip.ts +46 -0
- package/examples/vnext/.kxm/agents/coordinator.yaml +16 -0
- package/examples/vnext/.kxm/agents/critic-1.yaml +16 -0
- package/examples/vnext/.kxm/agents/critic-2.yaml +15 -0
- package/examples/vnext/.kxm/agents/critic-3.yaml +15 -0
- package/examples/vnext/.kxm/agents/implementer.yaml +15 -0
- package/examples/vnext/.kxm/agents/planner.yaml +13 -0
- package/examples/vnext/.kxm/agents/reproducer.yaml +15 -0
- package/examples/vnext/.kxm/agents/reviewer.yaml +15 -0
- package/examples/vnext/.kxm/gates.yaml +8 -0
- package/examples/vnext/.kxm/models/critic-claude.yaml +11 -0
- package/examples/vnext/.kxm/models/critic-gemini.yaml +11 -0
- package/examples/vnext/.kxm/models/critic-grok.yaml +12 -0
- package/examples/vnext/.kxm/models/implementation.yaml +14 -0
- package/examples/vnext/.kxm/models/primary.yaml +17 -0
- package/examples/vnext/.kxm/prices.yaml +111 -0
- package/examples/vnext/.kxm/project/env.yaml +7 -0
- package/examples/vnext/.kxm/project.yaml +32 -0
- package/examples/vnext/.kxm/repo/repo.yaml +8 -0
- package/examples/vnext/.kxm/workflows/default.yaml +92 -0
- package/examples/vnext/.kxm/workflows/fix.yaml +376 -0
- package/examples/vnext/.kxm/workflows/improve.yaml +57 -0
- package/examples/vnext/README.md +53 -0
- package/examples/vnext/records/assignment-result-recorded.json +63 -0
- package/examples/vnext/records/assignment-result.json +46 -0
- package/examples/vnext/records/context-candidate.json +42 -0
- package/examples/vnext/records/delivery-manifest.json +66 -0
- package/examples/vnext/records/effect-uncertainty-resolved-sync.json +67 -0
- package/examples/vnext/records/effect-uncertainty-resolved.json +62 -0
- package/examples/vnext/records/run-created.json +54 -0
- package/examples/vnext/records/sync-event.json +65 -0
- package/examples/vnext/repositories/api/.kxm/repo/env.yaml +7 -0
- package/examples/vnext/repositories/api/.kxm/repo/repo.yaml +8 -0
- package/examples/vnext/repositories/web/.kxm/repo/repo.yaml +8 -0
- package/examples/workflow-signal.ts +63 -0
- package/package.json +129 -0
- package/plugins/kxm/.claude-plugin/plugin.json +73 -0
- package/plugins/kxm/.mcp.json +19 -0
- package/plugins/kxm/README.md +93 -0
- package/plugins/kxm/dist/cli.js +42853 -0
- package/plugins/kxm/dist/client.js +416 -0
- package/plugins/kxm/dist/core.js +1823 -0
- package/plugins/kxm/dist/extension.js +3797 -0
- package/plugins/kxm/dist/mcp-server.js +17104 -0
- package/plugins/kxm/dist/runtime.js +23361 -0
- package/plugins/kxm/dist/server.js +13640 -0
- package/plugins/kxm/dist/vnext-runtime-supervisor.js +21109 -0
- package/plugins/kxm/package.json +12 -0
- package/plugins/kxm/skills/kxm/SKILL.md +97 -0
- package/plugins/kxm/skills/kxm/references/protocol.md +103 -0
- package/plugins/kxm/skills/kxm-session/SKILL.md +53 -0
- package/plugins/kxm/src/arbiter.ts +355 -0
- package/plugins/kxm/src/artifacts-exist.ts +62 -0
- package/plugins/kxm/src/autocomplete.ts +236 -0
- package/plugins/kxm/src/cli.ts +3707 -0
- package/plugins/kxm/src/client.ts +614 -0
- package/plugins/kxm/src/commands.ts +1063 -0
- package/plugins/kxm/src/config.ts +290 -0
- package/plugins/kxm/src/context/providers.ts +101 -0
- package/plugins/kxm/src/context-packet.ts +332 -0
- package/plugins/kxm/src/context.ts +499 -0
- package/plugins/kxm/src/core.ts +6 -0
- package/plugins/kxm/src/database.ts +563 -0
- package/plugins/kxm/src/diagnostics.ts +184 -0
- package/plugins/kxm/src/envelope.ts +118 -0
- package/plugins/kxm/src/extension.ts +895 -0
- package/plugins/kxm/src/external-effects.ts +299 -0
- package/plugins/kxm/src/github-watch.ts +255 -0
- package/plugins/kxm/src/hub-binding.ts +160 -0
- package/plugins/kxm/src/hub.ts +2502 -0
- package/plugins/kxm/src/improve.ts +383 -0
- package/plugins/kxm/src/inbox.ts +10 -0
- package/plugins/kxm/src/kxm-install-kind.ts +113 -0
- package/plugins/kxm/src/kxm-update-config.ts +39 -0
- package/plugins/kxm/src/kxm-update.ts +238 -0
- package/plugins/kxm/src/local-snapshot.ts +406 -0
- package/plugins/kxm/src/logger.ts +198 -0
- package/plugins/kxm/src/mcp-server.ts +143 -0
- package/plugins/kxm/src/memory.ts +385 -0
- package/plugins/kxm/src/nous-pi.ts +287 -0
- package/plugins/kxm/src/nous-provider.ts +729 -0
- package/plugins/kxm/src/price-calc.ts +87 -0
- package/plugins/kxm/src/prices.ts +121 -0
- package/plugins/kxm/src/protocol.ts +172 -0
- package/plugins/kxm/src/recovery.ts +211 -0
- package/plugins/kxm/src/redact.ts +26 -0
- package/plugins/kxm/src/retrospective.ts +400 -0
- package/plugins/kxm/src/routing.ts +830 -0
- package/plugins/kxm/src/runtime.ts +9 -0
- package/plugins/kxm/src/server.ts +117 -0
- package/plugins/kxm/src/session-work.ts +571 -0
- package/plugins/kxm/src/session.ts +184 -0
- package/plugins/kxm/src/skills.ts +535 -0
- package/plugins/kxm/src/state.ts +326 -0
- package/plugins/kxm/src/store.ts +637 -0
- package/plugins/kxm/src/studio-layout.ts +268 -0
- package/plugins/kxm/src/suggest.ts +162 -0
- package/plugins/kxm/src/task-manager.ts +244 -0
- package/plugins/kxm/src/telemetry.ts +116 -0
- package/plugins/kxm/src/tui.ts +1046 -0
- package/plugins/kxm/src/vnext-bindings.ts +403 -0
- package/plugins/kxm/src/vnext-config.ts +1646 -0
- package/plugins/kxm/src/vnext-engine-artifacts.ts +86 -0
- package/plugins/kxm/src/vnext-engine-command.ts +533 -0
- package/plugins/kxm/src/vnext-engine-compile.ts +722 -0
- package/plugins/kxm/src/vnext-engine-evidence.ts +273 -0
- package/plugins/kxm/src/vnext-engine-fold.ts +1400 -0
- package/plugins/kxm/src/vnext-engine-gate-records.ts +583 -0
- package/plugins/kxm/src/vnext-engine-plan.ts +717 -0
- package/plugins/kxm/src/vnext-engine.ts +2458 -0
- package/plugins/kxm/src/vnext-gate-hash.ts +10 -0
- package/plugins/kxm/src/vnext-harness.ts +1142 -0
- package/plugins/kxm/src/vnext-init.ts +430 -0
- package/plugins/kxm/src/vnext-migrate.ts +1848 -0
- package/plugins/kxm/src/vnext-oneshot-producer.ts +424 -0
- package/plugins/kxm/src/vnext-permission.ts +936 -0
- package/plugins/kxm/src/vnext-pi-producer.ts +628 -0
- package/plugins/kxm/src/vnext-repair.ts +1094 -0
- package/plugins/kxm/src/vnext-runtime-owner.ts +320 -0
- package/plugins/kxm/src/vnext-runtime-store.ts +1560 -0
- package/plugins/kxm/src/vnext-runtime-supervisor.ts +586 -0
- package/plugins/kxm/src/vnext-runtime.ts +663 -0
- package/plugins/kxm/src/vnext-template.ts +247 -0
- package/plugins/kxm/src/wiki.ts +313 -0
- package/plugins/kxm/src/workflow.ts +1548 -0
- package/schemas/vnext/README.md +46 -0
- package/schemas/vnext/agent.schema.json +40 -0
- package/schemas/vnext/assignment-result.schema.json +66 -0
- package/schemas/vnext/backup-manifest.schema.json +89 -0
- package/schemas/vnext/candidate.schema.json +109 -0
- package/schemas/vnext/common.schema.json +422 -0
- package/schemas/vnext/context-candidate.schema.json +76 -0
- package/schemas/vnext/context-packet.schema.json +192 -0
- package/schemas/vnext/delivery-manifest.schema.json +159 -0
- package/schemas/vnext/environment.schema.json +66 -0
- package/schemas/vnext/gate-registry.schema.json +109 -0
- package/schemas/vnext/handoff-manifest.schema.json +146 -0
- package/schemas/vnext/init-operation.schema.json +61 -0
- package/schemas/vnext/local-repository-bindings.schema.json +30 -0
- package/schemas/vnext/memory-record.schema.json +45 -0
- package/schemas/vnext/migration-decision.schema.json +26 -0
- package/schemas/vnext/migration-plan.schema.json +123 -0
- package/schemas/vnext/migration-receipt.schema.json +52 -0
- package/schemas/vnext/model.schema.json +42 -0
- package/schemas/vnext/permission-diff.schema.json +57 -0
- package/schemas/vnext/prices.schema.json +115 -0
- package/schemas/vnext/project.schema.json +85 -0
- package/schemas/vnext/repository.schema.json +24 -0
- package/schemas/vnext/run-event.schema.json +460 -0
- package/schemas/vnext/session-brief.schema.json +153 -0
- package/schemas/vnext/sync-event.schema.json +234 -0
- package/schemas/vnext/template-provenance.schema.json +38 -0
- package/schemas/vnext/workflow.schema.json +248 -0
- package/scripts/assignment-run.d.mts +354 -0
- package/scripts/assignment-run.mjs +4451 -0
- package/scripts/build-runtime.mjs +56 -0
- package/scripts/check-generated.mjs +77 -0
- package/scripts/check-versions.mjs +34 -0
- package/scripts/emit-codex-artifacts.d.mts +9 -0
- package/scripts/emit-codex-artifacts.mjs +91 -0
- package/scripts/harness-run.d.mts +83 -0
- package/scripts/harness-run.mjs +2095 -0
- package/scripts/kxm-hub.mjs +105 -0
- package/scripts/kxm-publish-npm.mjs +327 -0
- package/scripts/kxm-release-github.mjs +472 -0
- package/scripts/kxm-runtime-supervisor.mjs +7 -0
- package/scripts/kxm-worker.mjs +1127 -0
- package/scripts/kxm.mjs +27 -0
- package/scripts/roster-policy.d.mts +20 -0
- package/scripts/roster-policy.mjs +161 -0
- package/scripts/smoke-multi-pi.mjs +479 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Durable lifecycles
|
|
2
|
+
|
|
3
|
+
All transitions are append-only events. A projection may materialize the
|
|
4
|
+
current state, but it cannot create a transition absent from the home Runtime's
|
|
5
|
+
event sequence.
|
|
6
|
+
|
|
7
|
+
## Event ordering
|
|
8
|
+
|
|
9
|
+
Each run has a strictly increasing 1-based `sequence` assigned by its home
|
|
10
|
+
Runtime. Repeating an idempotent command returns the prior result and does not
|
|
11
|
+
append a duplicate semantic event. The hub deduplicates synchronized events by
|
|
12
|
+
`{projectId, runId, sequence}`.
|
|
13
|
+
|
|
14
|
+
UTC timestamps are audit/display data. Durations and timeouts use the Runtime's
|
|
15
|
+
monotonic clock and persisted duration samples.
|
|
16
|
+
|
|
17
|
+
## Run request
|
|
18
|
+
|
|
19
|
+
A hub run request is coordination state, not execution state.
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
queued → offered → accepted
|
|
23
|
+
│ │ └── creates one home-owned run
|
|
24
|
+
│ ├── declined
|
|
25
|
+
│ └── expired
|
|
26
|
+
└── cancelled
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Acceptance is atomic with reserving a unique run ID and immutable
|
|
30
|
+
`homeRuntimeId`. A repeated request key returns the existing acceptance.
|
|
31
|
+
|
|
32
|
+
## Run
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
created → preparing → running ↔ waiting
|
|
36
|
+
│ │
|
|
37
|
+
├── blocked_uncertain
|
|
38
|
+
├── cancelling → cancelled
|
|
39
|
+
├── completed
|
|
40
|
+
└── failed
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
| State | Meaning | Allowed exits |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `created` | Identity, owner, and pinned revisions recorded | `preparing`, `cancelled`, `failed` |
|
|
46
|
+
| `preparing` | Inputs, capabilities, workspaces, secrets, and models are being verified; the run plan pin is recorded here | `running`, `cancelled`, `failed` |
|
|
47
|
+
| `running` | One top-level step is active | `waiting`, `blocked_uncertain`, `cancelling`, `completed`, `failed` |
|
|
48
|
+
| `waiting` | No model/process compute is required; a declared signal, lease, or approval is pending | `running`, `blocked_uncertain`, `cancelling`, `completed`, `failed`, `cancelled` |
|
|
49
|
+
| `blocked_uncertain` | An effect outcome cannot be proven | `running`, `cancelling`, `failed` |
|
|
50
|
+
| `cancelling` | Cancellation has been durably requested and child processes are draining | `cancelled`, `blocked_uncertain`, `failed` |
|
|
51
|
+
| `completed` | Declared success terminal reached | None |
|
|
52
|
+
| `failed` | Declared failure or exhausted budget reached | None |
|
|
53
|
+
| `cancelled` | Cancellation completed without unresolved owned effects | None |
|
|
54
|
+
|
|
55
|
+
Operator `cancelled` from `created` or `preparing` requires a recorded
|
|
56
|
+
`run.cancel_requested`. A compiled selected `terminalStatus=cancelled` may
|
|
57
|
+
still complete from `running` without that operator event.
|
|
58
|
+
|
|
59
|
+
A run cannot move to another Runtime by editing a projection or hub record.
|
|
60
|
+
|
|
61
|
+
## Step and step attempt
|
|
62
|
+
|
|
63
|
+
Only one top-level step is active. Entering a step creates a new positive
|
|
64
|
+
`stepAttempt` number.
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
pending → preparing → running ↔ waiting
|
|
68
|
+
│ │
|
|
69
|
+
├── blocked_uncertain
|
|
70
|
+
├── passed
|
|
71
|
+
├── failed
|
|
72
|
+
├── skipped
|
|
73
|
+
└── cancelled
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
A typed transition from a terminal step attempt selects the next step or a run
|
|
77
|
+
terminal. A back-edge creates a fresh step attempt and fresh assignment set.
|
|
78
|
+
`step.maxAttempts` bounds all entries/retries of that step for the run in
|
|
79
|
+
addition to global and per-edge transition budgets. Evidence is attempt-bound
|
|
80
|
+
unless its declaration explicitly allows reuse.
|
|
81
|
+
|
|
82
|
+
`skipped` is legal only when a validated workflow declares the skip outcome and
|
|
83
|
+
proves that no required approval or gate is bypassed.
|
|
84
|
+
|
|
85
|
+
## Assignment
|
|
86
|
+
|
|
87
|
+
An assignment is logical work and may have more than one physical attempt.
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
created → accepted → dispatched → executing → result_recorded → terminal
|
|
91
|
+
▲ │ │
|
|
92
|
+
│ ├── reattaching
|
|
93
|
+
└── retry_pending─┘ └── blocked_uncertain
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
| State | Durable condition |
|
|
97
|
+
|---|---|
|
|
98
|
+
| `created` | Assignment identity, purpose, bounds, and requested evidence recorded |
|
|
99
|
+
| `accepted` | Runtime has resolved policy, agent, model, repository, tools, secrets, and executor |
|
|
100
|
+
| `dispatched` | Attempt identity and dispatch intent persisted before process start |
|
|
101
|
+
| `executing` | Invocation admitted and the attempt capability is usable. This slice is in-process (no OS process identity yet); later recovery still requires exact process/session proof |
|
|
102
|
+
| `reattaching` | Runtime is verifying the same process/session and event cursor |
|
|
103
|
+
| `result_recorded` | Structured attempt result and referenced receipts are durably stored |
|
|
104
|
+
| `retry_pending` | Policy permits another physical attempt after the prior attempt became terminal |
|
|
105
|
+
| `blocked_uncertain` | A dependent effect cannot be reconciled safely |
|
|
106
|
+
| `terminal` | The logical assignment outcome is final and immutable: passed, failed, or cancelled |
|
|
107
|
+
|
|
108
|
+
`assignmentId` remains stable. A retry moves the nonterminal assignment through
|
|
109
|
+
`retry_pending` to `accepted`, creates a new `attemptId`, and never rewrites or
|
|
110
|
+
exits the previous attempt's terminal state. The effective
|
|
111
|
+
`assignments.maxAttemptsPerAssignment` bounds physical attempts; the Runtime
|
|
112
|
+
may retry only outcomes and effect classes declared safe by trusted policy.
|
|
113
|
+
|
|
114
|
+
## Assignment attempt
|
|
115
|
+
|
|
116
|
+
```text
|
|
117
|
+
created → starting → executing → settling → terminal
|
|
118
|
+
│ │
|
|
119
|
+
│ ├── reattaching → executing
|
|
120
|
+
│ └── blocked_uncertain
|
|
121
|
+
└── connection_lost
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Reattachment to the same attempt requires all of:
|
|
125
|
+
|
|
126
|
+
- exact Runtime, run, assignment, and attempt identity;
|
|
127
|
+
- exact physical process or harness session identity;
|
|
128
|
+
- compatible executor/helper generation;
|
|
129
|
+
- valid last durable event cursor;
|
|
130
|
+
- no replacement process or attempt;
|
|
131
|
+
- unchanged scope epoch and grants.
|
|
132
|
+
|
|
133
|
+
If those facts cannot be proven, the Runtime either creates a new attempt after
|
|
134
|
+
safe reconciliation or enters `blocked_uncertain`.
|
|
135
|
+
|
|
136
|
+
## Dynamic assignment panel
|
|
137
|
+
|
|
138
|
+
Every step has effective bounds:
|
|
139
|
+
|
|
140
|
+
```text
|
|
141
|
+
minimum ≤ target ≤ maximum
|
|
142
|
+
maxParallel ≤ maximum
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The coordinator may create assignments only until `maximum`. Every assignment,
|
|
146
|
+
including one whose provider work began but failed to start fully, counts
|
|
147
|
+
against the step attempt's maximum. Each assignment also has a compiled physical
|
|
148
|
+
attempt ceiling; omitting a project override uses the step-kind default rather
|
|
149
|
+
than an unbounded retry policy.
|
|
150
|
+
|
|
151
|
+
Fail-closed compiled defaults:
|
|
152
|
+
|
|
153
|
+
| Step kind | Step attempts | Assignments | Physical attempts per assignment | Join |
|
|
154
|
+
|---|---:|---:|---:|---|
|
|
155
|
+
| Single agent | 1 | Exactly 1 | 1 | `all` |
|
|
156
|
+
| Deterministic gate | 1 | Exactly 1 | 1 | `all` |
|
|
157
|
+
| Human approval | 1 | Exactly 1 authorized decision | 1 | `all` |
|
|
158
|
+
| Wait | 1 | Exactly 1 signal | 1 | `all` |
|
|
159
|
+
| MOA | 1 | Exactly 1 unless the step declares a panel | 1 | `all` |
|
|
160
|
+
|
|
161
|
+
Current contract (`kxm.workflow.v1`): an omitted `assignments` block resolves for every kind to minimum 1, target = minimum, maximum = target, maxParallel = maximum, one physical attempt per assignment; an omitted `join` resolves to `all`. The loader checks these numbers and the compiler mirrors them exactly; the compiler never resolves a larger ceiling than the loader validated. A MOA step must declare its panel explicitly (see `fix.yaml`). The kind-level MOA default of target 3, minimum 2, maximum 3, all-settled with two valid completions is a Phase 7 change made to schema, loader, compiler, and this table in one change.
|
|
162
|
+
|
|
163
|
+
Templates may materialize larger reviewed attempt ceilings. No omitted field ever
|
|
164
|
+
means unlimited retries.
|
|
165
|
+
`first-success` is valid only for an explicitly speculative, safely cancellable
|
|
166
|
+
step. It is invalid for independent review.
|
|
167
|
+
|
|
168
|
+
## Effect
|
|
169
|
+
|
|
170
|
+
```text
|
|
171
|
+
intent_recorded → dispatched → observed → receipt_recorded → settled
|
|
172
|
+
│ │
|
|
173
|
+
└──────────┴── blocked_uncertain
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The intent, effect class, idempotency key, and expected receipt query are
|
|
177
|
+
recorded before dispatch. See [Effects and recovery](effects-and-recovery.md).
|
|
178
|
+
|
|
179
|
+
## Delivery
|
|
180
|
+
|
|
181
|
+
A multi-repository delivery is explicitly non-atomic.
|
|
182
|
+
|
|
183
|
+
```text
|
|
184
|
+
planned → preparing → delivering → completed
|
|
185
|
+
│ │
|
|
186
|
+
│ ├── partial
|
|
187
|
+
│ ├── blocked_uncertain
|
|
188
|
+
│ └── failed
|
|
189
|
+
└── cancelled
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Each repository has its own result and receipt. `partial` is a delivery-panel
|
|
193
|
+
state, not an individual assignment-result status. It never projects as
|
|
194
|
+
`completed`; remediation or compensation is explicit. Conversely, a manifest
|
|
195
|
+
with any `delivered` repository cannot project as `failed`, `cancelled`, or
|
|
196
|
+
`blocked_uncertain`: it is `partial` until the delivered work is explicitly
|
|
197
|
+
accounted for. Every `delivered` repository has at least one receipt.
|
|
198
|
+
|
|
199
|
+
## Synchronization
|
|
200
|
+
|
|
201
|
+
```text
|
|
202
|
+
local_event → sync_transform → outbox_pending → acknowledged
|
|
203
|
+
│ │
|
|
204
|
+
└── omitted ├── retry_pending
|
|
205
|
+
└── rejected
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
`omitted` means the event contains no sync-worthy fields under policy. A
|
|
209
|
+
schema-invalid or unsafe transformation never enters the outbox. `rejected`
|
|
210
|
+
requires operator-visible diagnostics; the local run remains authoritative.
|
|
211
|
+
|
|
212
|
+
## Session lifecycle
|
|
213
|
+
|
|
214
|
+
A physical agent session is reusable only within one exact run and compatible
|
|
215
|
+
scope epoch.
|
|
216
|
+
|
|
217
|
+
```text
|
|
218
|
+
created → active ↔ idle → closed
|
|
219
|
+
│ │
|
|
220
|
+
└── rotate_scope → closed + new scope epoch
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Scope rotation occurs before an assignment with narrower or incompatible
|
|
224
|
+
repository, secret, tool, model, executor, or disclosure scope is dispatched.
|
|
225
|
+
|
|
226
|
+
## Recovery invariants
|
|
227
|
+
|
|
228
|
+
1. No terminal state exits.
|
|
229
|
+
2. No sequence number is reused.
|
|
230
|
+
3. No new process inherits an old `attemptId`.
|
|
231
|
+
4. No prior step-attempt evidence silently satisfies a later attempt.
|
|
232
|
+
5. No coordinator command expands a compiled policy ceiling.
|
|
233
|
+
6. No unknown effect is replayed automatically.
|
|
234
|
+
7. No session crosses a run or incompatible scope epoch.
|
|
235
|
+
8. No hub projection changes home-owned run state.
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# Migration and compatibility matrix
|
|
2
|
+
|
|
3
|
+
KXM vNext is introduced beside the current v0.5 transport/workflow surfaces.
|
|
4
|
+
Presence of vNext documents does not activate new behavior.
|
|
5
|
+
|
|
6
|
+
## Surface matrix
|
|
7
|
+
|
|
8
|
+
| Current surface | vNext 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 | Copy through versioned migration; never mutate the only database in place |
|
|
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
|
+
Local Runtime support may ship publicly before hub vNext, but it remains beside
|
|
30
|
+
existing hub contracts and stores. Old command names are not preserved. A project
|
|
31
|
+
activates `kxm.*.v1` only by an explicit successful `kxm init`/migration receipt;
|
|
32
|
+
file presence alone never activates it. Legacy hub runs continue on the legacy
|
|
33
|
+
engine.
|
|
34
|
+
|
|
35
|
+
When Phase 8 activates hub vNext, at least one hub transition release provides:
|
|
36
|
+
|
|
37
|
+
- current `mesh_*` peer tools;
|
|
38
|
+
- current hub APIs behind a compatibility adapter;
|
|
39
|
+
- legacy JSON configuration read support while vNext writes only YAML;
|
|
40
|
+
- current completed workflow history read/export support;
|
|
41
|
+
- Runtime-managed vNext runs in new event stores with new identities;
|
|
42
|
+
- CLI labels for legacy versus vNext state;
|
|
43
|
+
- no implicit movement of active runs between engines.
|
|
44
|
+
|
|
45
|
+
Before activation, a repository MUST NOT use legacy and vNext definitions with
|
|
46
|
+
the same normalized identity. Validation reports the conflict and requires an
|
|
47
|
+
explicit migration choice. After a migration receipt activates the vNext copy,
|
|
48
|
+
the matching legacy definition is read-only compatibility input and cannot be
|
|
49
|
+
selected for a new vNext run.
|
|
50
|
+
|
|
51
|
+
## Migration commands
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
kxm migrate plan
|
|
55
|
+
kxm migrate apply [--decisions <file>] [--project-id <id>] [--name <name>]
|
|
56
|
+
kxm migrate verify
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`kxm init` invokes the planning flow when it detects legacy state.
|
|
60
|
+
|
|
61
|
+
**Implementation status (Phase 1 slice):** the commands above are implemented
|
|
62
|
+
for **configuration migration only** — legacy `agents.json`, `gates.json`, and
|
|
63
|
+
workflow-definition JSON under `.kxm/config/`. Database/WAL migration,
|
|
64
|
+
active-run cutover, session migration, and rollback orchestration remain
|
|
65
|
+
later-phase work and are not performed by these commands.
|
|
66
|
+
|
|
67
|
+
### Plan
|
|
68
|
+
|
|
69
|
+
Produces a secret-free `kxm.migration-plan.v1` report containing:
|
|
70
|
+
|
|
71
|
+
- detected source files with sha256 and byte counts plus a combined
|
|
72
|
+
`sourceDigest`;
|
|
73
|
+
- target resource paths with their rendered content hashes;
|
|
74
|
+
- deterministic ambiguities, each with a stable decision key and the allowed
|
|
75
|
+
values: terminal status for legacy `$terminal` edges, per-edge budgets for
|
|
76
|
+
unbounded back-edges, missing global transition budgets, evidence-policy
|
|
77
|
+
strengthening (`replied` → `passed`), foreign producer identities, secret
|
|
78
|
+
field drops, narrowed permission ceilings, and identity normalization;
|
|
79
|
+
- unrecognized or unmappable fields preserved as hashed `unmapped` entries
|
|
80
|
+
(sensitive values are hashed, never copied);
|
|
81
|
+
- old-to-new identity renames;
|
|
82
|
+
- the resulting permission changes tied to their decision keys.
|
|
83
|
+
|
|
84
|
+
It changes nothing: no writes, no locks, no staging, no local state.
|
|
85
|
+
|
|
86
|
+
### Decisions
|
|
87
|
+
|
|
88
|
+
`kxm migrate apply` requires every ambiguity to be resolved. Decisions are
|
|
89
|
+
supplied either as a reviewed `kxm.migration-decision.v1` YAML file
|
|
90
|
+
(`--decisions <file>`) binding the exact `projectId`, `projectName`, and
|
|
91
|
+
`sourceDigest` of the plan, or programmatically. Unknown decision keys and
|
|
92
|
+
values outside the plan's allowed set fail closed before any write.
|
|
93
|
+
|
|
94
|
+
### Apply
|
|
95
|
+
|
|
96
|
+
1. Acquire the project mutation lock.
|
|
97
|
+
2. Recompute the plan and re-check the decision binding (project, source
|
|
98
|
+
digest, key set, allowed values).
|
|
99
|
+
3. Validate every converted resource against its exact schema and the whole
|
|
100
|
+
bundle against semantic rules.
|
|
101
|
+
4. Refuse to overwrite any existing target path.
|
|
102
|
+
5. Install resources with durable writes (fsync + rename).
|
|
103
|
+
6. Load and validate the complete installed bundle.
|
|
104
|
+
7. Write a hash-linked `kxm.migration-receipt.v1` binding source hashes,
|
|
105
|
+
decision digest, target configuration revision, and installed resource
|
|
106
|
+
hashes; the receipt is self-hashed.
|
|
107
|
+
8. Re-load the mixed tree: legacy inputs remain intact but receipt-pinned
|
|
108
|
+
read-only; `loadVnextProject` accepts coexistence only through the
|
|
109
|
+
verified receipt.
|
|
110
|
+
|
|
111
|
+
Re-applying with the receipt present is an idempotent no-op
|
|
112
|
+
(`already-migrated`). Editing a legacy source after the receipt makes both
|
|
113
|
+
`loadVnextProject` and `kxm migrate verify` fail closed.
|
|
114
|
+
|
|
115
|
+
### Verify
|
|
116
|
+
|
|
117
|
+
`kxm migrate verify` reopens the target, re-checks the receipt self-hash,
|
|
118
|
+
re-hashes legacy sources, and compares the target configuration revision and
|
|
119
|
+
installed resource bytes against the receipt. It performs no writes.
|
|
120
|
+
|
|
121
|
+
## Database migration
|
|
122
|
+
|
|
123
|
+
Before any database operation:
|
|
124
|
+
|
|
125
|
+
- verify SQLite `user_version`;
|
|
126
|
+
- refuse a newer unknown version;
|
|
127
|
+
- checkpoint WAL or copy using the SQLite backup API;
|
|
128
|
+
- include `-wal` state correctly rather than copying only the main file;
|
|
129
|
+
- verify backup integrity;
|
|
130
|
+
- record source and target hashes.
|
|
131
|
+
|
|
132
|
+
Current agents, messages, workflow runs, journal entries, and context items are
|
|
133
|
+
imported as typed **legacy records**. They are not fabricated into fine-grained
|
|
134
|
+
vNext run events whose original ordering was never observed.
|
|
135
|
+
|
|
136
|
+
Completed legacy runs remain queryable. A legacy active run must either finish
|
|
137
|
+
on the old engine or be explicitly cancelled/exported; it is not resumed as a
|
|
138
|
+
vNext run.
|
|
139
|
+
|
|
140
|
+
## Configuration migration
|
|
141
|
+
|
|
142
|
+
The implemented converter:
|
|
143
|
+
|
|
144
|
+
- reads legacy JSON with byte/depth/node bounds and token-level duplicate-key
|
|
145
|
+
rejection; linked files and linked `workflows/` directories are never
|
|
146
|
+
traversed for authoritative bytes;
|
|
147
|
+
- normalizes case-insensitive identities, records explicit old-to-new renames,
|
|
148
|
+
and rejects case-fold collisions and destination-invalid names;
|
|
149
|
+
- splits `agents.json` into `.kxm/agents/<id>.yaml` resources and emits one
|
|
150
|
+
`.kxm/models/<id>-primary.yaml` profile per agent whose legacy record pinned
|
|
151
|
+
a provider/model pair with a thinking level;
|
|
152
|
+
- maps roster-only concepts (`ownership`, `host`, top-level `project`) into
|
|
153
|
+
hashed `unmapped` report entries rather than dropping them silently;
|
|
154
|
+
- maps workflow stages to agent steps, preserves `reproOracle`, `planHash`,
|
|
155
|
+
`requirePlanHash`, typed transitions, immutable oracles, and global
|
|
156
|
+
transition budgets, and widens evidence-carrying steps into an explicit
|
|
157
|
+
assignment pool containing their producers;
|
|
158
|
+
- converts legacy peer-reply evidence policies (`acceptedStatuses:
|
|
159
|
+
["replied"]`) into vNext producer policies requiring `passed` only through
|
|
160
|
+
an explicit operator decision;
|
|
161
|
+
- requires decisions for: every legacy `$terminal` edge's terminal status
|
|
162
|
+
(legacy completed the run even on failure outcomes), every unbounded
|
|
163
|
+
back-edge's per-edge budget, missing global budgets, foreign producer
|
|
164
|
+
identities, secret-field drops, unimplemented gates, and each narrowed
|
|
165
|
+
permission ceiling;
|
|
166
|
+
- never copies secret values or environment indirections; webhook secret
|
|
167
|
+
fields are hashed into the report and dropped by explicit decision;
|
|
168
|
+
- records template provenance only for files whose exact generated baseline is
|
|
169
|
+
known; migrated files carry no template provenance and are never
|
|
170
|
+
retroactively adopted;
|
|
171
|
+
- validates the entire target project (exact schemas plus semantic rules)
|
|
172
|
+
before installation and shows the Git diff through normal review.
|
|
173
|
+
|
|
174
|
+
Unknown data is preserved in the migration report, not placed into a generic
|
|
175
|
+
runtime extension map.
|
|
176
|
+
|
|
177
|
+
Legacy typed workflows have a global transition budget but may lack vNext
|
|
178
|
+
per-back-edge caps. The migrator MUST NOT invent those caps silently. `migrate
|
|
179
|
+
plan` lists every affected edge and a proposed bounded value; `migrate apply`
|
|
180
|
+
requires the values in an operator-approved migration decision. The committed
|
|
181
|
+
vNext `/fix` fixture is one reviewed resolution, not a generic automatic rule.
|
|
182
|
+
|
|
183
|
+
Stage IDs, outcome keys, evidence keys, oracle references, plan-hash references,
|
|
184
|
+
and eligible producer identities are preserved by default. Any unavoidable
|
|
185
|
+
normalization appears as an explicit old-to-new mapping and rewrites all bound
|
|
186
|
+
references atomically.
|
|
187
|
+
|
|
188
|
+
## Session migration
|
|
189
|
+
|
|
190
|
+
Old shared Pi histories may contain content from broader scopes. They remain
|
|
191
|
+
archived under the old worker binding and are never selected for a vNext run.
|
|
192
|
+
The first vNext physical session starts clean. Durable facts must come from Git,
|
|
193
|
+
workflow evidence, artifacts, or promoted context rather than conversation
|
|
194
|
+
history.
|
|
195
|
+
|
|
196
|
+
## Rollback
|
|
197
|
+
|
|
198
|
+
Rollback is supported until the operator accepts the migration receipt and
|
|
199
|
+
starts a permission-expanding vNext-only run.
|
|
200
|
+
|
|
201
|
+
Rollback:
|
|
202
|
+
|
|
203
|
+
1. stop vNext writers;
|
|
204
|
+
2. preserve vNext stores as diagnostic artifacts;
|
|
205
|
+
3. restore the recorded legacy configuration selection and database path;
|
|
206
|
+
4. restart only compatible legacy processes;
|
|
207
|
+
5. verify legacy health and record rollback evidence.
|
|
208
|
+
|
|
209
|
+
Events created only by vNext are not reverse-translated into fabricated legacy
|
|
210
|
+
workflow history.
|
|
211
|
+
|
|
212
|
+
## Removal gate
|
|
213
|
+
|
|
214
|
+
Legacy readers and command aliases are removed only after:
|
|
215
|
+
|
|
216
|
+
- at least one compatibility release;
|
|
217
|
+
- migration telemetry shows no material unmapped cases;
|
|
218
|
+
- package/install/Windows tests cover vNext;
|
|
219
|
+
- operator documentation and rollback paths are proven;
|
|
220
|
+
- removal is announced in the changelog.
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# Routing and cost telemetry
|
|
2
|
+
|
|
3
|
+
> **Status.** `kxm.routing-record.v1` is parse-only for legacy records.
|
|
4
|
+
> `kxm.routing-record.v2` is **implemented and active**: emitted at engine
|
|
5
|
+
> attempt settlement (`routing.attempt.recorded` event in `plugins/kxm/src/vnext-engine.ts`),
|
|
6
|
+
> enforced with fail-closed `costBasis` requirement. Price catalog `.kxm/prices.yaml`
|
|
7
|
+
> (`kxm.prices.v1`) is implemented, dated, and hashed. `kxm routing report`
|
|
8
|
+
> is implemented (`plugins/kxm/src/routing.ts`) and ranks routes quality-first,
|
|
9
|
+
> then cost per accepted attempt, never ranking unknown cost cheapest and
|
|
10
|
+
> reporting metered, unmetered, and unknown populations separately. Dev-helper
|
|
11
|
+
> telemetry (`scripts/harness-run.mjs`) and the issue 127 assignment runner
|
|
12
|
+
> (`scripts/assignment-run.mjs`, `just assign`) are implemented developer tools.
|
|
13
|
+
|
|
14
|
+
This document describes what the tree does today versus what Tracking still
|
|
15
|
+
plans. It does not invent prices or close product enums.
|
|
16
|
+
|
|
17
|
+
## Implemented: v1 record
|
|
18
|
+
|
|
19
|
+
Schema id: `kxm.routing-record.v1` (`plugins/kxm/src/routing.ts`).
|
|
20
|
+
|
|
21
|
+
Always present or defaulted by `parseRoutingRecord`: `schema`,
|
|
22
|
+
`behavioralHashVersion`, `behavioralSha256`, `skills` (default `[]`),
|
|
23
|
+
`contextItemIds` (default `[]`), `retries` / `transitions` /
|
|
24
|
+
`humanInterventions` (default `0`).
|
|
25
|
+
|
|
26
|
+
Optional when present and valid: `workflowRunId`, `stageId`, `attempt`,
|
|
27
|
+
`requestedModel`, `effectiveModel`, `reasoningEffort`, `agentRole`,
|
|
28
|
+
`rolePromptSha256`, `contextPolicyVersion`, `toolPolicyVersion`,
|
|
29
|
+
`workflowDefinitionSha256`, `verifierConfigSha256`, `tokensIn`, `tokensOut`,
|
|
30
|
+
`cacheReadTokens`, `costUsd`, `verifierOutcome`, `finalOutcome`, bounded
|
|
31
|
+
`providerMetadata`.
|
|
32
|
+
|
|
33
|
+
The behavioral hash covers the configuration tuple (normalized models, role,
|
|
34
|
+
prompt/skill/tool/workflow/verifier hashes). Outcome telemetry (tokens, cost,
|
|
35
|
+
retries, outcomes) is outside the hash.
|
|
36
|
+
|
|
37
|
+
**No built-in product producer.** The worker envelope validates a `routing`
|
|
38
|
+
field when present. Nothing in `plugins/kxm/src` or `scripts/kxm-worker.mjs`
|
|
39
|
+
writes a record. Repo records are test-built. External JSONL can be ingested.
|
|
40
|
+
|
|
41
|
+
v1 has **no dedicated fields** for harness, provider, latency, cost basis,
|
|
42
|
+
cache-write tokens, or context occupancy. Bounded `providerMetadata` may
|
|
43
|
+
carry extra keys (at most 32; values are strings, numbers, or booleans;
|
|
44
|
+
`prompt`/`body`/`content`/`message` keys are rejected), but those keys are
|
|
45
|
+
**not standardized** and `kxm routing report` does not read them.
|
|
46
|
+
|
|
47
|
+
`kxm routing report` reads `telemetry.jsonl`, groups by behavioral hash, sorts
|
|
48
|
+
by run count (then hash), and sums missing `costUsd` as **zero**. That silent
|
|
49
|
+
underquote is why the report is **not** a ranking source.
|
|
50
|
+
|
|
51
|
+
## Implemented: dev helper telemetry
|
|
52
|
+
|
|
53
|
+
`scripts/harness-run.mjs` emits `kxm.harness-result.v2` after a
|
|
54
|
+
`kxm.harness-request.v1`. It is not a Phase 11 adapter and is not persisted as
|
|
55
|
+
a routing record. Helper `status` is transport-only (`completed`, `failed`,
|
|
56
|
+
`interrupted`) and must not be read as product `routing-record.v1`
|
|
57
|
+
`finalOutcome`. Obsolete `kxm.harness-result.v1` files are diagnosed (file,
|
|
58
|
+
observed known schema or `unrecognized`, obsolete schema id) and left
|
|
59
|
+
untouched; there is no v1 parser or upgrade lane. Public result fields are
|
|
60
|
+
a closed allowlist with type checks (no arbitrary objects in scalar
|
|
61
|
+
positions); raw model/stdio text is not copied into metadata.
|
|
62
|
+
|
|
63
|
+
Observed normalization (not an invoice; none of these paths reconcile
|
|
64
|
+
against an invoice or usage API):
|
|
65
|
+
|
|
66
|
+
- Token basis is `cumulative`. Context occupancy is always `unknown`.
|
|
67
|
+
Values above the routing v1 int cap stay in metadata and are not clamped.
|
|
68
|
+
- Helper cost-basis labels are `provider-reported`, `list`, `unmetered`, and
|
|
69
|
+
`unknown`. `billed` is reserved for invoice provenance and is **not**
|
|
70
|
+
emitted here. `just runs` can still print a `billed` label if a v2 file
|
|
71
|
+
already has that string.
|
|
72
|
+
- Claude/Grok (`normalizeClaudeOrGrok`): when the payload has a provider
|
|
73
|
+
cost, that number is copied into **both** `costUsd` and
|
|
74
|
+
`providerReportedCostUsd`. Explicit `modelUsage` `costBasis: "list"` stays
|
|
75
|
+
`list`. Grok `total_cost_usd` without that list basis is
|
|
76
|
+
`provider-reported`. After parse, subscription Claude
|
|
77
|
+
(`authStatus.method === "claude.ai"`) sets `costBasis` to `unmetered` and
|
|
78
|
+
**clears `costUsd`**, leaving `providerReportedCostUsd` when it was present.
|
|
79
|
+
- Pi (`normalizePi`): sums `usage.cost.total` from assistant
|
|
80
|
+
`message_end` events into `costUsd` only. Basis is `list` when that
|
|
81
|
+
aggregate exists, otherwise `unknown`. There is **no**
|
|
82
|
+
`providerReportedCostUsd` field on this path.
|
|
83
|
+
- Codex (`normalizeCodex`): emits `costBasis: "unmetered"` (empty payload
|
|
84
|
+
is `unknown`). Root-verified helper auth preflight permits Codex
|
|
85
|
+
**ChatGPT only** (`scripts/harness-run.mjs` ChatGPT login parse). The
|
|
86
|
+
post-normalize ChatGPT branch also clears `costUsd`. Do not invent an
|
|
87
|
+
API-key billing path here; B3 inventory of other Codex surfaces is a
|
|
88
|
+
**separate** product/inventory question, not this helper.
|
|
89
|
+
- Formatter `formatRunCost` still prints `billed $…` when a listing file
|
|
90
|
+
already has `costBasis: "billed"`. The helper itself does not emit that
|
|
91
|
+
label. That is display of a supplied label, not invoice reconciliation.
|
|
92
|
+
|
|
93
|
+
Do not relabel provider-reported or list-basis amounts as billed. Partial
|
|
94
|
+
usage after failure or interruption is kept and marked `usagePartial`;
|
|
95
|
+
missing counters stay absent, not zero.
|
|
96
|
+
|
|
97
|
+
## Implemented/unreleased: assignment runner (issue 127)
|
|
98
|
+
|
|
99
|
+
`scripts/assignment-run.mjs` is the normal **dev** entry. It is not `kxm run`
|
|
100
|
+
and does not replace Phase 3/4 gates.
|
|
101
|
+
|
|
102
|
+
Working commands (absolute paths; flags from the script, not invented):
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
just assign /abs/manifest.json
|
|
106
|
+
# node scripts/assignment-run.mjs run --manifest /abs/manifest.json
|
|
107
|
+
|
|
108
|
+
just witness /abs/record-dir
|
|
109
|
+
# witness --record-dir /abs/record-dir
|
|
110
|
+
|
|
111
|
+
just attribute /abs/task-dir /abs/record-dir orchestration /abs/note.txt
|
|
112
|
+
# attribute --task-dir --record-dir --class --explanation-file
|
|
113
|
+
|
|
114
|
+
just observe-cost /abs/task-dir /abs/observation.json
|
|
115
|
+
# observe-cost --task-dir --input
|
|
116
|
+
|
|
117
|
+
just accept /abs/task-dir <commit> /abs/writer-record /abs/arch-review /abs/cli-review
|
|
118
|
+
# accept --task-dir --commit --record-dir --critic --critic
|
|
119
|
+
# optional observed PR/CI (direct script; the five-argument just recipe cannot forward them):
|
|
120
|
+
# node scripts/assignment-run.mjs accept --task-dir /abs/task --commit <sha> --record-dir /abs/writer --critic /abs/arch --critic /abs/cli [--observed-pr <id>] [--observed-ci <id>]
|
|
121
|
+
|
|
122
|
+
just plan-current /abs/task-dir /abs/plan.md <sha256> <base-commit> <expected-generation>
|
|
123
|
+
just change-report /abs/task-dir
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`just impl|plan|review-arch|review-cli` remain harness transport. They do not
|
|
127
|
+
create assignment identity, witness receipts, or `accepted.json`.
|
|
128
|
+
|
|
129
|
+
Distinctions the report and docs must keep:
|
|
130
|
+
|
|
131
|
+
- **Manifest / current plan / gate / acceptance / cost** are different
|
|
132
|
+
records. Completions are not acceptance. Witness receipts are not critic
|
|
133
|
+
PASS. `attribute` history does not edit `completion.json`. Cost-only
|
|
134
|
+
imports never gain witness or acceptance eligibility.
|
|
135
|
+
- `change-report` separates provider-reported sums, list estimates,
|
|
136
|
+
unmetered, unknown, not-dispatched (`provider_calls` 0), and partial
|
|
137
|
+
markers. Missing is not `0`. Unmetered is not free. Cumulative tokens are
|
|
138
|
+
not context occupancy. True elapsed time is separate from summed latency
|
|
139
|
+
and summed witness duration. The effort table is descriptive, not a
|
|
140
|
+
ranking. Orchestration/root usage is unavailable unless imported.
|
|
141
|
+
- Observed PR/CI identifiers are unvalidated observations.
|
|
142
|
+
- Private handoff notes live in `attribute` explanations and private model
|
|
143
|
+
summaries; the report references them and does not print the prose.
|
|
144
|
+
|
|
145
|
+
Evidence-informed **effort defaults** for transport recipes and operator
|
|
146
|
+
manifests: medium implementation/planning/architecture, low CLI review. Not a
|
|
147
|
+
learned policy and not a catalog feed. Phase 9 may use this report to
|
|
148
|
+
**propose** harness or model changes; activation still requires Git review.
|
|
149
|
+
|
|
150
|
+
Per-candidate acceptance requires an actual native writer, the fixed witness,
|
|
151
|
+
and both designated native reviews. PR/CI/merge complete issue 127. This
|
|
152
|
+
document does not assert those gates have passed. Low-level
|
|
153
|
+
`just impl|plan|review-arch|review-cli` recipes remain harness transport.
|
|
154
|
+
|
|
155
|
+
## Implemented: v2 record
|
|
156
|
+
|
|
157
|
+
Schema id: `kxm.routing-record.v2` (`plugins/kxm/src/routing.ts`).
|
|
158
|
+
|
|
159
|
+
Fields carried on `RoutingRecordV2`:
|
|
160
|
+
|
|
161
|
+
- Identity & scoping: `schema`, `recordedAt`, `project`, `runId`, `stepId`, `assignmentId`, `attemptId`.
|
|
162
|
+
- Routing configuration: `harness`, `provider`, `requestedModel`, `effectiveModel`, optional `thinking`, optional `agentRole`, `behavioralSha256`.
|
|
163
|
+
- Execution metrics: `latencyMs`, `contextTokens`, `tokensIn`, `tokensOut`, `cacheReadTokens`, `cacheWriteTokens`.
|
|
164
|
+
- Outcomes: `verifierOutcome` (`passed` | `warning` | `failed`), `finalOutcome` (`accepted` | `blocked` | `failed` | `pending`), `retries`, optional `transitions`, optional `humanInterventions`, optional `providerMetadata`.
|
|
165
|
+
- Cost accounting: `costBasis` (`"metered" | "unmetered" | "unknown"`), `costUsd` (required when metered), optional `priceRef`.
|
|
166
|
+
|
|
167
|
+
The vNext engine settle transaction appends a `routing.attempt.recorded` event carrying the v2 record and refuses to settle without a valid `costBasis`. Attempt dispatch enforces `limits.maxModelCost` against metered cost before invocation (`budget_model_cost`).
|
|
168
|
+
|
|
169
|
+
## Implemented: report and price catalog
|
|
170
|
+
|
|
171
|
+
- **Price catalog:** `.kxm/prices.yaml` (`kxm.prices.v1`, dated and hashed) defines input, output, cache-read, cache-write rates, and context tiers for active models. Missing rows or uncataloged models evaluate to `costBasis: "unknown"`.
|
|
172
|
+
- **Ranked report:** `kxm routing report` (`plugins/kxm/src/routing.ts`, CLI command `kxm routing report`) groups records by `(harness, model, thinking, role)`.
|
|
173
|
+
- **Ranking order:** Quality first (`verifyPassRate` descending, then `reworkRate` ascending where rework measures back-edge re-entries `transitions > 0`), followed by `costPerAcceptedUsd` ascending.
|
|
174
|
+
- **Underquote prevention:** Routes with unknown cost are flagged (`*`) and **never ranked cheapest**, eliminating silent underquoting.
|
|
175
|
+
- **Population separation:** Reports metered cost, unmetered attempt counts, unknown-cost attempt counts, and quota-exhausted attempt counts as separate metrics rather than a single misleading total.
|
|
176
|
+
- **List prices flag:** Supports `--equivalent-list-cost` / `--list-prices` to display estimated list rates for comparison alongside actual recorded spend.
|
|
177
|
+
- **Post-MVP:** Dynamic catalog price feeds (`kxm update --models`), budget roll-over, and automated promotion of repeat successes into workflow gates.
|
|
178
|
+
|
|
179
|
+
## Precedence
|
|
180
|
+
|
|
181
|
+
[AGENTS.md](../../AGENTS.md) and
|
|
182
|
+
[Tracking](../../plans/implementation-plan.md#tracking-working-tree-not-a-release)
|
|
183
|
+
win where they differ from historical 2026-09-04 reviews.
|
|
184
|
+
Issue 86 stays open for later-phase remainder (see Tracking).
|