create-agdf 0.14.2 → 0.14.3
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/README.md +5 -1
- package/generated/.opencode/contracts/control-scaffold.md +17 -2
- package/generated/.opencode/skills/agdf-delivery-path-search/SKILL.md +16 -4
- package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/agdf/meta/contracts/control-scaffold.md +17 -2
- package/generated/plugins/agdf/meta/copilot-payload-baseline.json +2 -2
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/delivery-path-search-command.js +51 -19
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/contracts.js +37 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/persistence.js +14 -2
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/search-engine.js +126 -36
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/state-adapter.js +40 -92
- package/generated/plugins/agdf/runtime/create-agdf/package.json +1 -1
- package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
- package/generated/plugins/agdf/skills/delivery-path-search/SKILL.md +16 -4
- package/generated/plugins/agdf/submission/openai/availability.md +1 -1
- package/generated/plugins/agdf/submission/openai/capability-matrix.json +1 -1
- package/generated/plugins/agdf/submission/openai/release-notes.md +7 -1
- package/generated/plugins/agdf/submission/openai/reviewer-cases.json +1 -1
- package/generated/plugins/copilot/agdf/.agdf-payload-inventory.json +27 -27
- package/generated/plugins/copilot/agdf/copilot-skills/agdf-delivery-path-search/SKILL.md +16 -4
- package/generated/plugins/copilot/agdf/copilot-skills/contracts/control-scaffold.md +17 -2
- package/generated/plugins/copilot/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/copilot/agdf/plugin.json +1 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/delivery-path-search-command.js +51 -19
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/contracts.js +37 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/persistence.js +14 -2
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/search-engine.js +126 -36
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/state-adapter.js +40 -92
- package/generated/plugins/copilot/agdf/runtime/create-agdf/package.json +1 -1
- package/generated/plugins/copilot/agdf/runtime/runtime-manifest.json +2 -2
- package/generated/submissions/openai/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/submissions/openai/agdf/meta/contracts/control-scaffold.md +17 -2
- package/generated/submissions/openai/agdf/meta/copilot-payload-baseline.json +2 -2
- package/generated/submissions/openai/agdf/skills/delivery-path-search/SKILL.md +16 -4
- package/generated/submissions/openai/agdf/submission/openai/availability.md +1 -1
- package/generated/submissions/openai/agdf/submission/openai/capability-matrix.json +1 -1
- package/generated/submissions/openai/agdf/submission/openai/inventory.json +12 -12
- package/generated/submissions/openai/agdf/submission/openai/listing.json +1 -1
- package/generated/submissions/openai/agdf/submission/openai/readiness.json +2 -2
- package/generated/submissions/openai/agdf/submission/openai/readiness.md +2 -2
- package/generated/submissions/openai/agdf/submission/openai/release-notes.md +7 -1
- package/generated/submissions/openai/agdf/submission/openai/reviewer-cases.json +1 -1
- package/lib/cli/delivery-path-search-command.js +51 -19
- package/lib/delivery-path-search/contracts.js +37 -0
- package/lib/delivery-path-search/persistence.js +14 -2
- package/lib/delivery-path-search/search-engine.js +126 -36
- package/lib/delivery-path-search/state-adapter.js +40 -92
- package/package.json +1 -1
package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/delivery-path-search-command.js
CHANGED
|
@@ -12,21 +12,25 @@ import { enforcementForSurface } from '../delivery-path-search/surfaces/capabili
|
|
|
12
12
|
import { persistSearchResult } from '../delivery-path-search/persistence.js';
|
|
13
13
|
|
|
14
14
|
function unavailableOpenCodeResult({ options, preflight, input = null, error = null }) {
|
|
15
|
+
const surface = options.surface ?? "opencode";
|
|
15
16
|
const mutation = error?.code === "OPENCODE_EVALUATOR_MUTATION_DETECTED";
|
|
16
|
-
const attempted = Boolean(input);
|
|
17
|
+
const attempted = Boolean(input && error);
|
|
17
18
|
const nextAction = mutation
|
|
18
19
|
? "Investigate and revert the detected repository mutation before any evaluator fallback or retry."
|
|
19
20
|
: "Repair the reported OpenCode capability and retry, or use the existing instruction-only Delivery Path Search workflow.";
|
|
20
21
|
return {
|
|
21
22
|
contract_version: "1",
|
|
22
|
-
surface
|
|
23
|
+
surface,
|
|
23
24
|
scope_key: input?.scope_key ?? options.runId ?? null,
|
|
25
|
+
scope_revision: input?.scope_revision ?? "unversioned",
|
|
26
|
+
objective: input?.objective ?? "Delivery Path Search evaluator capability",
|
|
24
27
|
current_gate: input?.current_gate ?? null,
|
|
28
|
+
outcome_phase: "evaluation",
|
|
25
29
|
status: mutation ? "evaluator_error" : "evaluator_unavailable",
|
|
26
30
|
recommendation: null,
|
|
27
|
-
enforcement: enforcementForSurface(
|
|
31
|
+
enforcement: enforcementForSurface(surface),
|
|
28
32
|
evaluator: {
|
|
29
|
-
name:
|
|
33
|
+
name: surface,
|
|
30
34
|
preflight: preflight?.code ?? "not_run",
|
|
31
35
|
failure_code: error?.code ?? preflight?.code,
|
|
32
36
|
detail: error?.message ?? preflight?.detail,
|
|
@@ -38,6 +42,16 @@ function unavailableOpenCodeResult({ options, preflight, input = null, error = n
|
|
|
38
42
|
failure_code: error?.code ?? preflight?.code,
|
|
39
43
|
evidence: preflight?.evidence ?? [],
|
|
40
44
|
},
|
|
45
|
+
provenance: {
|
|
46
|
+
baseline_candidates: Math.min(input?.allowed_actions?.length ?? 0, input?.budgets?.max_candidates ?? 0),
|
|
47
|
+
generated_candidates: 0,
|
|
48
|
+
legal_candidates: attempted ? 1 : 0,
|
|
49
|
+
rejected_candidates: 0,
|
|
50
|
+
evaluation_attempts: attempted ? 1 : 0,
|
|
51
|
+
valid_evaluations: 0,
|
|
52
|
+
invalid_evaluations: attempted ? 1 : 0,
|
|
53
|
+
},
|
|
54
|
+
failure_code: error?.code ?? preflight?.code,
|
|
41
55
|
stopping_reason: mutation ? "opencode_mutation_detected" : attempted ? "opencode_evaluator_failed" : "opencode_preflight_failed",
|
|
42
56
|
next_action: nextAction,
|
|
43
57
|
next_gate_action: nextAction,
|
|
@@ -46,11 +60,26 @@ function unavailableOpenCodeResult({ options, preflight, input = null, error = n
|
|
|
46
60
|
|
|
47
61
|
export async function executeDeliveryPathSearch(options, io = console, dependencies = {}) {
|
|
48
62
|
const fixture = options.fixture ? JSON.parse(readFileSync(options.fixture, "utf8")) : null;
|
|
63
|
+
const fixtureGeneration = fixture?.generator_response;
|
|
64
|
+
const generationEnabled = Boolean(fixtureGeneration || options.generateCandidates);
|
|
65
|
+
const initialEnforcement = fixture?.input?.enforcement ?? enforcementForSurface(options.surface);
|
|
66
|
+
const initialInput = fixture?.input ?? (dependencies.searchInputFromControl ?? searchInputFromControl)(options.dir, {
|
|
67
|
+
scopeKey: options.runId,
|
|
68
|
+
enforcement: initialEnforcement,
|
|
69
|
+
generation: generationEnabled ? {
|
|
70
|
+
enabled: true,
|
|
71
|
+
maxProposals: options.maxGeneratedCandidates,
|
|
72
|
+
maxDurationMs: options.generationTimeoutMs,
|
|
73
|
+
maxCostUnits: options.generationCostUnits,
|
|
74
|
+
} : undefined,
|
|
75
|
+
});
|
|
49
76
|
const preflight = !fixture && options.surface === "opencode"
|
|
50
77
|
? (dependencies.preflightOpenCodeEvaluator ?? preflightOpenCodeEvaluator)({ cwd: options.dir })
|
|
51
78
|
: null;
|
|
52
79
|
if (preflight?.status === "failed") {
|
|
53
|
-
const result =
|
|
80
|
+
const result = initialInput.input_failure_code
|
|
81
|
+
? await runDeliveryPathSearch(initialInput, { name: "not-invoked", async evaluate() { throw new Error("input failure must stop before evaluation"); } })
|
|
82
|
+
: unavailableOpenCodeResult({ options, preflight, input: initialInput });
|
|
54
83
|
printDeliveryPathSearchResult(result, options, io);
|
|
55
84
|
return result;
|
|
56
85
|
}
|
|
@@ -58,18 +87,7 @@ export async function executeDeliveryPathSearch(options, io = console, dependenc
|
|
|
58
87
|
?? (preflight
|
|
59
88
|
? enforcementForSurface("opencode", preflight.evidence, { preflight })
|
|
60
89
|
: enforcementForSurface(options.surface));
|
|
61
|
-
const
|
|
62
|
-
const generationEnabled = Boolean(fixtureGeneration || options.generateCandidates);
|
|
63
|
-
const baseInput = fixture?.input ?? (dependencies.searchInputFromControl ?? searchInputFromControl)(options.dir, {
|
|
64
|
-
scopeKey: options.runId,
|
|
65
|
-
enforcement,
|
|
66
|
-
generation: generationEnabled ? {
|
|
67
|
-
enabled: true,
|
|
68
|
-
maxProposals: options.maxGeneratedCandidates,
|
|
69
|
-
maxDurationMs: options.generationTimeoutMs,
|
|
70
|
-
maxCostUnits: options.generationCostUnits,
|
|
71
|
-
} : undefined,
|
|
72
|
-
});
|
|
90
|
+
const baseInput = fixture ? initialInput : { ...initialInput, enforcement };
|
|
73
91
|
const input = generationEnabled && !baseInput.generation ? {
|
|
74
92
|
...baseInput,
|
|
75
93
|
generation: {
|
|
@@ -90,7 +108,13 @@ export async function executeDeliveryPathSearch(options, io = console, dependenc
|
|
|
90
108
|
? (dependencies.openCodeEvaluator ?? openCodeEvaluator)({ cwd: options.dir, model: options.model, preflight })
|
|
91
109
|
: null;
|
|
92
110
|
if (!evaluator) {
|
|
93
|
-
|
|
111
|
+
const detail = `${options.surface} has no executable evaluator in this release. Codex, Claude and preflight-qualified OpenCode are the executable adapters; --fixture is available for deterministic contract testing.`;
|
|
112
|
+
const result = {
|
|
113
|
+
...unavailableOpenCodeResult({ options, preflight: { code: "surface_evaluator_unavailable", detail, evidence: [] }, input }),
|
|
114
|
+
surface: options.surface,
|
|
115
|
+
};
|
|
116
|
+
printDeliveryPathSearchResult(result, options, io);
|
|
117
|
+
return result;
|
|
94
118
|
}
|
|
95
119
|
const generator = fixtureGeneration
|
|
96
120
|
? fixtureGenerator(fixtureGeneration)
|
|
@@ -125,15 +149,23 @@ function printDeliveryPathSearchResult(result, options, io) {
|
|
|
125
149
|
return;
|
|
126
150
|
}
|
|
127
151
|
io.log(`AGDF Delivery Path Search: ${result.status}`);
|
|
152
|
+
io.log(`Scope: ${result.scope_key ?? "unknown"} @ ${result.scope_revision ?? "unversioned"}`);
|
|
153
|
+
if (result.objective) io.log(`Objective: ${result.objective}`);
|
|
128
154
|
io.log(`Current gate: ${result.current_gate ?? "unknown"}`);
|
|
155
|
+
io.log(`Outcome phase: ${result.outcome_phase ?? "unknown"}`);
|
|
129
156
|
io.log(`Enforcement: ${result.enforcement.level}`);
|
|
130
157
|
io.log(`Recommendation: ${result.recommendation?.action ?? "none"}`);
|
|
131
158
|
if (result.budgets) io.log(`Evaluations: ${result.budgets.evaluations}`);
|
|
159
|
+
if (result.provenance) {
|
|
160
|
+
io.log(`Candidates: ${result.provenance.legal_candidates} legal, ${result.provenance.rejected_candidates} rejected`);
|
|
161
|
+
io.log(`Evaluation provenance: ${result.provenance.valid_evaluations}/${result.provenance.evaluation_attempts} valid, ${result.provenance.invalid_evaluations} invalid`);
|
|
162
|
+
}
|
|
132
163
|
if (result.generation) {
|
|
133
164
|
io.log(`Generation: ${result.generation.status} (${result.generation.accepted}/${result.generation.returned} accepted)`);
|
|
134
165
|
io.log(`Generation budget: ${result.generation.cost_units} cost units, ${result.generation.duration_ms} ms`);
|
|
135
166
|
if (result.generation.failure_code) io.log(`Generation failure: ${result.generation.failure_code}`);
|
|
136
167
|
}
|
|
137
168
|
io.log(`Stopping reason: ${result.stopping_reason}`);
|
|
138
|
-
io.log(result.
|
|
169
|
+
if (result.failure_code) io.log(`Failure: ${result.failure_code}`);
|
|
170
|
+
io.log(result.next_action ?? result.next_gate_action);
|
|
139
171
|
}
|
package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/contracts.js
CHANGED
|
@@ -68,6 +68,10 @@ export function validateSearchInput(value) {
|
|
|
68
68
|
}
|
|
69
69
|
requireString(input.objective, "objective");
|
|
70
70
|
requireString(input.current_gate, "current_gate");
|
|
71
|
+
optionalBoundedString(input.scope_revision, "scope_revision", 200);
|
|
72
|
+
optionalBoundedString(input.input_failure_code, "input_failure_code", 200);
|
|
73
|
+
optionalBoundedString(input.input_failure_detail, "input_failure_detail", 1000);
|
|
74
|
+
optionalBoundedString(input.input_recovery_action, "input_recovery_action", 1000);
|
|
71
75
|
stringArray(input.allowed_actions, "allowed_actions");
|
|
72
76
|
stringArray(input.forbidden_actions, "forbidden_actions");
|
|
73
77
|
stringArray(input.evidence_refs ?? [], "evidence_refs");
|
|
@@ -81,6 +85,39 @@ export function validateSearchInput(value) {
|
|
|
81
85
|
return structuredClone(input);
|
|
82
86
|
}
|
|
83
87
|
|
|
88
|
+
const RESULT_PHASE_BY_STATUS = new Map([
|
|
89
|
+
["input_unavailable", "input"],
|
|
90
|
+
["no_legal_candidates", "candidate"],
|
|
91
|
+
["evaluator_unavailable", "evaluation"],
|
|
92
|
+
["evaluator_error", "evaluation"],
|
|
93
|
+
["recommendation", "search"],
|
|
94
|
+
["no_safe_recommendation", "search"],
|
|
95
|
+
]);
|
|
96
|
+
|
|
97
|
+
export function validateSearchResult(value) {
|
|
98
|
+
const result = requireObject(value, "search result");
|
|
99
|
+
if (result.contract_version !== CONTRACT_VERSION) throw new Error(`unsupported search result contract_version: ${result.contract_version}`);
|
|
100
|
+
const status = requireString(result.status, "result.status");
|
|
101
|
+
const expectedPhase = RESULT_PHASE_BY_STATUS.get(status);
|
|
102
|
+
if (!expectedPhase) throw new Error(`unsupported search result status: ${status}`);
|
|
103
|
+
if (result.outcome_phase !== expectedPhase) throw new Error(`${status} requires outcome_phase ${expectedPhase}`);
|
|
104
|
+
requireString(result.scope_key, "result.scope_key");
|
|
105
|
+
optionalBoundedString(result.scope_revision, "result.scope_revision", 200);
|
|
106
|
+
const provenance = requireObject(result.provenance, "result.provenance");
|
|
107
|
+
for (const key of ["baseline_candidates", "generated_candidates", "legal_candidates", "rejected_candidates", "evaluation_attempts", "valid_evaluations", "invalid_evaluations"]) {
|
|
108
|
+
if (!Number.isInteger(provenance[key]) || provenance[key] < 0) throw new Error(`result.provenance.${key} must be a non-negative integer`);
|
|
109
|
+
}
|
|
110
|
+
if (provenance.evaluation_attempts !== provenance.valid_evaluations + provenance.invalid_evaluations) throw new Error("result evaluation provenance counts are inconsistent");
|
|
111
|
+
const recommendationFacing = status === "recommendation" || status === "no_safe_recommendation";
|
|
112
|
+
if (recommendationFacing && provenance.valid_evaluations < 1) throw new Error(`${status} requires at least one valid evaluation`);
|
|
113
|
+
if (status === "recommendation" && !result.recommendation) throw new Error("recommendation status requires recommendation content");
|
|
114
|
+
if (status !== "recommendation" && result.recommendation != null) throw new Error(`${status} must not contain recommendation content`);
|
|
115
|
+
if (status === "no_legal_candidates" && (provenance.legal_candidates !== 0 || provenance.evaluation_attempts !== 0)) throw new Error("no_legal_candidates requires zero legal candidates and evaluation attempts");
|
|
116
|
+
if (status === "input_unavailable" && provenance.evaluation_attempts !== 0) throw new Error("input_unavailable requires zero evaluation attempts");
|
|
117
|
+
if ((status === "evaluator_unavailable" || status === "evaluator_error") && provenance.valid_evaluations !== 0) throw new Error(`${status} requires zero valid evaluations`);
|
|
118
|
+
return structuredClone(result);
|
|
119
|
+
}
|
|
120
|
+
|
|
84
121
|
export function validateCandidate(value) {
|
|
85
122
|
const candidate = requireObject(value, "candidate");
|
|
86
123
|
requireString(candidate.id, "candidate.id");
|
package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/persistence.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
+
import { validateSearchResult } from "./contracts.js";
|
|
3
4
|
|
|
4
5
|
function safeResult(result) {
|
|
5
6
|
return JSON.parse(JSON.stringify(result, (key, value) => {
|
|
@@ -9,22 +10,33 @@ function safeResult(result) {
|
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export function persistSearchResult(targetDir, result) {
|
|
12
|
-
const
|
|
13
|
+
const validated = validateSearchResult(result);
|
|
14
|
+
if (!["recommendation", "no_safe_recommendation"].includes(validated.status)) {
|
|
15
|
+
throw new Error(`search result status ${validated.status} is not persistable`);
|
|
16
|
+
}
|
|
17
|
+
if (validated.provenance.valid_evaluations < 1) {
|
|
18
|
+
throw new Error("search result requires at least one valid evaluation before persistence");
|
|
19
|
+
}
|
|
20
|
+
const root = join(targetDir, ".agdf", "control", "artefacts", validated.scope_key);
|
|
13
21
|
const jsonPath = join(root, "DELIVERY_PATH_SEARCH.json");
|
|
14
22
|
const markdownPath = join(root, "DELIVERY_PATH_SEARCH.md");
|
|
15
23
|
mkdirSync(dirname(jsonPath), { recursive: true });
|
|
16
|
-
const safe = safeResult(
|
|
24
|
+
const safe = safeResult(validated);
|
|
17
25
|
writeFileSync(jsonPath, `${JSON.stringify(safe, null, 2)}\n`, "utf8");
|
|
18
26
|
const recommendation = safe.recommendation?.action ?? "No safe recommendation";
|
|
19
27
|
writeFileSync(markdownPath, [
|
|
20
28
|
"# Delivery Path Search Decision",
|
|
21
29
|
"",
|
|
22
30
|
`- status: ${safe.status}`,
|
|
31
|
+
`- outcome_phase: ${safe.outcome_phase}`,
|
|
32
|
+
`- scope_revision: ${safe.scope_revision}`,
|
|
23
33
|
`- current_gate: ${safe.current_gate}`,
|
|
24
34
|
`- enforcement: ${safe.enforcement.level}`,
|
|
25
35
|
`- recommendation: ${recommendation}`,
|
|
26
36
|
`- stopping_reason: ${safe.stopping_reason}`,
|
|
27
37
|
`- evaluations: ${safe.budgets.evaluations}`,
|
|
38
|
+
`- evaluation_attempts: ${safe.provenance.evaluation_attempts}`,
|
|
39
|
+
`- invalid_evaluations: ${safe.provenance.invalid_evaluations}`,
|
|
28
40
|
`- generation_status: ${safe.generation?.status ?? "legacy_deterministic"}`,
|
|
29
41
|
`- generated_candidates: ${safe.generation ? `${safe.generation.accepted}/${safe.generation.returned}` : "0/0"}`,
|
|
30
42
|
`- generation_cost_units: ${safe.generation?.cost_units ?? 0}`,
|
package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/search-engine.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CONTRACT_VERSION, SCORING_POLICY_VERSION, validateEvaluation, validateSearchInput } from "./contracts.js";
|
|
1
|
+
import { CONTRACT_VERSION, SCORING_POLICY_VERSION, validateEvaluation, validateSearchInput, validateSearchResult } from "./contracts.js";
|
|
2
2
|
import { candidateLegality, candidatesFromInput, generatedCandidatesFromResponse } from "./candidate-policy.js";
|
|
3
3
|
import { scoreEvaluation } from "./scoring.js";
|
|
4
4
|
import { generatorRequestFromInput } from "./state-adapter.js";
|
|
@@ -14,6 +14,30 @@ function generatorFailureCode(error) {
|
|
|
14
14
|
return "generator_schema_invalid";
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
function evaluatorFailureCode(error) {
|
|
18
|
+
if (error?.code === "ENOENT") return "evaluator_unavailable";
|
|
19
|
+
if (/auth/i.test(error?.message ?? "")) return "evaluator_authentication_failed";
|
|
20
|
+
if (/unavailable|not found|not configured/i.test(error?.message ?? "")) return "evaluator_unavailable";
|
|
21
|
+
return "evaluator_output_invalid";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function classifyTerminalOutcome({
|
|
25
|
+
inputUnavailable = false,
|
|
26
|
+
legalCandidates = 0,
|
|
27
|
+
evaluationAttempts = 0,
|
|
28
|
+
validEvaluations = 0,
|
|
29
|
+
invalidEvaluations = 0,
|
|
30
|
+
evaluatorUnavailable = false,
|
|
31
|
+
leader = null,
|
|
32
|
+
}) {
|
|
33
|
+
if (inputUnavailable) return { status: "input_unavailable", outcome_phase: "input" };
|
|
34
|
+
if (legalCandidates === 0) return { status: "no_legal_candidates", outcome_phase: "candidate" };
|
|
35
|
+
if (validEvaluations === 0 && evaluatorUnavailable) return { status: "evaluator_unavailable", outcome_phase: "evaluation" };
|
|
36
|
+
if (validEvaluations === 0 && legalCandidates > 0) return { status: "evaluator_error", outcome_phase: "evaluation" };
|
|
37
|
+
if (leader) return { status: "recommendation", outcome_phase: "search" };
|
|
38
|
+
return { status: "no_safe_recommendation", outcome_phase: "search" };
|
|
39
|
+
}
|
|
40
|
+
|
|
17
41
|
export async function runDeliveryPathSearch(inputValue, evaluator, options = {}) {
|
|
18
42
|
const input = validateSearchInput(inputValue);
|
|
19
43
|
const startedAt = Date.now();
|
|
@@ -22,12 +46,18 @@ export async function runDeliveryPathSearch(inputValue, evaluator, options = {})
|
|
|
22
46
|
const rejected = [];
|
|
23
47
|
const evaluated = [];
|
|
24
48
|
let evaluations = 0;
|
|
49
|
+
let evaluationAttempts = 0;
|
|
50
|
+
let invalidEvaluations = 0;
|
|
51
|
+
let legalCandidates = 0;
|
|
52
|
+
let rejectedCandidates = 0;
|
|
53
|
+
let evaluatorUnavailable = false;
|
|
54
|
+
let evaluationFailureCode = null;
|
|
25
55
|
let costUnits = 0;
|
|
26
56
|
let lastLeaderId = null;
|
|
27
57
|
let stableComparisons = 0;
|
|
28
58
|
let stoppingReason = "candidate_queue_exhausted";
|
|
29
59
|
const generation = {
|
|
30
|
-
status: input.generation?.enabled ? "
|
|
60
|
+
status: input.generation?.enabled ? "not_run" : "disabled",
|
|
31
61
|
adapter: options.generator?.metadata ?? null,
|
|
32
62
|
budgets: input.generation ?? null,
|
|
33
63
|
returned: 0,
|
|
@@ -38,7 +68,66 @@ export async function runDeliveryPathSearch(inputValue, evaluator, options = {})
|
|
|
38
68
|
failure_code: null,
|
|
39
69
|
};
|
|
40
70
|
|
|
71
|
+
const finish = ({ leader = null, outcome, failureCode = null, recoveryAction = null }) => {
|
|
72
|
+
evaluated.sort((a, b) => b.score - a.score || a.candidate.id.localeCompare(b.candidate.id));
|
|
73
|
+
const result = {
|
|
74
|
+
contract_version: CONTRACT_VERSION,
|
|
75
|
+
scoring_policy_version: SCORING_POLICY_VERSION,
|
|
76
|
+
scope_key: input.scope_key,
|
|
77
|
+
scope_revision: input.scope_revision ?? "unversioned",
|
|
78
|
+
objective: input.objective,
|
|
79
|
+
current_gate: input.current_gate,
|
|
80
|
+
outcome_phase: outcome.outcome_phase,
|
|
81
|
+
status: outcome.status,
|
|
82
|
+
recommendation: outcome.status === "recommendation" && leader ? {
|
|
83
|
+
candidate_id: leader.candidate.id,
|
|
84
|
+
action: leader.candidate.action,
|
|
85
|
+
score: leader.score,
|
|
86
|
+
rationale: leader.evaluation.rationale,
|
|
87
|
+
expected_evidence: leader.candidate.expected_evidence,
|
|
88
|
+
tests: leader.candidate.tests,
|
|
89
|
+
risks: leader.evaluation.risks,
|
|
90
|
+
assumptions: leader.evaluation.assumptions,
|
|
91
|
+
} : null,
|
|
92
|
+
alternatives: outcome.outcome_phase === "search" ? evaluated.slice(1).map((item) => ({
|
|
93
|
+
candidate_id: item.candidate.id,
|
|
94
|
+
action: item.candidate.action,
|
|
95
|
+
score: item.score,
|
|
96
|
+
rejection_reason: `ranked_below_${leader?.candidate.id ?? "search_policy"}`,
|
|
97
|
+
})) : [],
|
|
98
|
+
rejected,
|
|
99
|
+
provenance: {
|
|
100
|
+
baseline_candidates: baseline.length,
|
|
101
|
+
generated_candidates: generation.accepted,
|
|
102
|
+
legal_candidates: legalCandidates,
|
|
103
|
+
rejected_candidates: rejectedCandidates + generation.rejected.length,
|
|
104
|
+
evaluation_attempts: evaluationAttempts,
|
|
105
|
+
valid_evaluations: evaluations,
|
|
106
|
+
invalid_evaluations: invalidEvaluations,
|
|
107
|
+
},
|
|
108
|
+
enforcement: input.enforcement,
|
|
109
|
+
evaluator: evaluator?.metadata ?? { name: evaluator?.name ?? "unknown" },
|
|
110
|
+
generation,
|
|
111
|
+
budgets: { configured: input.budgets, evaluations, cost_units: costUnits, stable_comparisons: stableComparisons, duration_ms: Date.now() - startedAt },
|
|
112
|
+
stopping_reason: stoppingReason,
|
|
113
|
+
failure_code: failureCode,
|
|
114
|
+
next_action: recoveryAction ?? "Run canonical AGDF gate-check; search does not grant permission.",
|
|
115
|
+
next_gate_action: recoveryAction ?? "Run canonical AGDF gate-check; search does not grant permission.",
|
|
116
|
+
};
|
|
117
|
+
return validateSearchResult(result);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
if (input.input_failure_code || input.allowed_actions.length === 0) {
|
|
121
|
+
stoppingReason = input.input_failure_code || "canonical_actions_unavailable";
|
|
122
|
+
return finish({
|
|
123
|
+
outcome: classifyTerminalOutcome({ inputUnavailable: true }),
|
|
124
|
+
failureCode: input.input_failure_code || "canonical_actions_unavailable",
|
|
125
|
+
recoveryAction: input.input_recovery_action || "Run canonical AGDF gate-check and repair the selected control state.",
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
41
129
|
if (input.generation?.enabled) {
|
|
130
|
+
generation.status = "failed";
|
|
42
131
|
if (!options.generator) {
|
|
43
132
|
generation.failure_code = "generator_unavailable";
|
|
44
133
|
} else {
|
|
@@ -75,17 +164,20 @@ export async function runDeliveryPathSearch(inputValue, evaluator, options = {})
|
|
|
75
164
|
}
|
|
76
165
|
|
|
77
166
|
while (queue.length > 0) {
|
|
78
|
-
if (evaluations >= input.budgets.max_evaluations) { stoppingReason = "evaluation_budget_exhausted"; break; }
|
|
79
|
-
if (costUnits >= input.budgets.max_cost_units) { stoppingReason = "cost_budget_exhausted"; break; }
|
|
80
|
-
if (Date.now() - startedAt >= input.budgets.max_duration_ms) { stoppingReason = "duration_budget_exhausted"; break; }
|
|
81
167
|
const candidate = queue.shift();
|
|
82
168
|
const legality = candidateLegality(candidate, input);
|
|
83
169
|
if (!legality.legal) {
|
|
170
|
+
rejectedCandidates += 1;
|
|
84
171
|
rejected.push({ candidate_id: candidate.id, action: candidate.action, reason: legality.reason });
|
|
85
172
|
continue;
|
|
86
173
|
}
|
|
174
|
+
legalCandidates += 1;
|
|
175
|
+
if (evaluations >= input.budgets.max_evaluations) { stoppingReason = "evaluation_budget_exhausted"; evaluationFailureCode = stoppingReason; break; }
|
|
176
|
+
if (costUnits >= input.budgets.max_cost_units) { stoppingReason = "cost_budget_exhausted"; evaluationFailureCode = stoppingReason; break; }
|
|
177
|
+
if (Date.now() - startedAt >= input.budgets.max_duration_ms) { stoppingReason = "duration_budget_exhausted"; evaluationFailureCode = stoppingReason; break; }
|
|
87
178
|
|
|
88
179
|
try {
|
|
180
|
+
evaluationAttempts += 1;
|
|
89
181
|
const evaluation = validateEvaluation(await evaluator.evaluate(input, candidate), candidate.id);
|
|
90
182
|
evaluations += 1;
|
|
91
183
|
costUnits += evaluation.cost;
|
|
@@ -115,41 +207,39 @@ export async function runDeliveryPathSearch(inputValue, evaluator, options = {})
|
|
|
115
207
|
}
|
|
116
208
|
} catch (error) {
|
|
117
209
|
if (error?.fatalEvaluator === true) throw error;
|
|
210
|
+
invalidEvaluations += 1;
|
|
211
|
+
evaluationFailureCode = evaluatorFailureCode(error);
|
|
212
|
+
evaluatorUnavailable ||= evaluationFailureCode === "evaluator_unavailable" || evaluationFailureCode === "evaluator_authentication_failed";
|
|
118
213
|
rejected.push({ candidate_id: candidate.id, action: candidate.action, reason: `invalid_evaluation: ${error.message}` });
|
|
214
|
+
if (evaluatorUnavailable) break;
|
|
119
215
|
}
|
|
120
216
|
}
|
|
121
217
|
|
|
122
218
|
evaluated.sort((a, b) => b.score - a.score || a.candidate.id.localeCompare(b.candidate.id));
|
|
123
219
|
const leader = evaluated[0];
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
evaluator: evaluator.metadata ?? { name: evaluator.name ?? "unknown" },
|
|
150
|
-
generation,
|
|
151
|
-
budgets: { configured: input.budgets, evaluations, cost_units: costUnits, stable_comparisons: stableComparisons, duration_ms: Date.now() - startedAt },
|
|
152
|
-
stopping_reason: stoppingReason,
|
|
153
|
-
next_gate_action: "Run canonical AGDF gate-check; search does not grant permission.",
|
|
154
|
-
};
|
|
220
|
+
const outcome = classifyTerminalOutcome({
|
|
221
|
+
legalCandidates,
|
|
222
|
+
evaluationAttempts,
|
|
223
|
+
validEvaluations: evaluations,
|
|
224
|
+
invalidEvaluations,
|
|
225
|
+
evaluatorUnavailable,
|
|
226
|
+
leader,
|
|
227
|
+
});
|
|
228
|
+
if (!leader) {
|
|
229
|
+
stoppingReason = outcome.status === "no_legal_candidates"
|
|
230
|
+
? "no_legal_candidates"
|
|
231
|
+
: outcome.status === "evaluator_unavailable"
|
|
232
|
+
? "evaluator_unavailable"
|
|
233
|
+
: outcome.status === "evaluator_error"
|
|
234
|
+
? "evaluator_error"
|
|
235
|
+
: stoppingReason;
|
|
236
|
+
}
|
|
237
|
+
return finish({
|
|
238
|
+
leader,
|
|
239
|
+
outcome,
|
|
240
|
+
failureCode: outcome.outcome_phase === "evaluation" ? evaluationFailureCode : null,
|
|
241
|
+
recoveryAction: outcome.outcome_phase === "evaluation"
|
|
242
|
+
? "Repair the declared evaluator capability and retry from a fresh canonical control snapshot."
|
|
243
|
+
: null,
|
|
244
|
+
});
|
|
155
245
|
}
|
package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/state-adapter.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
1
|
import {
|
|
4
2
|
CONTRACT_VERSION,
|
|
5
3
|
GENERATOR_CONTRACT_VERSION,
|
|
6
4
|
validateGeneratorRequest,
|
|
7
5
|
} from "./contracts.js";
|
|
8
|
-
import {
|
|
6
|
+
import { evaluateGateCheck } from "../control-evaluation/gate-check.js";
|
|
7
|
+
import { readRunState } from "../control-evaluation/run-state.js";
|
|
9
8
|
|
|
10
9
|
function section(content, heading) {
|
|
11
10
|
return (
|
|
@@ -15,100 +14,44 @@ function section(content, heading) {
|
|
|
15
14
|
);
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
.split("|")
|
|
23
|
-
.slice(1, -1)
|
|
24
|
-
.map((cell) => cell.trim());
|
|
25
|
-
if (
|
|
26
|
-
cells.length >= 2 &&
|
|
27
|
-
cells[0] &&
|
|
28
|
-
!cells[0].startsWith("---") &&
|
|
29
|
-
cells[0] !== "Question"
|
|
30
|
-
)
|
|
31
|
-
answers[cells[0]] = cells[1];
|
|
32
|
-
}
|
|
33
|
-
return answers;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function statusCard(content) {
|
|
37
|
-
const card = {};
|
|
38
|
-
for (const line of section(content, "Run Status Card").split(/\r?\n/)) {
|
|
39
|
-
const cells = line
|
|
40
|
-
.split("|")
|
|
41
|
-
.slice(1, -1)
|
|
42
|
-
.map((cell) => cell.trim().replace(/^`|`$/g, ""));
|
|
43
|
-
if (
|
|
44
|
-
cells.length >= 2 &&
|
|
45
|
-
cells[0] &&
|
|
46
|
-
!cells[0].startsWith("---") &&
|
|
47
|
-
cells[0] !== "Run status"
|
|
48
|
-
)
|
|
49
|
-
card[cells[0]] = cells[1];
|
|
50
|
-
}
|
|
51
|
-
return card;
|
|
17
|
+
function metaField(content, name) {
|
|
18
|
+
return content.match(new RegExp(`^- ${name}:\\s*(.+)$`, "m"))?.[1]
|
|
19
|
+
?.replace(/^`|`$/g, "")
|
|
20
|
+
.trim() ?? "";
|
|
52
21
|
}
|
|
53
22
|
|
|
54
|
-
function
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
23
|
+
export function searchInputFromControl(targetDir, options = {}, dependencies = {}) {
|
|
24
|
+
const evaluate = dependencies.evaluateGateCheck ?? evaluateGateCheck;
|
|
25
|
+
const readRun = dependencies.readRunState ?? readRunState;
|
|
26
|
+
const selection = options.scopeKey ? { runId: options.scopeKey } : {};
|
|
27
|
+
const gate = evaluate(targetDir, selection);
|
|
28
|
+
const run = readRun(targetDir, selection);
|
|
29
|
+
const content = run.content ?? "";
|
|
30
|
+
const evaluatedRunId = gate.status_card?.run_id ?? "";
|
|
31
|
+
const evaluatedRevision = gate.status_presentation?.revision_id ?? "";
|
|
32
|
+
const runId = metaField(content, "run_id");
|
|
33
|
+
const runRevision = metaField(content, "revision_id");
|
|
34
|
+
const runGate = metaField(content, "current_gate");
|
|
35
|
+
let inputFailureCode = "";
|
|
36
|
+
if (!content || run.resolution_error) inputFailureCode = "canonical_control_unavailable";
|
|
37
|
+
else if (!evaluatedRunId || !evaluatedRevision) inputFailureCode = "canonical_snapshot_identity_missing";
|
|
38
|
+
else if (evaluatedRunId !== runId || evaluatedRevision !== runRevision || gate.current_gate !== runGate) {
|
|
39
|
+
inputFailureCode = "stale_control_snapshot";
|
|
40
|
+
} else if (!Array.isArray(gate.allowed) || gate.allowed.length === 0) {
|
|
41
|
+
inputFailureCode = "canonical_actions_unavailable";
|
|
68
42
|
}
|
|
69
|
-
const resolved = existsSync(canonicalRoot)
|
|
70
|
-
? resolveRuns(targetDir, {
|
|
71
|
-
runIdArg: options.scopeKey,
|
|
72
|
-
runIdEnv: process.env.AGDF_RUN_ID,
|
|
73
|
-
})
|
|
74
|
-
: null;
|
|
75
|
-
const runPath =
|
|
76
|
-
resolved?.run.path ?? join(targetDir, ".agdf", "control", "AGDF_RUN.md");
|
|
77
|
-
if (!existsSync(runPath)) throw new Error("missing AGDF run state");
|
|
78
|
-
const content = readFileSync(runPath, "utf8");
|
|
79
|
-
const meta = Object.fromEntries(
|
|
80
|
-
[...content.matchAll(/^- ([a-z_]+):\s*(.+)$/gm)].map((match) => [
|
|
81
|
-
match[1],
|
|
82
|
-
match[2].replace(/^`|`$/g, "").trim(),
|
|
83
|
-
]),
|
|
84
|
-
);
|
|
85
|
-
const answers = tableAnswers(content);
|
|
86
|
-
const card = statusCard(content);
|
|
87
43
|
const result = {
|
|
88
44
|
contract_version: CONTRACT_VERSION,
|
|
89
|
-
scope_key: options.scopeKey
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
),
|
|
100
|
-
]
|
|
101
|
-
.slice(1)
|
|
102
|
-
.map((match) => `${match[1].trim()}: ${match[2].trim()}`),
|
|
103
|
-
risks: section(content, "Risks")
|
|
104
|
-
.split(/\r?\n/)
|
|
105
|
-
.filter(
|
|
106
|
-
(line) =>
|
|
107
|
-
line.startsWith("|") &&
|
|
108
|
-
!line.includes("---") &&
|
|
109
|
-
!line.includes("| Risk |"),
|
|
110
|
-
)
|
|
111
|
-
.map((line) => line.split("|")[1].trim()),
|
|
45
|
+
scope_key: evaluatedRunId || runId || options.scopeKey || "unknown-scope",
|
|
46
|
+
scope_revision: evaluatedRevision || runRevision || "unversioned",
|
|
47
|
+
objective: section(content, "Objective").trim() || "Canonical Delivery Path Search input unavailable",
|
|
48
|
+
current_gate: gate.current_gate || runGate || "unknown",
|
|
49
|
+
allowed_actions: inputFailureCode ? [] : [...gate.allowed],
|
|
50
|
+
forbidden_actions: Array.isArray(gate.forbidden) ? [...gate.forbidden] : [],
|
|
51
|
+
evidence_refs: Array.isArray(gate.evidence_refs)
|
|
52
|
+
? gate.evidence_refs.map((item) => `${item.evidence}: ${item.source}`)
|
|
53
|
+
: [],
|
|
54
|
+
risks: Array.isArray(run.risks) ? run.risks.map((item) => item.risk).filter(Boolean) : [],
|
|
112
55
|
enforcement: options.enforcement ?? {
|
|
113
56
|
level: "instruction_only",
|
|
114
57
|
evidence: ["surface instruction prohibits implementation during search"],
|
|
@@ -122,6 +65,11 @@ export function searchInputFromControl(targetDir, options = {}) {
|
|
|
122
65
|
stability_window: options.stabilityWindow ?? 3,
|
|
123
66
|
},
|
|
124
67
|
};
|
|
68
|
+
if (inputFailureCode) {
|
|
69
|
+
result.input_failure_code = inputFailureCode;
|
|
70
|
+
result.input_failure_detail = run.resolution_error || (gate.blocking_reason !== "none" ? gate.blocking_reason : "") || "canonical input is not ready";
|
|
71
|
+
result.input_recovery_action = gate.next_allowed_action || "Run canonical AGDF gate-check and repair the selected control state.";
|
|
72
|
+
}
|
|
125
73
|
if (options.generation?.enabled)
|
|
126
74
|
result.generation = {
|
|
127
75
|
enabled: true,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schema_version": "1",
|
|
3
3
|
"generated": true,
|
|
4
4
|
"source": "create-agdf/cli",
|
|
5
|
-
"version": "0.14.
|
|
5
|
+
"version": "0.14.3",
|
|
6
6
|
"entrypoint": "create-agdf/bin/agdf-validator.js",
|
|
7
|
-
"digest": "
|
|
7
|
+
"digest": "8f6dbd5e647aff7dfc1405f4e54a5b135a8d820858b5f8f85873964f6eb2f7cf"
|
|
8
8
|
}
|