@kontextmind/kxm 0.7.61 → 0.7.64
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 +1 -1
- package/docs/contracts/lifecycles.md +1 -1
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/runtime-supervisor.js +28 -9
- package/plugins/kxm/dist/runtime.js +28 -9
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/engine.ts +38 -7
- package/plugins/kxm/src/harness.ts +11 -2
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/schemas/run-event.schema.json +1 -0
|
@@ -100,7 +100,7 @@ created → accepted → dispatched → executing → result_recorded → termin
|
|
|
100
100
|
| `dispatched` | Attempt identity and dispatch intent persisted before process start |
|
|
101
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
102
|
| `reattaching` | Runtime is verifying the same process/session and event cursor |
|
|
103
|
-
| `result_recorded` | Structured attempt result and referenced receipts are durably stored |
|
|
103
|
+
| `result_recorded` | Structured attempt result and referenced receipts are durably stored. When a producer **refused** (`resultClass: producer_rejected`), the payload may carry `producerError`: a **machine code only** (lowercase-underscore identifier, ≤64 chars, schema-enforced; capability material is redacted before extraction, and anything unclassifiable — including prose — records as `producer_error`). The routing record names the producer that actually ran: a live drive that fails authentication must never read in the log as a simulation |
|
|
104
104
|
| `retry_pending` | Policy permits another physical attempt after the prior attempt became terminal |
|
|
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 |
|
package/package.json
CHANGED
|
@@ -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.
|
|
5
|
+
"version": "0.7.64",
|
|
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",
|
|
@@ -17121,7 +17121,7 @@ async function deliverInboxNotification(messageId, delivered, notify) {
|
|
|
17121
17121
|
}
|
|
17122
17122
|
|
|
17123
17123
|
// plugins/kxm/src/mcp-server.ts
|
|
17124
|
-
var VERSION = "0.7.
|
|
17124
|
+
var VERSION = "0.7.64";
|
|
17125
17125
|
var inbox = /* @__PURE__ */ new Map();
|
|
17126
17126
|
var notifiedInbox = /* @__PURE__ */ new Set();
|
|
17127
17127
|
var meshClient;
|
|
@@ -16102,8 +16102,9 @@ function probeHarnessAssignment(options) {
|
|
|
16102
16102
|
};
|
|
16103
16103
|
}
|
|
16104
16104
|
const authArgs = ["auth", "check"];
|
|
16105
|
-
|
|
16106
|
-
|
|
16105
|
+
const qualifiedModel = options.model ? options.provider && options.model.startsWith(`${options.provider}/`) ? options.model : options.provider ? `${options.provider}/${options.model}` : options.model : void 0;
|
|
16106
|
+
if (qualifiedModel) {
|
|
16107
|
+
authArgs.push("--model", qualifiedModel);
|
|
16107
16108
|
} else if (options.provider) {
|
|
16108
16109
|
authArgs.push("--provider", options.provider);
|
|
16109
16110
|
}
|
|
@@ -24601,15 +24602,29 @@ var KxmRunScheduler = class _KxmRunScheduler {
|
|
|
24601
24602
|
}
|
|
24602
24603
|
};
|
|
24603
24604
|
function invokeProducer(producer, request) {
|
|
24605
|
+
const reason = (error) => {
|
|
24606
|
+
try {
|
|
24607
|
+
const raw = error instanceof Error ? error.message : error;
|
|
24608
|
+
const message = typeof raw === "string" ? raw : "";
|
|
24609
|
+
let text = message;
|
|
24610
|
+
if (request.capability) text = text.split(request.capability).join("[redacted]");
|
|
24611
|
+
text = text.replace(/kxmcap_[A-Za-z0-9_-]+/g, "[redacted]");
|
|
24612
|
+
const match = /^[a-z][a-z0-9]*(?:_[a-z0-9]+){1,3}/.exec(text);
|
|
24613
|
+
const code = match?.[0] ?? "";
|
|
24614
|
+
return code.length > 0 && code.length <= 64 ? code : "producer_error";
|
|
24615
|
+
} catch {
|
|
24616
|
+
return "producer_error";
|
|
24617
|
+
}
|
|
24618
|
+
};
|
|
24604
24619
|
let pending;
|
|
24605
24620
|
try {
|
|
24606
24621
|
pending = Promise.resolve(producer.produce(request));
|
|
24607
|
-
} catch {
|
|
24608
|
-
return Promise.resolve({ error: true });
|
|
24622
|
+
} catch (error) {
|
|
24623
|
+
return Promise.resolve({ error: true, errorCode: reason(error) });
|
|
24609
24624
|
}
|
|
24610
24625
|
return pending.then(
|
|
24611
24626
|
(result) => ({ result, error: false }),
|
|
24612
|
-
() => ({ error: true })
|
|
24627
|
+
(error) => ({ error: true, errorCode: reason(error) })
|
|
24613
24628
|
);
|
|
24614
24629
|
}
|
|
24615
24630
|
var kxmGateDispatchSeams = {};
|
|
@@ -25428,7 +25443,7 @@ async function drivePanel(context, panel, producer) {
|
|
|
25428
25443
|
if (kxmPanelDispatchSeams.failSettleMember?.(member)) {
|
|
25429
25444
|
throw runtimeError("run_events_illegal", runId, "member settlement write failed");
|
|
25430
25445
|
}
|
|
25431
|
-
settleMember(context, member, produced.result, produced.error);
|
|
25446
|
+
settleMember(context, member, produced.result, produced.error, produced.errorCode);
|
|
25432
25447
|
});
|
|
25433
25448
|
return true;
|
|
25434
25449
|
} catch (err) {
|
|
@@ -25583,7 +25598,7 @@ function producerRoutingRecord(context, dispatch, result, now) {
|
|
|
25583
25598
|
}
|
|
25584
25599
|
return parseRoutingRecordV2(record2);
|
|
25585
25600
|
}
|
|
25586
|
-
function settleMember(context, dispatch, result, produceError) {
|
|
25601
|
+
function settleMember(context, dispatch, result, produceError, produceErrorCode) {
|
|
25587
25602
|
const run = requireRun(context, dispatch.run.runId);
|
|
25588
25603
|
const state = foldStoredKxmRun(context, run);
|
|
25589
25604
|
const capability = context.eventStore.capabilityByAttempt(dispatch.attemptId);
|
|
@@ -25634,7 +25649,10 @@ function settleMember(context, dispatch, result, produceError) {
|
|
|
25634
25649
|
stepId: dispatch.stepId,
|
|
25635
25650
|
assignmentId: dispatch.assignmentId,
|
|
25636
25651
|
attemptId: dispatch.attemptId,
|
|
25637
|
-
|
|
25652
|
+
// Label the producer that actually ran: the old fallback printed "driver-simulated"
|
|
25653
|
+
// for every producer that was not literally "pi", so a live oneshot drive that
|
|
25654
|
+
// failed authentication read in the log as a simulation.
|
|
25655
|
+
harness: result?.harness ?? dispatch.producerId,
|
|
25638
25656
|
provider: result?.provider ?? "simulated",
|
|
25639
25657
|
requestedModel: result?.requestedModel ?? "simulated",
|
|
25640
25658
|
effectiveModel: result?.effectiveModel ?? result?.requestedModel ?? "simulated",
|
|
@@ -25648,7 +25666,8 @@ function settleMember(context, dispatch, result, produceError) {
|
|
|
25648
25666
|
push("assignment.result_recorded", {
|
|
25649
25667
|
assignmentId: dispatch.assignmentId,
|
|
25650
25668
|
resultClass: "producer_rejected",
|
|
25651
|
-
status: "result_recorded"
|
|
25669
|
+
status: "result_recorded",
|
|
25670
|
+
...produceErrorCode !== void 0 ? { producerError: produceErrorCode } : {}
|
|
25652
25671
|
});
|
|
25653
25672
|
push("attempt.status_changed", { attemptId: dispatch.attemptId, status: "terminal" });
|
|
25654
25673
|
push("assignment.terminal", { assignmentId: dispatch.assignmentId, outcome: "failed", status: "terminal" });
|
|
@@ -16125,8 +16125,9 @@ function probeHarnessAssignment(options) {
|
|
|
16125
16125
|
};
|
|
16126
16126
|
}
|
|
16127
16127
|
const authArgs = ["auth", "check"];
|
|
16128
|
-
|
|
16129
|
-
|
|
16128
|
+
const qualifiedModel = options.model ? options.provider && options.model.startsWith(`${options.provider}/`) ? options.model : options.provider ? `${options.provider}/${options.model}` : options.model : void 0;
|
|
16129
|
+
if (qualifiedModel) {
|
|
16130
|
+
authArgs.push("--model", qualifiedModel);
|
|
16130
16131
|
} else if (options.provider) {
|
|
16131
16132
|
authArgs.push("--provider", options.provider);
|
|
16132
16133
|
}
|
|
@@ -25113,15 +25114,29 @@ var KxmRunScheduler = class _KxmRunScheduler {
|
|
|
25113
25114
|
}
|
|
25114
25115
|
};
|
|
25115
25116
|
function invokeProducer(producer, request) {
|
|
25117
|
+
const reason = (error) => {
|
|
25118
|
+
try {
|
|
25119
|
+
const raw = error instanceof Error ? error.message : error;
|
|
25120
|
+
const message = typeof raw === "string" ? raw : "";
|
|
25121
|
+
let text = message;
|
|
25122
|
+
if (request.capability) text = text.split(request.capability).join("[redacted]");
|
|
25123
|
+
text = text.replace(/kxmcap_[A-Za-z0-9_-]+/g, "[redacted]");
|
|
25124
|
+
const match = /^[a-z][a-z0-9]*(?:_[a-z0-9]+){1,3}/.exec(text);
|
|
25125
|
+
const code = match?.[0] ?? "";
|
|
25126
|
+
return code.length > 0 && code.length <= 64 ? code : "producer_error";
|
|
25127
|
+
} catch {
|
|
25128
|
+
return "producer_error";
|
|
25129
|
+
}
|
|
25130
|
+
};
|
|
25116
25131
|
let pending;
|
|
25117
25132
|
try {
|
|
25118
25133
|
pending = Promise.resolve(producer.produce(request));
|
|
25119
|
-
} catch {
|
|
25120
|
-
return Promise.resolve({ error: true });
|
|
25134
|
+
} catch (error) {
|
|
25135
|
+
return Promise.resolve({ error: true, errorCode: reason(error) });
|
|
25121
25136
|
}
|
|
25122
25137
|
return pending.then(
|
|
25123
25138
|
(result) => ({ result, error: false }),
|
|
25124
|
-
() => ({ error: true })
|
|
25139
|
+
(error) => ({ error: true, errorCode: reason(error) })
|
|
25125
25140
|
);
|
|
25126
25141
|
}
|
|
25127
25142
|
var kxmGateDispatchSeams = {};
|
|
@@ -25940,7 +25955,7 @@ async function drivePanel(context, panel, producer) {
|
|
|
25940
25955
|
if (kxmPanelDispatchSeams.failSettleMember?.(member)) {
|
|
25941
25956
|
throw runtimeError("run_events_illegal", runId, "member settlement write failed");
|
|
25942
25957
|
}
|
|
25943
|
-
settleMember(context, member, produced.result, produced.error);
|
|
25958
|
+
settleMember(context, member, produced.result, produced.error, produced.errorCode);
|
|
25944
25959
|
});
|
|
25945
25960
|
return true;
|
|
25946
25961
|
} catch (err) {
|
|
@@ -26095,7 +26110,7 @@ function producerRoutingRecord(context, dispatch, result, now) {
|
|
|
26095
26110
|
}
|
|
26096
26111
|
return parseRoutingRecordV2(record2);
|
|
26097
26112
|
}
|
|
26098
|
-
function settleMember(context, dispatch, result, produceError) {
|
|
26113
|
+
function settleMember(context, dispatch, result, produceError, produceErrorCode) {
|
|
26099
26114
|
const run = requireRun(context, dispatch.run.runId);
|
|
26100
26115
|
const state = foldStoredKxmRun(context, run);
|
|
26101
26116
|
const capability = context.eventStore.capabilityByAttempt(dispatch.attemptId);
|
|
@@ -26146,7 +26161,10 @@ function settleMember(context, dispatch, result, produceError) {
|
|
|
26146
26161
|
stepId: dispatch.stepId,
|
|
26147
26162
|
assignmentId: dispatch.assignmentId,
|
|
26148
26163
|
attemptId: dispatch.attemptId,
|
|
26149
|
-
|
|
26164
|
+
// Label the producer that actually ran: the old fallback printed "driver-simulated"
|
|
26165
|
+
// for every producer that was not literally "pi", so a live oneshot drive that
|
|
26166
|
+
// failed authentication read in the log as a simulation.
|
|
26167
|
+
harness: result?.harness ?? dispatch.producerId,
|
|
26150
26168
|
provider: result?.provider ?? "simulated",
|
|
26151
26169
|
requestedModel: result?.requestedModel ?? "simulated",
|
|
26152
26170
|
effectiveModel: result?.effectiveModel ?? result?.requestedModel ?? "simulated",
|
|
@@ -26160,7 +26178,8 @@ function settleMember(context, dispatch, result, produceError) {
|
|
|
26160
26178
|
push("assignment.result_recorded", {
|
|
26161
26179
|
assignmentId: dispatch.assignmentId,
|
|
26162
26180
|
resultClass: "producer_rejected",
|
|
26163
|
-
status: "result_recorded"
|
|
26181
|
+
status: "result_recorded",
|
|
26182
|
+
...produceErrorCode !== void 0 ? { producerError: produceErrorCode } : {}
|
|
26164
26183
|
});
|
|
26165
26184
|
push("attempt.status_changed", { attemptId: dispatch.attemptId, status: "terminal" });
|
|
26166
26185
|
push("assignment.terminal", { assignmentId: dispatch.assignmentId, outcome: "failed", status: "terminal" });
|
package/plugins/kxm/package.json
CHANGED
|
@@ -854,15 +854,41 @@ function invokeProducer(
|
|
|
854
854
|
producer: KxmProducer,
|
|
855
855
|
request: KxmProducerRequest,
|
|
856
856
|
): Promise<{ result?: KxmProducerResult; error: boolean; errorCode?: string }> {
|
|
857
|
+
// The reason a producer refused is the single most useful fact about a failed attempt,
|
|
858
|
+
// and it used to be discarded here: a live drive that could not authenticate read in the
|
|
859
|
+
// event log exactly like a simulation that ran fine. But the message is producer-
|
|
860
|
+
// controlled text and must never reach durable records as-is — a producer that throws
|
|
861
|
+
// its capability (the hygiene contract tests exactly that) would persist the secret.
|
|
862
|
+
// So: redact the attempt capability and anything capability-shaped, then keep only a
|
|
863
|
+
// leading machine-code identifier (lowercase segments joined by underscores). Anything
|
|
864
|
+
// else — prose, free text, a redacted-to-empty message — records as producer_error.
|
|
865
|
+
const reason = (error: unknown): string => {
|
|
866
|
+
// Never throw while classifying a throw: a producer can reject with anything
|
|
867
|
+
// (Object.create(null) defeats String(), an Error whose message is not a string
|
|
868
|
+
// defeats split()), and a throwing classifier would reroute a producer_rejected
|
|
869
|
+
// settle into the execution-error path — the exact invisibility this exists to fix.
|
|
870
|
+
try {
|
|
871
|
+
const raw = error instanceof Error ? error.message : error;
|
|
872
|
+
const message = typeof raw === "string" ? raw : "";
|
|
873
|
+
let text = message;
|
|
874
|
+
if (request.capability) text = text.split(request.capability).join("[redacted]");
|
|
875
|
+
text = text.replace(/kxmcap_[A-Za-z0-9_-]+/g, "[redacted]");
|
|
876
|
+
const match = /^[a-z][a-z0-9]*(?:_[a-z0-9]+){1,3}/.exec(text);
|
|
877
|
+
const code = match?.[0] ?? "";
|
|
878
|
+
return code.length > 0 && code.length <= 64 ? code : "producer_error";
|
|
879
|
+
} catch {
|
|
880
|
+
return "producer_error";
|
|
881
|
+
}
|
|
882
|
+
};
|
|
857
883
|
let pending: Promise<KxmProducerResult>;
|
|
858
884
|
try {
|
|
859
885
|
pending = Promise.resolve(producer.produce(request));
|
|
860
|
-
} catch {
|
|
861
|
-
return Promise.resolve({ error: true });
|
|
886
|
+
} catch (error) {
|
|
887
|
+
return Promise.resolve({ error: true, errorCode: reason(error) });
|
|
862
888
|
}
|
|
863
889
|
return pending.then(
|
|
864
890
|
(result) => ({ result, error: false }),
|
|
865
|
-
() => ({ error: true }),
|
|
891
|
+
(error) => ({ error: true, errorCode: reason(error) }),
|
|
866
892
|
);
|
|
867
893
|
}
|
|
868
894
|
|
|
@@ -1778,7 +1804,7 @@ function appendExecuting(context: KxmRuntimeContext, dispatch: PreparedDispatch)
|
|
|
1778
1804
|
}
|
|
1779
1805
|
|
|
1780
1806
|
type MemberWork =
|
|
1781
|
-
| { attemptId: string; invoked: true; produced: { result?: KxmProducerResult; error: boolean } }
|
|
1807
|
+
| { attemptId: string; invoked: true; produced: { result?: KxmProducerResult; error: boolean; errorCode?: string } }
|
|
1782
1808
|
| { attemptId: string; invoked: false; skipped: true }
|
|
1783
1809
|
| { attemptId: string; invoked: false; appendFailed: true; error: unknown };
|
|
1784
1810
|
|
|
@@ -1919,7 +1945,7 @@ async function drivePanel(
|
|
|
1919
1945
|
});
|
|
1920
1946
|
};
|
|
1921
1947
|
|
|
1922
|
-
const settleInvoked = (member: PreparedDispatch, produced: { result?: KxmProducerResult; error: boolean }): boolean => {
|
|
1948
|
+
const settleInvoked = (member: PreparedDispatch, produced: { result?: KxmProducerResult; error: boolean; errorCode?: string }): boolean => {
|
|
1923
1949
|
if (produced.result?.effectUncertain) {
|
|
1924
1950
|
settlementFailed = true;
|
|
1925
1951
|
stopBirths = true;
|
|
@@ -1930,7 +1956,7 @@ async function drivePanel(
|
|
|
1930
1956
|
if (kxmPanelDispatchSeams.failSettleMember?.(member)) {
|
|
1931
1957
|
throw runtimeError("run_events_illegal", runId, "member settlement write failed");
|
|
1932
1958
|
}
|
|
1933
|
-
settleMember(context, member, produced.result, produced.error);
|
|
1959
|
+
settleMember(context, member, produced.result, produced.error, produced.errorCode);
|
|
1934
1960
|
});
|
|
1935
1961
|
return true;
|
|
1936
1962
|
} catch (err) {
|
|
@@ -2092,6 +2118,7 @@ function settleMember(
|
|
|
2092
2118
|
dispatch: PreparedDispatch,
|
|
2093
2119
|
result: KxmProducerResult | undefined,
|
|
2094
2120
|
produceError: boolean,
|
|
2121
|
+
produceErrorCode?: string,
|
|
2095
2122
|
): void {
|
|
2096
2123
|
const run = requireRun(context, dispatch.run.runId);
|
|
2097
2124
|
const state = foldStoredKxmRun(context, run);
|
|
@@ -2146,7 +2173,10 @@ function settleMember(
|
|
|
2146
2173
|
stepId: dispatch.stepId,
|
|
2147
2174
|
assignmentId: dispatch.assignmentId,
|
|
2148
2175
|
attemptId: dispatch.attemptId,
|
|
2149
|
-
|
|
2176
|
+
// Label the producer that actually ran: the old fallback printed "driver-simulated"
|
|
2177
|
+
// for every producer that was not literally "pi", so a live oneshot drive that
|
|
2178
|
+
// failed authentication read in the log as a simulation.
|
|
2179
|
+
harness: result?.harness ?? dispatch.producerId,
|
|
2150
2180
|
provider: result?.provider ?? "simulated",
|
|
2151
2181
|
requestedModel: result?.requestedModel ?? "simulated",
|
|
2152
2182
|
effectiveModel: result?.effectiveModel ?? result?.requestedModel ?? "simulated",
|
|
@@ -2162,6 +2192,7 @@ function settleMember(
|
|
|
2162
2192
|
assignmentId: dispatch.assignmentId,
|
|
2163
2193
|
resultClass: "producer_rejected",
|
|
2164
2194
|
status: "result_recorded",
|
|
2195
|
+
...(produceErrorCode !== undefined ? { producerError: produceErrorCode } : {}),
|
|
2165
2196
|
});
|
|
2166
2197
|
push("attempt.status_changed", { attemptId: dispatch.attemptId, status: "terminal" });
|
|
2167
2198
|
push("assignment.terminal", { assignmentId: dispatch.assignmentId, outcome: "failed", status: "terminal" });
|
|
@@ -1118,8 +1118,17 @@ export function probeHarnessAssignment(options: HarnessAssignmentProbeOptions):
|
|
|
1118
1118
|
}
|
|
1119
1119
|
|
|
1120
1120
|
const authArgs = ["auth", "check"];
|
|
1121
|
-
|
|
1122
|
-
|
|
1121
|
+
// `pi auth check --model` requires a provider-qualified id: a bare model answers
|
|
1122
|
+
// status "invalid", which reads as not_authenticated and hides the real state. When
|
|
1123
|
+
// the caller holds provider and bare model separately (the engine's request shape),
|
|
1124
|
+
// qualify the id; a model that already carries its namespace goes through as-is.
|
|
1125
|
+
const qualifiedModel = options.model
|
|
1126
|
+
? (options.provider && options.model.startsWith(`${options.provider}/`)
|
|
1127
|
+
? options.model
|
|
1128
|
+
: options.provider ? `${options.provider}/${options.model}` : options.model)
|
|
1129
|
+
: undefined;
|
|
1130
|
+
if (qualifiedModel) {
|
|
1131
|
+
authArgs.push("--model", qualifiedModel);
|
|
1123
1132
|
} else if (options.provider) {
|
|
1124
1133
|
authArgs.push("--provider", options.provider);
|
|
1125
1134
|
}
|
|
@@ -8,7 +8,7 @@ import { AGENT_COMMANDS_MAP, enforceToolPolicy, getMcpTools, reconcileInbox } fr
|
|
|
8
8
|
import { deliverInboxNotification } from "./inbox.ts";
|
|
9
9
|
import type { HubEvent, MessageRecord } from "./protocol.ts";
|
|
10
10
|
|
|
11
|
-
const VERSION = "0.7.
|
|
11
|
+
const VERSION = "0.7.64";
|
|
12
12
|
const inbox = new Map<string, MessageRecord>();
|
|
13
13
|
const notifiedInbox = new Set<string>();
|
|
14
14
|
let meshClient: HubClient | undefined;
|
|
@@ -364,6 +364,7 @@
|
|
|
364
364
|
"runPlanHash": { "$ref": "common.schema.json#/$defs/sha256" },
|
|
365
365
|
"capabilityHash": { "$ref": "common.schema.json#/$defs/sha256" },
|
|
366
366
|
"resultClass": { "enum": ["outcome", "outcome_unknown", "producer_rejected", "cancelled"] },
|
|
367
|
+
"producerError": { "type": "string", "pattern": "^[a-z][a-z0-9]*(?:_[a-z0-9]+){1,3}$", "maxLength": 64, "description": "Machine-code reason a producer refused (produce threw), present only for resultClass producer_rejected. Capability material is redacted before extraction; anything unclassifiable records as producer_error." },
|
|
367
368
|
"status": { "$ref": "common.schema.json#/$defs/lifecycleStatus" },
|
|
368
369
|
"previousStatus": { "$ref": "common.schema.json#/$defs/lifecycleStatus" },
|
|
369
370
|
"outcome": { "$ref": "common.schema.json#/$defs/identifier" },
|