@cassiomc1/forgeloop 1.5.0 → 1.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/DOCS_INDEX.md +13 -8
- package/EXECUTION_STATE.md +20 -0
- package/LOOP_ENGINEERING.md +81 -0
- package/LOOP_SYSTEM_DESIGN.md +32 -0
- package/PROTOCOL_INTEGRATION.md +46 -0
- package/QUALITY_SCORECARD.md +2 -0
- package/README.md +31 -9
- package/THIRD_PARTY_NOTICES.md +15 -0
- package/THREAT_MODEL.md +39 -0
- package/docs/ARTIFACT_REFERENCE.md +140 -0
- package/docs/CLI_REFERENCE.md +294 -3
- package/docs/DIAGNOSTIC_MODEL.md +181 -0
- package/docs/DOCUMENTATION_GUIDE.md +22 -13
- package/docs/EXECUTION_TRACE.md +76 -0
- package/docs/MCP.md +33 -0
- package/docs/RECIPES.md +67 -0
- package/docs/TROUBLESHOOTING.md +106 -2
- package/docs/assets/diagrams/forgeloop-engineering-flow.html +13797 -0
- package/docs/assets/diagrams/forgeloop-engineering-flow.receipt.json +37 -0
- package/docs/assets/diagrams/forgeloop-engineering-flow.svg +5002 -0
- package/docs/diagrams/README.md +55 -0
- package/docs/diagrams/forgeloop-engineering-flow.workflow.json +122 -0
- package/docs/diagrams/manifest.json +42 -0
- package/docs/diagrams/reviews/forgeloop-engineering-flow.review.json +20 -0
- package/package.json +8 -6
- package/schemas/action.schema.json +100 -0
- package/schemas/approval.schema.json +51 -0
- package/schemas/capability-policy.schema.json +41 -0
- package/schemas/diagnostic-case.schema.json +85 -0
- package/schemas/execution-receipt.schema.json +16 -0
- package/schemas/hypothesis-disposition.schema.json +16 -0
- package/schemas/intervention.schema.json +27 -0
- package/schemas/policy-lock.schema.json +1 -0
- package/schemas/policy-snapshot.schema.json +2 -0
- package/schemas/trajectory-evaluation.schema.json +64 -0
- package/schemas/trajectory-scenario.schema.json +42 -0
- package/src/cli.js +94 -0
- package/src/commands/action-authorize.js +41 -0
- package/src/commands/action-propose.js +10 -0
- package/src/commands/action-reconcile.js +10 -0
- package/src/commands/action-record.js +47 -0
- package/src/commands/action-show.js +10 -0
- package/src/commands/action-verify.js +10 -0
- package/src/commands/advance.js +7 -2
- package/src/commands/approval-request.js +64 -0
- package/src/commands/approval-resolve.js +10 -0
- package/src/commands/baseline.js +3 -3
- package/src/commands/eval.js +6 -0
- package/src/commands/history.js +18 -0
- package/src/commands/init.js +2 -2
- package/src/commands/inspect.js +49 -0
- package/src/commands/metrics.js +7 -0
- package/src/commands/next.js +8 -2
- package/src/commands/policy-discover.js +2 -2
- package/src/commands/record-diagnosis.js +37 -1
- package/src/commands/record-hypothesis-disposition.js +45 -0
- package/src/commands/record-intervention.js +35 -0
- package/src/commands/reflect.js +38 -0
- package/src/commands/report.js +9 -1
- package/src/commands/run-action.js +18 -0
- package/src/commands/trace.js +34 -0
- package/src/commands/validate-protocol.js +21 -13
- package/src/core/action-authorization.js +106 -0
- package/src/core/action-constants.js +86 -0
- package/src/core/action-execution.js +105 -0
- package/src/core/action-ledger-projection.js +302 -0
- package/src/core/action-model.js +581 -0
- package/src/core/action-readiness.js +141 -0
- package/src/core/action-reconciliation-policy.js +49 -0
- package/src/core/action-reconciliation.js +66 -0
- package/src/core/action-verification.js +111 -0
- package/src/core/actions.js +462 -0
- package/src/core/approvals.js +405 -0
- package/src/core/artifact-registry.js +48 -0
- package/src/core/audit.js +25 -0
- package/src/core/bundles.js +15 -0
- package/src/core/capability-policy.js +226 -0
- package/src/core/cli-command-definitions.js +210 -1
- package/src/core/command-executors.js +171 -15
- package/src/core/command-runtime.js +12 -1
- package/src/core/completion-artifacts.js +37 -12
- package/src/core/completion-recovery-rebind.js +194 -0
- package/src/core/completion.js +70 -0
- package/src/core/continuity-reconciliation.js +24 -5
- package/src/core/diagnostic-model.js +396 -0
- package/src/core/diagnostic-projection.js +51 -0
- package/src/core/diagnostic-record.js +360 -0
- package/src/core/error-codes.js +343 -0
- package/src/core/events.js +41 -1
- package/src/core/execution-prerequisites.js +4 -1
- package/src/core/execution.js +26 -188
- package/src/core/failure-signature.js +70 -0
- package/src/core/failure-surface.js +57 -0
- package/src/core/history.js +110 -0
- package/src/core/hypothesis-projection.js +85 -0
- package/src/core/information-gain-projection.js +283 -0
- package/src/core/information-gain.js +138 -0
- package/src/core/inspect.js +105 -7
- package/src/core/integration-invocation-policy.js +47 -0
- package/src/core/integration-resources.js +51 -0
- package/src/core/next-action-model.js +35 -1
- package/src/core/next-action.js +459 -3
- package/src/core/phase.js +40 -21
- package/src/core/policy-engine.js +113 -6
- package/src/core/preflight-consistency.js +31 -5
- package/src/core/preflight.js +19 -2
- package/src/core/prepared-execution.js +227 -0
- package/src/core/progress.js +41 -4
- package/src/core/protocol-info.js +48 -0
- package/src/core/protocol.js +14 -0
- package/src/core/receipt.js +1 -0
- package/src/core/reconcile-closure.js +15 -12
- package/src/core/reflection.js +305 -0
- package/src/core/resumability.js +57 -3
- package/src/core/schema-validation.js +8 -0
- package/src/core/strategy-analysis.js +97 -0
- package/src/core/task-paths.js +28 -0
- package/src/core/task-snapshot.js +53 -0
- package/src/core/templates.js +8 -0
- package/src/core/trace.js +548 -0
- package/src/core/trajectory-evaluation.js +71 -0
- package/src/core/trajectory-metrics.js +80 -0
- package/src/core/transaction.js +8 -0
- package/src/core/work-state.js +10 -5
- package/docs/assets/forgeloop-flow.svg +0 -1
- package/docs/forgeloop-flow.mmd +0 -51
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readContract } from "./contract.js";
|
|
2
2
|
import { canonicalFingerprint, readJsonArtifact, writeJsonArtifact } from "./artifacts.js";
|
|
3
|
-
import { appendProtocolEvent, validateEventLedger
|
|
3
|
+
import { appendProtocolEvent, validateEventLedger } from "./events.js";
|
|
4
|
+
import { authorizeCompletionRecoveryOrRebind } from "./completion-recovery-rebind.js";
|
|
4
5
|
import { runCommandExecution } from "./execution.js";
|
|
5
6
|
import { createReceipt } from "./receipt.js";
|
|
6
7
|
import { currentRepositoryFingerprint } from "./repository.js";
|
|
@@ -68,7 +69,7 @@ export async function runReconcileClosure({
|
|
|
68
69
|
const eventsRel = taskArtifactPath(taskId, "events");
|
|
69
70
|
const receiptRel = taskArtifactPath(taskId, "receipt");
|
|
70
71
|
|
|
71
|
-
|
|
72
|
+
let state = await readWorkState(target, { packageRoot, taskId });
|
|
72
73
|
if (!state) {
|
|
73
74
|
throw reconcileError("E_RECONCILE_PHASE_INVALID", "Cannot reconcile without work state", [stateRel]);
|
|
74
75
|
}
|
|
@@ -80,22 +81,24 @@ export async function runReconcileClosure({
|
|
|
80
81
|
);
|
|
81
82
|
}
|
|
82
83
|
if (state.phase === "REVIEWING") {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const first = recoveryAuth.errors?.[0] ?? {};
|
|
84
|
+
const recovery = await authorizeCompletionRecoveryOrRebind({
|
|
85
|
+
target,
|
|
86
|
+
packageRoot,
|
|
87
|
+
taskId,
|
|
88
|
+
authorityContext,
|
|
89
|
+
runtimeContext,
|
|
90
|
+
});
|
|
91
|
+
if (!recovery.recoveryAuth.authorized) {
|
|
92
|
+
const first = recovery.recoveryAuth.errors?.[0] ?? {};
|
|
93
93
|
throw reconcileError(
|
|
94
94
|
first.code ?? "E_COMPLETION_RECOVERY_UNAUTHORIZED",
|
|
95
95
|
`REVIEWING reconciliation requires authorized completion recovery: ${first.message ?? "unauthorized"}`,
|
|
96
96
|
[stateRel, receiptRel],
|
|
97
97
|
);
|
|
98
98
|
}
|
|
99
|
+
if (recovery.rebound) {
|
|
100
|
+
state = recovery.state;
|
|
101
|
+
}
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
const freshness = await classifyLoadedWorkState({ target, state, contractFile: contractRel });
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { buildTaskTrace } from "./trace.js";
|
|
2
|
+
import { readEvents } from "./events.js";
|
|
3
|
+
import { findTaskById } from "./task-discovery.js";
|
|
4
|
+
import { projectHypothesisStates } from "./hypothesis-projection.js";
|
|
5
|
+
import {
|
|
6
|
+
buildInformationGainProjection,
|
|
7
|
+
evaluateStructuredDiagnosticStall,
|
|
8
|
+
} from "./information-gain-projection.js";
|
|
9
|
+
import { computeFailureSignature } from "./failure-signature.js";
|
|
10
|
+
import {
|
|
11
|
+
computeStrategyFingerprints as computeStrategyFingerprintsImpl,
|
|
12
|
+
detectOscillation as detectOscillationImpl,
|
|
13
|
+
evaluateInterventionEffectiveness as evaluateInterventionEffectivenessImpl,
|
|
14
|
+
} from "./strategy-analysis.js";
|
|
15
|
+
|
|
16
|
+
export const REFLECTION_STATUS = Object.freeze({
|
|
17
|
+
ADVANCING: "ADVANCING",
|
|
18
|
+
WATCH: "WATCH",
|
|
19
|
+
STALLED: "STALLED",
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
export function summarizeHypotheses(trace) {
|
|
24
|
+
const summary = { created: 0, supported: 0, weakened: 0, falsified: 0, superseded: 0, unresolved: 0, open: 0 };
|
|
25
|
+
|
|
26
|
+
const pseudoEvents = [
|
|
27
|
+
...trace.diagnostics.cases.map((diagnosticCase) => ({
|
|
28
|
+
seq: diagnosticCase.sequence,
|
|
29
|
+
event: "DIAGNOSTIC_CASE_RECORDED",
|
|
30
|
+
details: diagnosticCase,
|
|
31
|
+
})),
|
|
32
|
+
...trace.diagnostics.legacyDiagnoses.map((legacy) => ({
|
|
33
|
+
seq: legacy.sequence,
|
|
34
|
+
event: "DIAGNOSIS_RECORDED",
|
|
35
|
+
details: legacy,
|
|
36
|
+
})),
|
|
37
|
+
...trace.diagnostics.dispositions.map((disposition) => ({
|
|
38
|
+
seq: disposition.sequence,
|
|
39
|
+
event: "HYPOTHESIS_DISPOSITION_RECORDED",
|
|
40
|
+
details: disposition,
|
|
41
|
+
})),
|
|
42
|
+
];
|
|
43
|
+
const projection = projectHypothesisStates(pseudoEvents);
|
|
44
|
+
|
|
45
|
+
for (const hypothesis of projection.hypotheses) {
|
|
46
|
+
if (hypothesis.id === "h-legacy" && hypothesis.sourceEventSeq !== null) {
|
|
47
|
+
summary.created += 1;
|
|
48
|
+
} else if (hypothesis.id !== "h-legacy") {
|
|
49
|
+
summary.created += 1;
|
|
50
|
+
}
|
|
51
|
+
const status = hypothesis.currentStatus.toLowerCase();
|
|
52
|
+
if (summary[status] !== undefined) summary[status] += 1;
|
|
53
|
+
}
|
|
54
|
+
summary.open = projection.openHypotheses.length;
|
|
55
|
+
return summary;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function detectOscillation(strategies) {
|
|
59
|
+
return detectOscillationImpl(strategies);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function evaluateInterventionEffectiveness(trace, surfacesByCycle) {
|
|
63
|
+
return evaluateInterventionEffectivenessImpl(trace, surfacesByCycle);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function failedRequirementSurfacesFromEvents(events = [], state = null) {
|
|
67
|
+
const byCycle = new Map();
|
|
68
|
+
const record = (cycle, requirement) => {
|
|
69
|
+
if (!requirement) return;
|
|
70
|
+
if (!byCycle.has(cycle)) byCycle.set(cycle, new Set());
|
|
71
|
+
byCycle.get(cycle).add(requirement);
|
|
72
|
+
};
|
|
73
|
+
for (const event of events) {
|
|
74
|
+
if (event.event !== "VERIFICATION_RECORDED") continue;
|
|
75
|
+
const d = event.details ?? {};
|
|
76
|
+
if (d.status === "failed" || d.status === "blocked") {
|
|
77
|
+
record(d.verificationCycle ?? 1, d.requirement ?? d.id ?? d.checkId);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
for (const check of state?.checks ?? []) {
|
|
81
|
+
if (check.status !== "failed" && check.status !== "blocked") continue;
|
|
82
|
+
record(check.details?.verificationCycle ?? state?.verificationCycle ?? 1, check.requirement ?? check.id ?? check.checkId);
|
|
83
|
+
}
|
|
84
|
+
return byCycle;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function signatureSetsByCycle(trace) {
|
|
88
|
+
const byCycle = new Map();
|
|
89
|
+
for (const entry of trace.failureSignatures) {
|
|
90
|
+
for (const cycle of entry.cycles ?? []) {
|
|
91
|
+
if (!byCycle.has(cycle)) byCycle.set(cycle, new Set());
|
|
92
|
+
byCycle.get(cycle).add(entry.signature);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return byCycle;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function deriveDiagnosticContext(events = [], state = null) {
|
|
99
|
+
const cycle = state?.verificationCycle ?? null;
|
|
100
|
+
const taskEvents = events.filter((event) => !state?.taskId || event.taskId === state.taskId);
|
|
101
|
+
|
|
102
|
+
// Canonical failure-signature hashes for the active verification cycle.
|
|
103
|
+
const activeFailureSignatures = [...new Set(
|
|
104
|
+
taskEvents
|
|
105
|
+
.filter((event) => event.event === "VERIFICATION_RECORDED"
|
|
106
|
+
&& ["failed", "blocked"].includes(event.details?.status)
|
|
107
|
+
&& (cycle === null || event.details?.verificationCycle === cycle))
|
|
108
|
+
.map((event) => {
|
|
109
|
+
const d = event.details;
|
|
110
|
+
return computeFailureSignature({
|
|
111
|
+
requirement: d.requirement ?? d.id ?? d.checkId,
|
|
112
|
+
status: d.status,
|
|
113
|
+
exitCode: Number.isInteger(d.exitCode) ? d.exitCode : null,
|
|
114
|
+
failureToken: typeof d.failureToken === "string" && d.failureToken
|
|
115
|
+
? d.failureToken
|
|
116
|
+
: (typeof d.details?.failureToken === "string" ? d.details.failureToken : null),
|
|
117
|
+
});
|
|
118
|
+
}),
|
|
119
|
+
)].sort();
|
|
120
|
+
|
|
121
|
+
const activeFailedRequirements = [...new Set(
|
|
122
|
+
[
|
|
123
|
+
...taskEvents
|
|
124
|
+
.filter((event) => event.event === "VERIFICATION_RECORDED"
|
|
125
|
+
&& ["failed", "blocked"].includes(event.details?.status)
|
|
126
|
+
&& (cycle === null || event.details?.verificationCycle === cycle))
|
|
127
|
+
.map((event) => event.details?.requirement ?? event.details?.id ?? event.details?.checkId),
|
|
128
|
+
...((state?.checks ?? []))
|
|
129
|
+
.filter((check) => ["failed", "blocked"].includes(check.status)
|
|
130
|
+
&& (cycle === null || check.details?.verificationCycle === cycle))
|
|
131
|
+
.map((check) => check.requirement ?? check.id ?? check.checkId),
|
|
132
|
+
].filter(Boolean),
|
|
133
|
+
)].sort();
|
|
134
|
+
|
|
135
|
+
const projection = projectHypothesisStates(taskEvents);
|
|
136
|
+
const openHypotheses = [...projection.openHypotheses].sort();
|
|
137
|
+
|
|
138
|
+
const interventions = taskEvents.filter((event) => event.event === "INTERVENTION_RECORDED");
|
|
139
|
+
const latestIntervention = interventions.at(-1)?.details?.intervention?.id ?? null;
|
|
140
|
+
|
|
141
|
+
// doNotRepeat requires semantic repetition AND at least two completed
|
|
142
|
+
// post-intervention verification cycles AND unchanged failure surface.
|
|
143
|
+
const surfacesByCycle = failedRequirementSurfacesFromEvents(taskEvents, state);
|
|
144
|
+
const completedCycles = [...new Set(
|
|
145
|
+
taskEvents.filter((event) => event.event === "VERIFICATION_STARTED")
|
|
146
|
+
.map((event) => event.details?.verificationCycle)
|
|
147
|
+
.filter(Number.isInteger),
|
|
148
|
+
)].sort((a, b) => a - b);
|
|
149
|
+
|
|
150
|
+
const fingerprintGroups = new Map();
|
|
151
|
+
for (const event of interventions) {
|
|
152
|
+
const fingerprint = event.details?.interventionSemanticFingerprint;
|
|
153
|
+
if (!fingerprint) continue;
|
|
154
|
+
if (!fingerprintGroups.has(fingerprint)) fingerprintGroups.set(fingerprint, []);
|
|
155
|
+
fingerprintGroups.get(fingerprint).push(event);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const doNotRepeat = [];
|
|
159
|
+
for (const [fingerprint, group] of fingerprintGroups.entries()) {
|
|
160
|
+
if (group.length < 2) continue;
|
|
161
|
+
const lastInterventionCycle = Math.max(...group.map((event) => event.details?.verificationCycle ?? 1));
|
|
162
|
+
const postCycles = completedCycles.filter((completed) => completed > lastInterventionCycle);
|
|
163
|
+
if (postCycles.length < 2) continue;
|
|
164
|
+
const firstSurface = [...(surfacesByCycle.get(lastInterventionCycle) ?? [])].sort();
|
|
165
|
+
const latestSurface = [...(surfacesByCycle.get(postCycles.at(-1)) ?? [])].sort();
|
|
166
|
+
if (JSON.stringify(firstSurface) === JSON.stringify(latestSurface)) {
|
|
167
|
+
doNotRepeat.push(fingerprint);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
doNotRepeat.sort();
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
activeFailureSignatures,
|
|
174
|
+
activeFailedRequirements,
|
|
175
|
+
openHypotheses,
|
|
176
|
+
latestIntervention,
|
|
177
|
+
nextExperiment: null,
|
|
178
|
+
doNotRepeat,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export async function buildTaskReflection({ target, packageRoot, taskId = null } = {}) {
|
|
183
|
+
const trace = await buildTaskTrace({ target, packageRoot, taskId });
|
|
184
|
+
// Modern tasks own a scoped ledger; legacy singleton callers still pass a
|
|
185
|
+
// taskId that must be used only as a filter over the canonical ledger.
|
|
186
|
+
const task = taskId ? await findTaskById(target, taskId, packageRoot) : null;
|
|
187
|
+
const rawEvents = await readEvents(target, packageRoot, task ? { taskId } : {});
|
|
188
|
+
|
|
189
|
+
// Authoritative surfaces come from the canonical trace projection.
|
|
190
|
+
const surfaceEntries = {};
|
|
191
|
+
for (const entry of trace.failureSurfaces) {
|
|
192
|
+
surfaceEntries[entry.verificationCycle] = { surface: entry.surface, signatures: [] };
|
|
193
|
+
}
|
|
194
|
+
const signatureSets = signatureSetsByCycle(trace);
|
|
195
|
+
for (const [cycle, signatures] of signatureSets.entries()) {
|
|
196
|
+
if (!surfaceEntries[cycle]) surfaceEntries[cycle] = { surface: [], signatures: [] };
|
|
197
|
+
surfaceEntries[cycle].signatures = [...signatures].sort();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const cycles = [...new Set([
|
|
201
|
+
...trace.failureSurfaces.map((entry) => entry.verificationCycle),
|
|
202
|
+
...trace.diagnostics.cases.map((diagnosticCase) => diagnosticCase.verificationCycle),
|
|
203
|
+
])].sort((a, b) => a - b);
|
|
204
|
+
|
|
205
|
+
const strategies = computeStrategyFingerprintsImpl(trace);
|
|
206
|
+
const oscillation = detectOscillation(strategies);
|
|
207
|
+
|
|
208
|
+
const signals = [];
|
|
209
|
+
let status = REFLECTION_STATUS.ADVANCING;
|
|
210
|
+
|
|
211
|
+
const evaluatedInterventions = evaluateInterventionEffectiveness(trace, surfaceEntries);
|
|
212
|
+
const repeatedNonInformative = evaluatedInterventions
|
|
213
|
+
.filter((intervention) => intervention.effectiveness === "NON_INFORMATIVE");
|
|
214
|
+
if (oscillation.detected) {
|
|
215
|
+
signals.push("OSCILLATING_STRATEGY");
|
|
216
|
+
status = REFLECTION_STATUS.WATCH;
|
|
217
|
+
}
|
|
218
|
+
if (repeatedNonInformative.length >= 2) {
|
|
219
|
+
signals.push("REPEATED_INTERVENTION");
|
|
220
|
+
status = REFLECTION_STATUS.WATCH;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const lastTwoSameStrategy = strategies.length >= 2
|
|
224
|
+
&& strategies.at(-1).strategyFingerprint === strategies.at(-2).strategyFingerprint
|
|
225
|
+
&& JSON.stringify(surfaceEntries[strategies.at(-1)?.verificationCycle]?.signatures ?? [])
|
|
226
|
+
=== JSON.stringify(surfaceEntries[strategies.at(-2)?.verificationCycle]?.signatures ?? []);
|
|
227
|
+
if (lastTwoSameStrategy && !signals.includes("OSCILLATING_STRATEGY")) {
|
|
228
|
+
status = status === REFLECTION_STATUS.ADVANCING ? REFLECTION_STATUS.WATCH : status;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Information Gain v2 truth comes fully from the authoritative cycle
|
|
232
|
+
// analysis projection. Consumers must not redefine gain semantics.
|
|
233
|
+
const gainProjection = buildInformationGainProjection(rawEvents, taskId ?? null);
|
|
234
|
+
const cyclesWithoutEffectiveGain = gainProjection
|
|
235
|
+
.filter((entry) => !entry.effectiveGain)
|
|
236
|
+
.map((entry) => entry.verificationCycle);
|
|
237
|
+
|
|
238
|
+
// One canonical structured-stall truth shared with phase and progress.
|
|
239
|
+
const stallAnalysis = evaluateStructuredDiagnosticStall(gainProjection);
|
|
240
|
+
const latestNoGain = Boolean(stallAnalysis.stalled);
|
|
241
|
+
let consecutiveNoGainCycles = 0;
|
|
242
|
+
for (let i = gainProjection.length - 1; i >= 0 && gainProjection[i].effectiveGain === false; i--) {
|
|
243
|
+
consecutiveNoGainCycles += 1;
|
|
244
|
+
}
|
|
245
|
+
const previousEntry = gainProjection.length >= 2 ? gainProjection.at(-2) : null;
|
|
246
|
+
const currentEntry = gainProjection.at(-1) ?? null;
|
|
247
|
+
if (latestNoGain) {
|
|
248
|
+
status = REFLECTION_STATUS.STALLED;
|
|
249
|
+
if (!signals.includes("NO_EFFECTIVE_INFORMATION_GAIN")) signals.push("NO_EFFECTIVE_INFORMATION_GAIN");
|
|
250
|
+
}
|
|
251
|
+
if ((trace.actions?.ambiguous ?? 0) > 0) {
|
|
252
|
+
signals.push("EXTERNAL_ACTION_RECONCILIATION_REQUIRED");
|
|
253
|
+
status = status === REFLECTION_STATUS.ADVANCING ? REFLECTION_STATUS.WATCH : status;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const recommendedProtocolAction = (trace.actions?.ambiguous ?? 0) > 0
|
|
257
|
+
? "RECONCILE_EXTERNAL_ACTION"
|
|
258
|
+
: oscillation.detected
|
|
259
|
+
? "INTRODUCE_NEW_OBSERVATION"
|
|
260
|
+
: (status === REFLECTION_STATUS.STALLED ? "REQUIRE_NEW_DIAGNOSTIC_INFORMATION" : "CONTINUE");
|
|
261
|
+
|
|
262
|
+
return {
|
|
263
|
+
schemaVersion: 1,
|
|
264
|
+
command: "reflect",
|
|
265
|
+
taskId: trace.task.id,
|
|
266
|
+
taskPhase: trace.task.phase,
|
|
267
|
+
integrityValid: trace.integrity.valid,
|
|
268
|
+
snapshotConsistent: trace.snapshot.consistent,
|
|
269
|
+
status,
|
|
270
|
+
verificationCycles: cycles.length,
|
|
271
|
+
failureSurfaces: trace.failureSurfaces,
|
|
272
|
+
hypotheses: summarizeHypotheses(trace),
|
|
273
|
+
interventions: (() => {
|
|
274
|
+
const evaluated = evaluatedInterventions;
|
|
275
|
+
return {
|
|
276
|
+
count: evaluated.length,
|
|
277
|
+
informative: evaluated.filter((intervention) => ["INFORMATIVE", "IMPROVED"].includes(intervention.effectiveness)).length,
|
|
278
|
+
nonInformative: evaluated.filter((intervention) => intervention.effectiveness === "NON_INFORMATIVE").length,
|
|
279
|
+
details: evaluated,
|
|
280
|
+
};
|
|
281
|
+
})(),
|
|
282
|
+
informationGain: {
|
|
283
|
+
cyclesWithCases: trace.diagnostics.cases.map((diagnosticCase) => diagnosticCase.verificationCycle),
|
|
284
|
+
cyclesWithoutEffectiveGain,
|
|
285
|
+
cycles: gainProjection.map(({ dimensions, ...rest }) => ({ ...rest, dimensions })),
|
|
286
|
+
},
|
|
287
|
+
strategies,
|
|
288
|
+
oscillation,
|
|
289
|
+
signals,
|
|
290
|
+
stallAnalysis: {
|
|
291
|
+
latestNoGain,
|
|
292
|
+
consecutiveNoGainCycles,
|
|
293
|
+
sameStrategyAsPrevious: Boolean(previousEntry && currentEntry
|
|
294
|
+
&& previousEntry.evidence.strategyFingerprint === currentEntry.evidence.strategyFingerprint),
|
|
295
|
+
sameFailureSurfaceAsPrevious: Boolean(previousEntry && currentEntry
|
|
296
|
+
&& JSON.stringify(previousEntry.evidence.failureSurface) === JSON.stringify(currentEntry.evidence.failureSurface)),
|
|
297
|
+
sameFailureSignaturesAsPrevious: Boolean(previousEntry && currentEntry
|
|
298
|
+
&& JSON.stringify(previousEntry.evidence.failureSignatures) === JSON.stringify(currentEntry.evidence.failureSignatures)),
|
|
299
|
+
},
|
|
300
|
+
recommendedProtocolAction,
|
|
301
|
+
actions: trace.actions,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export { computeStrategyFingerprintsImpl as computeStrategyFingerprints };
|
package/src/core/resumability.js
CHANGED
|
@@ -1,22 +1,76 @@
|
|
|
1
1
|
import { currentRepositoryFingerprint } from "./repository.js";
|
|
2
|
+
import { validateEventLedger } from "./events.js";
|
|
2
3
|
import { createWorkState, initializeWorkState, readWorkState, mutateWorkState } from "./work-state.js";
|
|
3
4
|
|
|
4
5
|
const DEFAULT_PENDING_STEPS = ["planning", "implementation", "verification"];
|
|
5
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Resume phase derived from the highest lifecycle milestone already recorded in
|
|
9
|
+
* a validated ledger. Recreating a checkpoint at ROUTED for a task whose ledger
|
|
10
|
+
* already passed EXECUTION_STARTED would make every subsequent advance append a
|
|
11
|
+
* duplicate non-repeatable milestone and invalidate the ledger, so restoration
|
|
12
|
+
* must resume at the phase the recorded chronology supports.
|
|
13
|
+
*/
|
|
14
|
+
const RESUME_PHASE_BY_MILESTONE = Object.freeze({
|
|
15
|
+
PLAN_RECORDED: "PLANNED",
|
|
16
|
+
EXECUTION_STARTED: "EXECUTING",
|
|
17
|
+
VERIFICATION_STARTED: "VERIFYING",
|
|
18
|
+
VERIFICATION_RECORDED: "VERIFYING",
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
async function deriveResumePhaseFromLedger(target, packageRoot, taskId) {
|
|
22
|
+
let ledger;
|
|
23
|
+
try {
|
|
24
|
+
ledger = await validateEventLedger(target, packageRoot, { taskId });
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
if (!ledger?.valid) return null;
|
|
29
|
+
const scoped = (ledger.events ?? []).filter((event) => event.taskId === taskId);
|
|
30
|
+
if (scoped.some((event) => event.event === "COMPLETION_VALIDATED")) return null;
|
|
31
|
+
const positions = RESUME_PHASE_BY_MILESTONE;
|
|
32
|
+
let derived = null;
|
|
33
|
+
for (const event of scoped) {
|
|
34
|
+
const phase = positions[event.event];
|
|
35
|
+
if (!phase) continue;
|
|
36
|
+
if (!derived) {
|
|
37
|
+
derived = phase;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (phase === "VERIFYING") derived = "VERIFYING";
|
|
41
|
+
}
|
|
42
|
+
return derived;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function resumeSteps(phase) {
|
|
46
|
+
if (phase === "EXECUTING" || phase === "VERIFYING") {
|
|
47
|
+
return {
|
|
48
|
+
completedSteps: ["contract", "route", "planning", "implementation"],
|
|
49
|
+
pendingSteps: ["verification"],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
completedSteps: ["contract", "route"],
|
|
54
|
+
pendingSteps: [...DEFAULT_PENDING_STEPS],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
6
58
|
export async function ensureResumableState({ target, packageRoot, contract, route, taskId, statePath }) {
|
|
7
59
|
if (!contract || !route) return null;
|
|
8
60
|
const existing = await readWorkState(target, { packageRoot, taskId, statePath });
|
|
9
61
|
if (existing) return existing;
|
|
10
62
|
|
|
63
|
+
const resumedPhase = await deriveResumePhaseFromLedger(target, packageRoot, taskId) ?? "ROUTED";
|
|
64
|
+
const steps = resumeSteps(resumedPhase);
|
|
11
65
|
const state = createWorkState({
|
|
12
66
|
taskId: contract.value.taskId,
|
|
13
67
|
contractFingerprint: contract.fingerprint,
|
|
14
68
|
routeFingerprint: route.fingerprint,
|
|
15
69
|
repositoryFingerprint: await currentRepositoryFingerprint(target),
|
|
16
|
-
phase:
|
|
70
|
+
phase: resumedPhase,
|
|
17
71
|
selectedGuides: route.value.guides,
|
|
18
|
-
completedSteps:
|
|
19
|
-
pendingSteps:
|
|
72
|
+
completedSteps: steps.completedSteps,
|
|
73
|
+
pendingSteps: steps.pendingSteps,
|
|
20
74
|
checks: [],
|
|
21
75
|
failures: [],
|
|
22
76
|
blockers: [],
|
|
@@ -34,6 +34,14 @@ export const SHIPPED_SCHEMA_NAMES = Object.freeze([
|
|
|
34
34
|
"authority",
|
|
35
35
|
"task-descriptor",
|
|
36
36
|
"task-recovery",
|
|
37
|
+
"diagnostic-case",
|
|
38
|
+
"intervention",
|
|
39
|
+
"hypothesis-disposition",
|
|
40
|
+
"action",
|
|
41
|
+
"approval",
|
|
42
|
+
"capability-policy",
|
|
43
|
+
"trajectory-evaluation",
|
|
44
|
+
"trajectory-scenario",
|
|
37
45
|
]);
|
|
38
46
|
|
|
39
47
|
export class SchemaValidationError extends Error {
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { canonicalFingerprint } from "./artifacts.js";
|
|
2
|
+
import { compareFailureSurface } from "./failure-surface.js";
|
|
3
|
+
|
|
4
|
+
export function computeStrategyFingerprints(trace) {
|
|
5
|
+
const byCycle = new Map();
|
|
6
|
+
const add = (cycle, component, fingerprint) => {
|
|
7
|
+
if (!byCycle.has(cycle)) byCycle.set(cycle, { hypotheses: new Set(), contributors: new Set(), interventions: new Set() });
|
|
8
|
+
byCycle.get(cycle)[component].add(fingerprint);
|
|
9
|
+
};
|
|
10
|
+
for (const diagnosticCase of trace.diagnostics.cases) {
|
|
11
|
+
for (const hypothesis of diagnosticCase.hypotheses ?? []) {
|
|
12
|
+
add(diagnosticCase.verificationCycle, "hypotheses", `${hypothesis.statement}`.trim().toLowerCase());
|
|
13
|
+
}
|
|
14
|
+
for (const contributor of diagnosticCase.contributors ?? []) {
|
|
15
|
+
add(diagnosticCase.verificationCycle, "contributors", `${contributor.statement}`.trim().toLowerCase());
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
for (const legacy of trace.diagnostics.legacyDiagnoses) {
|
|
19
|
+
add(legacy.verificationCycle, "hypotheses", `${legacy.hypothesis}`.trim().toLowerCase());
|
|
20
|
+
}
|
|
21
|
+
for (const intervention of trace.diagnostics.interventions) {
|
|
22
|
+
add(intervention.verificationCycle, "interventions", intervention.interventionSemanticFingerprint ?? `${intervention.intervention?.statement ?? ""}`.trim().toLowerCase());
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return [...byCycle.entries()]
|
|
26
|
+
.sort(([a], [b]) => a - b)
|
|
27
|
+
.map(([cycle, components]) => ({
|
|
28
|
+
verificationCycle: cycle,
|
|
29
|
+
strategyFingerprint: JSON.stringify([
|
|
30
|
+
[...components.hypotheses].sort(),
|
|
31
|
+
[...components.contributors].sort(),
|
|
32
|
+
[...components.interventions].sort(),
|
|
33
|
+
]),
|
|
34
|
+
components: {
|
|
35
|
+
hypotheses: [...components.hypotheses].sort(),
|
|
36
|
+
contributors: [...components.contributors].sort(),
|
|
37
|
+
interventions: [...components.interventions].sort(),
|
|
38
|
+
},
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function detectOscillation(strategies) {
|
|
43
|
+
const fingerprints = strategies.map((strategy) => strategy.strategyFingerprint);
|
|
44
|
+
const patterns = [];
|
|
45
|
+
for (let i = 2; i < fingerprints.length; i++) {
|
|
46
|
+
if (fingerprints[i] === fingerprints[i - 2] && fingerprints[i] !== fingerprints[i - 1]) {
|
|
47
|
+
patterns.push({ kind: "A_B_A", cycles: [strategies[i - 2].verificationCycle, strategies[i - 1].verificationCycle, strategies[i].verificationCycle] });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
for (let i = 3; i < fingerprints.length; i++) {
|
|
51
|
+
if (fingerprints[i] === fingerprints[i - 2]
|
|
52
|
+
&& fingerprints[i - 1] === fingerprints[i - 3]
|
|
53
|
+
&& fingerprints[i] !== fingerprints[i - 1]) {
|
|
54
|
+
patterns.push({ kind: "A_B_A_B", cycles: [strategies[i - 3].verificationCycle, strategies[i - 2].verificationCycle, strategies[i - 1].verificationCycle, strategies[i].verificationCycle] });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const detected = patterns.length > 0;
|
|
58
|
+
return { detected, patterns };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function evaluateInterventionEffectiveness(trace, surfacesByCycle) {
|
|
62
|
+
const interventions = [];
|
|
63
|
+
const list = trace.diagnostics.interventions;
|
|
64
|
+
for (const entry of list) {
|
|
65
|
+
const cycle = entry.verificationCycle;
|
|
66
|
+
const laterVerificationCycles = Object.keys(surfacesByCycle).map(Number).filter((value) => value > cycle);
|
|
67
|
+
const nextCycle = laterVerificationCycles.length > 0 ? Math.min(...laterVerificationCycles) : null;
|
|
68
|
+
|
|
69
|
+
let effectiveness = "PENDING";
|
|
70
|
+
if (nextCycle !== null) {
|
|
71
|
+
const previousSurface = surfacesByCycle[cycle]?.surface ?? [];
|
|
72
|
+
const currentSurface = surfacesByCycle[nextCycle]?.surface ?? [];
|
|
73
|
+
const comparison = compareFailureSurface(previousSurface, currentSurface);
|
|
74
|
+
const signatureChanged = JSON.stringify(surfacesByCycle[cycle]?.signatures ?? []) !== JSON.stringify(surfacesByCycle[nextCycle]?.signatures ?? []);
|
|
75
|
+
if (comparison.direction === "REDUCED") effectiveness = "IMPROVED";
|
|
76
|
+
else if (comparison.direction === "EXPANDED") effectiveness = "REGRESSED";
|
|
77
|
+
else if (signatureChanged || comparison.changed) effectiveness = "INFORMATIVE";
|
|
78
|
+
else effectiveness = "NON_INFORMATIVE";
|
|
79
|
+
}
|
|
80
|
+
interventions.push({
|
|
81
|
+
id: entry.intervention?.id ?? null,
|
|
82
|
+
sequence: entry.sequence,
|
|
83
|
+
verificationCycle: cycle,
|
|
84
|
+
kind: entry.intervention?.kind ?? null,
|
|
85
|
+
reversible: entry.intervention?.reversible ?? null,
|
|
86
|
+
semanticFingerprint: entry.interventionSemanticFingerprint ?? null,
|
|
87
|
+
effectiveness,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return interventions;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
export function interventionSemanticFingerprintOf(entry) {
|
|
95
|
+
return entry?.interventionSemanticFingerprint
|
|
96
|
+
?? (entry?.intervention ? canonicalFingerprint(entry.intervention) : null);
|
|
97
|
+
}
|
package/src/core/task-paths.js
CHANGED
|
@@ -15,6 +15,9 @@ export const TASK_ARTIFACT_FILES = Object.freeze({
|
|
|
15
15
|
events: "events.ndjson",
|
|
16
16
|
gates: "gates",
|
|
17
17
|
executions: "executions",
|
|
18
|
+
actions: "actions",
|
|
19
|
+
approvals: "approvals",
|
|
20
|
+
evaluations: "evaluations",
|
|
18
21
|
policySnapshot: "policy-snapshot.json",
|
|
19
22
|
recovery: "recovery.json",
|
|
20
23
|
});
|
|
@@ -32,6 +35,7 @@ export const PROJECT_ARTIFACT_PATHS = Object.freeze({
|
|
|
32
35
|
policyBaseline: ".forgeloop/policy/baseline.json",
|
|
33
36
|
policyLock: ".forgeloop/policy/policy.lock",
|
|
34
37
|
policyDiscovery: ".forgeloop/policy/discovery.json",
|
|
38
|
+
capabilityPolicy: ".forgeloop/policy/capabilities.json",
|
|
35
39
|
});
|
|
36
40
|
|
|
37
41
|
export const LEGACY_TASK_ARTIFACT_PATHS = Object.freeze({
|
|
@@ -74,6 +78,27 @@ export function taskExecutionPath(taskId, executionId) {
|
|
|
74
78
|
return `${taskDirectory(taskId)}/${TASK_ARTIFACT_FILES.executions}/${executionId}.json`;
|
|
75
79
|
}
|
|
76
80
|
|
|
81
|
+
export function taskActionPath(taskId, actionId) {
|
|
82
|
+
if (typeof actionId !== "string" || !/^action-[A-Za-z0-9_-]+$/.test(actionId)) {
|
|
83
|
+
throw new Error(`Invalid action ID: ${actionId}`);
|
|
84
|
+
}
|
|
85
|
+
return `${taskDirectory(taskId)}/${TASK_ARTIFACT_FILES.actions}/${actionId}.json`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function taskApprovalPath(taskId, approvalId) {
|
|
89
|
+
if (typeof approvalId !== "string" || !/^approval-[A-Za-z0-9_-]+$/.test(approvalId)) {
|
|
90
|
+
throw new Error(`Invalid approval ID: ${approvalId}`);
|
|
91
|
+
}
|
|
92
|
+
return `${taskDirectory(taskId)}/${TASK_ARTIFACT_FILES.approvals}/${approvalId}.json`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function taskEvaluationPath(taskId, evaluationId) {
|
|
96
|
+
if (typeof evaluationId !== "string" || !/^eval-[A-Za-z0-9_-]+$/.test(evaluationId)) {
|
|
97
|
+
throw new Error(`Invalid evaluation ID: ${evaluationId}`);
|
|
98
|
+
}
|
|
99
|
+
return `${taskDirectory(taskId)}/${TASK_ARTIFACT_FILES.evaluations}/${evaluationId}.json`;
|
|
100
|
+
}
|
|
101
|
+
|
|
77
102
|
export function taskLockPath(taskId) {
|
|
78
103
|
assertTaskId(taskId);
|
|
79
104
|
return `${TASK_LOCK_ROOT}/${taskStorageKey(taskId)}.lock`;
|
|
@@ -101,6 +126,9 @@ export function buildTaskArtifactPaths(taskId) {
|
|
|
101
126
|
events: `${dir}/${TASK_ARTIFACT_FILES.events}`,
|
|
102
127
|
gates: `${dir}/${TASK_ARTIFACT_FILES.gates}`,
|
|
103
128
|
executions: `${dir}/${TASK_ARTIFACT_FILES.executions}`,
|
|
129
|
+
actions: `${dir}/${TASK_ARTIFACT_FILES.actions}`,
|
|
130
|
+
approvals: `${dir}/${TASK_ARTIFACT_FILES.approvals}`,
|
|
131
|
+
evaluations: `${dir}/${TASK_ARTIFACT_FILES.evaluations}`,
|
|
104
132
|
lock: taskLockPath(taskId),
|
|
105
133
|
policySnapshot: `${dir}/${TASK_ARTIFACT_FILES.policySnapshot}`,
|
|
106
134
|
recovery: `${dir}/${TASK_ARTIFACT_FILES.recovery}`,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { readEvents, validateEventLedger } from "./events.js";
|
|
2
|
+
import { readWorkState } from "./work-state.js";
|
|
3
|
+
import { canonicalFingerprint } from "./artifacts.js";
|
|
4
|
+
|
|
5
|
+
function ledgerTail(events) {
|
|
6
|
+
const last = events.at(-1) ?? null;
|
|
7
|
+
return {
|
|
8
|
+
sequence: last?.seq ?? 0,
|
|
9
|
+
hash: last?.hash ?? null,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function buildTaskSnapshot({
|
|
14
|
+
target,
|
|
15
|
+
packageRoot,
|
|
16
|
+
taskId = null,
|
|
17
|
+
eventsPath = null,
|
|
18
|
+
stateFile = null,
|
|
19
|
+
} = {}) {
|
|
20
|
+
const options = { packageRoot, taskId, ...(eventsPath ? { eventsPath } : {}) };
|
|
21
|
+
const state = await readWorkState(target, { ...options, ...(stateFile ? { statePath: stateFile } : {}) });
|
|
22
|
+
const events = await readEvents(target, packageRoot, options);
|
|
23
|
+
const before = {
|
|
24
|
+
stateRevision: state?.revision ?? null,
|
|
25
|
+
...ledgerTail(events),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const validation = await validateEventLedger(target, packageRoot, options);
|
|
29
|
+
|
|
30
|
+
const rereadState = await readWorkState(target, { ...options, ...(stateFile ? { statePath: stateFile } : {}) });
|
|
31
|
+
const rereadEvents = await readEvents(target, packageRoot, options);
|
|
32
|
+
const after = {
|
|
33
|
+
stateRevision: rereadState?.revision ?? null,
|
|
34
|
+
...ledgerTail(rereadEvents),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const consistent = JSON.stringify(before) === JSON.stringify(after);
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
consistent,
|
|
41
|
+
taskId: taskId ?? state?.taskId ?? rereadState?.taskId ?? null,
|
|
42
|
+
anchors: before,
|
|
43
|
+
capturedAt: new Date().toISOString(),
|
|
44
|
+
integrity: {
|
|
45
|
+
valid: validation.valid,
|
|
46
|
+
errors: validation.errors,
|
|
47
|
+
eventCount: validation.events.length,
|
|
48
|
+
fingerprint: canonicalFingerprint(validation.events.map(({ seq, event, at }) => ({ seq, event, at }))),
|
|
49
|
+
},
|
|
50
|
+
state: rereadState,
|
|
51
|
+
events: validation.events,
|
|
52
|
+
};
|
|
53
|
+
}
|
package/src/core/templates.js
CHANGED
|
@@ -67,6 +67,14 @@ export const TEMPLATE_PATHS = [
|
|
|
67
67
|
"schemas/authority.schema.json",
|
|
68
68
|
"schemas/task-descriptor.schema.json",
|
|
69
69
|
"schemas/task-recovery.schema.json",
|
|
70
|
+
"schemas/diagnostic-case.schema.json",
|
|
71
|
+
"schemas/intervention.schema.json",
|
|
72
|
+
"schemas/hypothesis-disposition.schema.json",
|
|
73
|
+
"schemas/action.schema.json",
|
|
74
|
+
"schemas/approval.schema.json",
|
|
75
|
+
"schemas/capability-policy.schema.json",
|
|
76
|
+
"schemas/trajectory-evaluation.schema.json",
|
|
77
|
+
"schemas/trajectory-scenario.schema.json",
|
|
70
78
|
];
|
|
71
79
|
|
|
72
80
|
export function getPackageRoot() {
|