loopforge 3.8.3 → 3.9.1
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 +15 -0
- package/dist/audit.d.ts +13 -1
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js +18 -3
- package/dist/audit.js.map +1 -1
- package/dist/canonical-state.d.ts +1 -2
- package/dist/canonical-state.d.ts.map +1 -1
- package/dist/canonical-state.js +4 -12
- package/dist/canonical-state.js.map +1 -1
- package/dist/cli.js +12 -12
- package/dist/committed-round.d.ts +48 -23
- package/dist/committed-round.d.ts.map +1 -1
- package/dist/committed-round.js +214 -149
- package/dist/committed-round.js.map +1 -1
- package/dist/contract-items.d.ts +3 -2
- package/dist/contract-items.d.ts.map +1 -1
- package/dist/contract-items.js +18 -7
- package/dist/contract-items.js.map +1 -1
- package/dist/enforcement-gate.d.ts +15 -5
- package/dist/enforcement-gate.d.ts.map +1 -1
- package/dist/enforcement-gate.js +60 -159
- package/dist/enforcement-gate.js.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +20 -14
- package/dist/engine.js.map +1 -1
- package/dist/evidence-claims.d.ts +6 -5
- package/dist/evidence-claims.d.ts.map +1 -1
- package/dist/evidence-claims.js +21 -20
- package/dist/evidence-claims.js.map +1 -1
- package/dist/evidence-provider.d.ts +73 -42
- package/dist/evidence-provider.d.ts.map +1 -1
- package/dist/evidence-provider.js +437 -138
- package/dist/evidence-provider.js.map +1 -1
- package/dist/explain.d.ts +18 -3
- package/dist/explain.d.ts.map +1 -1
- package/dist/explain.js +26 -5
- package/dist/explain.js.map +1 -1
- package/dist/field-accounting.d.ts +29 -0
- package/dist/field-accounting.d.ts.map +1 -0
- package/dist/field-accounting.js +132 -0
- package/dist/field-accounting.js.map +1 -0
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/loop-compiler.d.ts +5 -11
- package/dist/loop-compiler.d.ts.map +1 -1
- package/dist/loop-compiler.js +30 -90
- package/dist/loop-compiler.js.map +1 -1
- package/dist/loop-store.d.ts +3 -0
- package/dist/loop-store.d.ts.map +1 -1
- package/dist/loop-store.js +21 -11
- package/dist/loop-store.js.map +1 -1
- package/dist/mcp/round-lifecycle.d.ts +30 -2
- package/dist/mcp/round-lifecycle.d.ts.map +1 -1
- package/dist/mcp/round-lifecycle.js +206 -25
- package/dist/mcp/round-lifecycle.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +17 -14
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/session.d.ts +15 -1
- package/dist/mcp/session.d.ts.map +1 -1
- package/dist/mcp/session.js +34 -1
- package/dist/mcp/session.js.map +1 -1
- package/dist/mcp/submission-boundary.d.ts +5 -2
- package/dist/mcp/submission-boundary.d.ts.map +1 -1
- package/dist/mcp/submission-boundary.js +38 -6
- package/dist/mcp/submission-boundary.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +73 -45
- package/dist/mcp/tools.js.map +1 -1
- package/dist/policy-metrics.d.ts +14 -0
- package/dist/policy-metrics.d.ts.map +1 -1
- package/dist/policy-metrics.js +53 -1
- package/dist/policy-metrics.js.map +1 -1
- package/dist/policy.d.ts +1 -3
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +3 -4
- package/dist/policy.js.map +1 -1
- package/dist/prompt-assembler.d.ts.map +1 -1
- package/dist/prompt-assembler.js +71 -35
- package/dist/prompt-assembler.js.map +1 -1
- package/dist/protocol.d.ts +186 -19
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +4 -3
- package/dist/protocol.js.map +1 -1
- package/dist/replay.d.ts +3 -0
- package/dist/replay.d.ts.map +1 -1
- package/dist/replay.js +46 -7
- package/dist/replay.js.map +1 -1
- package/dist/round-contract.d.ts +5 -4
- package/dist/round-contract.d.ts.map +1 -1
- package/dist/round-contract.js +4 -4
- package/dist/round-contract.js.map +1 -1
- package/dist/round-coordinator.d.ts +11 -1
- package/dist/round-coordinator.d.ts.map +1 -1
- package/dist/round-coordinator.js +33 -14
- package/dist/round-coordinator.js.map +1 -1
- package/dist/round-driver.d.ts +6 -1
- package/dist/round-driver.d.ts.map +1 -1
- package/dist/round-driver.js +3 -0
- package/dist/round-driver.js.map +1 -1
- package/dist/round-facts.d.ts +3 -2
- package/dist/round-facts.d.ts.map +1 -1
- package/dist/round-facts.js +4 -4
- package/dist/round-facts.js.map +1 -1
- package/dist/round-transaction.d.ts +24 -10
- package/dist/round-transaction.d.ts.map +1 -1
- package/dist/round-transaction.js +83 -19
- package/dist/round-transaction.js.map +1 -1
- package/dist/self-eval.d.ts +28 -10
- package/dist/self-eval.d.ts.map +1 -1
- package/dist/self-eval.js +522 -128
- package/dist/self-eval.js.map +1 -1
- package/dist/submission-diagnostics.d.ts +12 -0
- package/dist/submission-diagnostics.d.ts.map +1 -0
- package/dist/submission-diagnostics.js +12 -0
- package/dist/submission-diagnostics.js.map +1 -0
- package/dist/submission-guidance.d.ts +119 -0
- package/dist/submission-guidance.d.ts.map +1 -0
- package/dist/submission-guidance.js +766 -0
- package/dist/submission-guidance.js.map +1 -0
- package/dist/submission-receipt.d.ts +48 -0
- package/dist/submission-receipt.d.ts.map +1 -0
- package/dist/submission-receipt.js +336 -0
- package/dist/submission-receipt.js.map +1 -0
- package/dist/verification-gate.d.ts +13 -7
- package/dist/verification-gate.d.ts.map +1 -1
- package/dist/verification-gate.js +149 -90
- package/dist/verification-gate.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/loop_policy.json +58 -59
- package/package.json +68 -67
- package/skills/perception/SKILL.md +90 -42
|
@@ -0,0 +1,766 @@
|
|
|
1
|
+
/** The evaluation field guide and the submission-guidance projection.
|
|
2
|
+
*
|
|
3
|
+
* This module is the ONE source for what an evaluation field means, when it
|
|
4
|
+
* applies, what a legal example looks like, and where a submitted value goes.
|
|
5
|
+
* The MCP tool schema, the round prompt's evaluation block, and
|
|
6
|
+
* `submission_guidance` all read it; none of them owns a second copy.
|
|
7
|
+
*
|
|
8
|
+
* It is an interface description, not state: it performs no I/O, persists
|
|
9
|
+
* nothing, and makes no business decision. The runtime's submission boundary
|
|
10
|
+
* remains the only validator.
|
|
11
|
+
*/
|
|
12
|
+
import { deriveConfiguredCapability, getPolicy, } from "./policy.js";
|
|
13
|
+
import { deriveRoundFacts, NO_IN_FLIGHT_ROUND } from "./round-facts.js";
|
|
14
|
+
import { deriveSubGoals } from "./subgoal-state.js";
|
|
15
|
+
/** Field order used by the prompt, guidance and receipts. Core fields first,
|
|
16
|
+
* then the execution report, then contract/sub-goal state, then the
|
|
17
|
+
* cognitive/report fields, then terminal fields. Deterministic by design. */
|
|
18
|
+
export const FIELD_ORDER = [
|
|
19
|
+
"success",
|
|
20
|
+
"output_summary",
|
|
21
|
+
"constraint_violations",
|
|
22
|
+
"should_continue",
|
|
23
|
+
"execution_report.files_changed",
|
|
24
|
+
"execution_report.tests_reported",
|
|
25
|
+
"execution_report.contract_item_claims",
|
|
26
|
+
"execution_report.criterion_claims",
|
|
27
|
+
"subgoal_updates",
|
|
28
|
+
"emerged_subtasks",
|
|
29
|
+
"discovered_constraints",
|
|
30
|
+
"wrong_assumptions",
|
|
31
|
+
"objective_refinement",
|
|
32
|
+
"retracted_constraints",
|
|
33
|
+
"revised_success_criteria",
|
|
34
|
+
"round_contract",
|
|
35
|
+
"worker_results",
|
|
36
|
+
"prompt_requests",
|
|
37
|
+
"compression_checkpoint",
|
|
38
|
+
"checkpoint_label",
|
|
39
|
+
"retroactiveClaims",
|
|
40
|
+
"gate_ids",
|
|
41
|
+
"outcome",
|
|
42
|
+
"blocker",
|
|
43
|
+
"stop_reason",
|
|
44
|
+
"no_change_reason",
|
|
45
|
+
];
|
|
46
|
+
const GUIDES = [
|
|
47
|
+
{
|
|
48
|
+
path: "success",
|
|
49
|
+
purpose: "Whether the whole objective and every hard constraint are satisfied.",
|
|
50
|
+
when: "Every round. Use true only when the full goal is achieved and verified.",
|
|
51
|
+
nature: "claim",
|
|
52
|
+
downstream: "Stop decision, success trajectory, verification posture.",
|
|
53
|
+
toolDescription: "true ONLY if all hard constraints were met AND the task goal was achieved. " +
|
|
54
|
+
"This is a claim; a machine observation is what backs it.",
|
|
55
|
+
core: true,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
path: "output_summary",
|
|
59
|
+
purpose: "What was actually done this round, not what was attempted.",
|
|
60
|
+
when: "Every round.",
|
|
61
|
+
nature: "report",
|
|
62
|
+
downstream: "Rolling summary, focus/handoff projection, backtrack failed-approach list.",
|
|
63
|
+
toolDescription: "Specific, actionable summary of what was DONE this round — not what was " +
|
|
64
|
+
"attempted. Do not restate the plan.",
|
|
65
|
+
core: true,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
path: "constraint_violations",
|
|
69
|
+
purpose: "Hard constraints actually violated this round.",
|
|
70
|
+
when: "Every round; empty when none were violated.",
|
|
71
|
+
nature: "report",
|
|
72
|
+
downstream: "Recurring-violation detection and constraint retirement.",
|
|
73
|
+
toolDescription: "Constraints the agent actually violated this round, preferably by the " +
|
|
74
|
+
"c-XXXXXXXX id the prompt rendered. Empty when none. Be honest.",
|
|
75
|
+
core: true,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
path: "should_continue",
|
|
79
|
+
purpose: "Whether the loop should advance to another round.",
|
|
80
|
+
when: "Every round. false only when the ENTIRE task is complete or the agent must stop.",
|
|
81
|
+
nature: "control",
|
|
82
|
+
downstream: "Stop decision. Partial progress is still true.",
|
|
83
|
+
toolDescription: "false ONLY when the ENTIRE task is complete or a stop is required. " +
|
|
84
|
+
"Partial progress = true.",
|
|
85
|
+
core: true,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
path: "execution_report.files_changed",
|
|
89
|
+
purpose: "The boundary net change: paths whose content or file type differs between " +
|
|
90
|
+
"round preparation and this submission, including deleted paths.",
|
|
91
|
+
when: "Every round that changed the workspace. A commit alone adds no entry when content is unchanged.",
|
|
92
|
+
nature: "report",
|
|
93
|
+
downstream: "Compared with the machine boundary delta; never trusted as the observation.",
|
|
94
|
+
toolDescription: "Paths whose content or file type differs between round start and this " +
|
|
95
|
+
"submission, including deletions. A commit alone does not add a path when " +
|
|
96
|
+
"content is unchanged. Gitignored paths are outside the machine boundary — " +
|
|
97
|
+
"do not report them merely to look complete.",
|
|
98
|
+
reportOnly: false,
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
path: "execution_report.tests_reported",
|
|
102
|
+
purpose: "The agent's own test counts.",
|
|
103
|
+
when: "When tests were run (or a test run is relevant to the claim).",
|
|
104
|
+
nature: "report",
|
|
105
|
+
downstream: "Compared with parsed command output when available; never converted into a verification verdict.",
|
|
106
|
+
toolDescription: "Self-reported test counts. Informational: the runtime never translates " +
|
|
107
|
+
"an exit code into a test count, and the receipt shows self-report and " +
|
|
108
|
+
"command observation separately.",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
path: "execution_report.contract_item_claims",
|
|
112
|
+
purpose: "Claims about items of the ACTIVE Round Contract.",
|
|
113
|
+
when: "Only when an active contract is open; cite the rci-XXXXXXXX ids rendered in the prompt.",
|
|
114
|
+
nature: "claim",
|
|
115
|
+
downstream: "Starts machine evaluation of the item; the item becomes verified only when its bound commands pass.",
|
|
116
|
+
toolDescription: "Claims about items of the ACTIVE contract, cited by the rci-XXXXXXXX id " +
|
|
117
|
+
"the prompt rendered. A claim never verifies anything by itself — the " +
|
|
118
|
+
"runtime marks an item verified only when its bound commands are observed " +
|
|
119
|
+
"passing. Unknown ids or illegal outcomes are contract_invalid.",
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
path: "execution_report.criterion_claims",
|
|
123
|
+
purpose: "Advisory claims about objective criteria.",
|
|
124
|
+
when: "When you want to state which criteria are met or still remaining.",
|
|
125
|
+
nature: "claim",
|
|
126
|
+
downstream: "Advisory only: unbacked claims warn; they never upgrade a criterion to verified.",
|
|
127
|
+
toolDescription: "Advisory claims about objective criteria. LENIENT: unknown or malformed " +
|
|
128
|
+
"ids are dropped with a diagnostic, never a rejection. A criterion claim " +
|
|
129
|
+
"never becomes machine-verified by itself.",
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
path: "subgoal_updates",
|
|
133
|
+
purpose: "Explicit status transitions for existing sub-goals.",
|
|
134
|
+
when: "When an active sg-XXXXXXXX sub-goal starts, is blocked, completes, or is canceled.",
|
|
135
|
+
nature: "transition",
|
|
136
|
+
downstream: "Sub-goal state derived from committed rounds; done/canceled are terminal.",
|
|
137
|
+
toolDescription: "Explicit status transitions for EXISTING sub-goals. Each entry references " +
|
|
138
|
+
"an ACTIVE sg-XXXXXXXX id from the prompt. Unknown ids, done/canceled " +
|
|
139
|
+
"(terminal) references, and illegal migrations are evaluation_invalid. " +
|
|
140
|
+
"Re-open work through a NEW emerged_subtasks declaration, never by " +
|
|
141
|
+
"referencing a terminal id.",
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
path: "emerged_subtasks",
|
|
145
|
+
purpose: "New sub-problems that surfaced during execution.",
|
|
146
|
+
when: "When a new work item appears or an existing one must be split.",
|
|
147
|
+
nature: "transition",
|
|
148
|
+
downstream: "The only sub-goal creation channel; the runtime derives stable sg- ids.",
|
|
149
|
+
toolDescription: "Sub-problems that surfaced during execution. The ONLY sub-goal creation " +
|
|
150
|
+
"channel. Plain descriptions, never sg-XXXXXXXX ids.",
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
path: "discovered_constraints",
|
|
154
|
+
purpose: "New constraints that later rounds must respect.",
|
|
155
|
+
when: "When this round discovered a limit that was not known before.",
|
|
156
|
+
nature: "report",
|
|
157
|
+
downstream: "Merged into the active constraint set by the compiler (bounded per round).",
|
|
158
|
+
toolDescription: "New constraints that must apply to later rounds. This is the ONLY " +
|
|
159
|
+
"promotion channel for a worker-discovered constraint: a worker result " +
|
|
160
|
+
"stays a report until the main agent states the constraint here.",
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
path: "wrong_assumptions",
|
|
164
|
+
purpose: "Assumptions from earlier rounds that this round falsified.",
|
|
165
|
+
when: "When evidence proved an earlier assumption wrong; omit when none.",
|
|
166
|
+
nature: "report",
|
|
167
|
+
downstream: "State-file 'Corrected assumption', recovery brief, and backtrack wrong-assumption facts.",
|
|
168
|
+
toolDescription: "Assumptions from earlier rounds that turned out to be wrong. Record one " +
|
|
169
|
+
"only when this round actually falsified it; otherwise omit. This is not " +
|
|
170
|
+
"a reflection quota.",
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
path: "objective_refinement",
|
|
174
|
+
purpose: "A deeper or more accurate understanding of the objective.",
|
|
175
|
+
when: "When this round changed your understanding of what the task needs.",
|
|
176
|
+
nature: "report",
|
|
177
|
+
downstream: "Appended to the objective with a version bump; never replaces the original objective.",
|
|
178
|
+
toolDescription: "Optional. A refinement or deepening of the task objective based on this " +
|
|
179
|
+
"round's discoveries. Appended, never substituted for the original goal.",
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
path: "retracted_constraints",
|
|
183
|
+
purpose: "Existing constraints that are no longer correct or relevant.",
|
|
184
|
+
when: "When a prior constraint is proven wrong or obsolete.",
|
|
185
|
+
nature: "report",
|
|
186
|
+
downstream: "Retired from the active set (with the configured retirement window for plan/hard constraints).",
|
|
187
|
+
toolDescription: "Optional. Constraints the agent now believes are wrong or irrelevant, by " +
|
|
188
|
+
"c-XXXXXXXX id or exact text. Omit when none.",
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
path: "revised_success_criteria",
|
|
192
|
+
purpose: "Success criteria that need reformulation.",
|
|
193
|
+
when: "When the original criterion was incorrect or unmeasurable.",
|
|
194
|
+
nature: "report",
|
|
195
|
+
downstream: "Applied to the Loop Objective with a version bump.",
|
|
196
|
+
toolDescription: "Optional. Success criteria that need reformulation: each entry has the " +
|
|
197
|
+
"old and new wording.",
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
path: "round_contract",
|
|
201
|
+
purpose: "A proposal for the NEXT round's evidence-bound contract.",
|
|
202
|
+
when: "When no contract is active and a contract command is available; while a " +
|
|
203
|
+
"contract is open, omit it (or restate it unchanged) unless this round " +
|
|
204
|
+
"closes it and declares a successor.",
|
|
205
|
+
nature: "proposal",
|
|
206
|
+
downstream: "Becomes active only after this round commits; item ids rci-XXXXXXXX are " +
|
|
207
|
+
"derived by the runtime.",
|
|
208
|
+
toolDescription: "Proposal for the NEXT round's contract (items + verify_with + scope). " +
|
|
209
|
+
"Declared here, it becomes the ACTIVE contract only after this round " +
|
|
210
|
+
"commits. While it is open, omitting it continues the contract; a " +
|
|
211
|
+
"different proposal is ignored (contract_premature). DECLARATION IS " +
|
|
212
|
+
"STRICT: an item with no bound command, an unknown/disabled command, a " +
|
|
213
|
+
"scope entry outside the workspace, a malformed reference, or a count " +
|
|
214
|
+
"over the limits returns contract_invalid.",
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
path: "worker_results",
|
|
218
|
+
purpose: "Results of sub-agent / worker delegations.",
|
|
219
|
+
when: "Only when work was actually delegated.",
|
|
220
|
+
nature: "report",
|
|
221
|
+
downstream: "Saved with its source and written to the delegation journal; worker " +
|
|
222
|
+
"discoveredConstraints is NOT auto-promoted.",
|
|
223
|
+
toolDescription: "Optional. Results of sub-agent / Worker delegations this round. Each " +
|
|
224
|
+
"entry must declare an outcome. Entries without a valid outcome are " +
|
|
225
|
+
"dropped with a diagnostic. A worker's discoveredConstraints stays in " +
|
|
226
|
+
"this report; to make it a global constraint, submit it in top-level " +
|
|
227
|
+
"discovered_constraints.",
|
|
228
|
+
reportOnly: true,
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
path: "prompt_requests",
|
|
232
|
+
purpose: "Information needs for the next round's prompt.",
|
|
233
|
+
when: "When you know what context the next round will need.",
|
|
234
|
+
nature: "control",
|
|
235
|
+
downstream: "Matched exactly against state items; applied to the next prompt only " +
|
|
236
|
+
"(L0 ignores it). Unmatched entries have no effect.",
|
|
237
|
+
toolDescription: "Optional. Information needs for the NEXT prompt. emphasize entries are " +
|
|
238
|
+
"matched by stable id or normalized-exact text; a paraphrase matches " +
|
|
239
|
+
"nothing. confusion_points are echoed at the top. L0 retry prompts ignore " +
|
|
240
|
+
"both arms. This never becomes long-term knowledge.",
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
path: "compression_checkpoint",
|
|
244
|
+
purpose: "Mark a meaningful work boundary.",
|
|
245
|
+
when: "At a phase/subtask boundary worth a full-state milestone.",
|
|
246
|
+
nature: "report",
|
|
247
|
+
downstream: "Creates an agent-declared milestone and forces an L2 rehydration boundary.",
|
|
248
|
+
toolDescription: "Optional. true at a subtask boundary to create a recoverable milestone " +
|
|
249
|
+
"and force a full-state checkpoint. Pair with checkpoint_label.",
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
path: "checkpoint_label",
|
|
253
|
+
purpose: "A human-readable label for the checkpoint.",
|
|
254
|
+
when: "Only together with compression_checkpoint=true.",
|
|
255
|
+
nature: "report",
|
|
256
|
+
downstream: "Milestone heading in later prompts and the state file.",
|
|
257
|
+
toolDescription: "Optional. Short label for the checkpoint (for example " +
|
|
258
|
+
"'core-model-complete'). Meaningful only when compression_checkpoint=true.",
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
path: "retroactiveClaims",
|
|
262
|
+
purpose: "A claim that an earlier round satisfied a criterion.",
|
|
263
|
+
when: "When you can point at an earlier round's evidence.",
|
|
264
|
+
nature: "claim",
|
|
265
|
+
downstream: "Advisory check against the named round's committed delta; never upgrades a criterion.",
|
|
266
|
+
toolDescription: "Optional. Claims that a PRIOR round satisfied a criterion. The runtime " +
|
|
267
|
+
"checks them against that round's committed evidence and warns when the " +
|
|
268
|
+
"claim is unbacked. Advisory: it never upgrades a criterion by itself.",
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
path: "gate_ids",
|
|
272
|
+
purpose: "Approved gate ids this round's work depended on.",
|
|
273
|
+
when: "Only when policy.gate.enabled is true and an approval was actually obtained.",
|
|
274
|
+
nature: "control",
|
|
275
|
+
downstream: "Checked only when the gate layer is enabled; otherwise saved as an unused report.",
|
|
276
|
+
toolDescription: "Optional. Approved loopforge_gate_check ids this round depended on. " +
|
|
277
|
+
"Enforced only when policy.gate.enabled: a cited, unapproved gate rejects " +
|
|
278
|
+
"the round. Without the gate layer this is saved but has no effect.",
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
path: "outcome",
|
|
282
|
+
purpose: "The declared round outcome.",
|
|
283
|
+
when: "When the round is partial, failed, or blocked (success is derivable).",
|
|
284
|
+
nature: "claim",
|
|
285
|
+
downstream: "Wins over `success` for the stop decision and success-class checks.",
|
|
286
|
+
toolDescription: "Optional. success | partial | failed | blocked. When absent, derived " +
|
|
287
|
+
"from success. A declared non-success outcome suppresses the " +
|
|
288
|
+
"success-class checks even when success=true.",
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
path: "blocker",
|
|
292
|
+
purpose: "A concrete description of what blocks the work.",
|
|
293
|
+
when: "Required when outcome=blocked; useful with stop_reason=blocked.",
|
|
294
|
+
nature: "report",
|
|
295
|
+
downstream: "Stop decision, handoff open risks, and gate classification when enabled.",
|
|
296
|
+
toolDescription: "Optional. A flat blocker description, required when outcome=blocked. " +
|
|
297
|
+
"State what cannot proceed and why; do not use it as a substitute for " +
|
|
298
|
+
"`success=false`.",
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
path: "stop_reason",
|
|
302
|
+
purpose: "Why the agent is stopping.",
|
|
303
|
+
when: "Only when should_continue=false and success=false.",
|
|
304
|
+
nature: "control",
|
|
305
|
+
downstream: "blocked/needs_human_input stop without claiming success; gave_up is the default stop behavior.",
|
|
306
|
+
toolDescription: "Optional. Why the agent is stopping: gave_up | blocked | needs_human_input. " +
|
|
307
|
+
"Only meaningful when should_continue=false and success=false.",
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
path: "no_change_reason",
|
|
311
|
+
purpose: "Why a success claim needs no workspace change.",
|
|
312
|
+
when: "Only when no enabled verification command is configured and the round " +
|
|
313
|
+
"genuinely required no change.",
|
|
314
|
+
nature: "report",
|
|
315
|
+
downstream: "Downgrades the unbacked-success check from warn to info; never creates evidence.",
|
|
316
|
+
toolDescription: "Optional. Reason for claiming success with no machine-verifiable change " +
|
|
317
|
+
"(for example a documentation-only round). Honored only when no enabled " +
|
|
318
|
+
"verification command is configured. Never excuses an open contract.",
|
|
319
|
+
},
|
|
320
|
+
];
|
|
321
|
+
const GUIDE_BY_PATH = new Map(GUIDES.map((guide) => [guide.path, guide]));
|
|
322
|
+
/** Fields that existed in earlier releases and are now unknown. A diagnostic
|
|
323
|
+
* for one of these names explains the removal instead of silently dropping. */
|
|
324
|
+
const RETIRED_FIELDS = {
|
|
325
|
+
progress_estimate: "removed in 3.9.0 — progress is machine-derived; remove this field",
|
|
326
|
+
progress_at_boundary: "removed in 3.9.0 — milestones render a round range, not a percentage",
|
|
327
|
+
success_criteria_remaining: "removed in 3.8 — report criterion claims under execution_report.criterion_claims",
|
|
328
|
+
next_action: "removed in 3.8 — the agent plans; LoopForge does not accept a next-action field",
|
|
329
|
+
};
|
|
330
|
+
export function fieldGuide(path) {
|
|
331
|
+
return GUIDE_BY_PATH.get(path);
|
|
332
|
+
}
|
|
333
|
+
export function fieldGuideDescription(path) {
|
|
334
|
+
return GUIDE_BY_PATH.get(path)?.toolDescription ?? "";
|
|
335
|
+
}
|
|
336
|
+
export function retiredFieldDetail(path) {
|
|
337
|
+
return RETIRED_FIELDS[path];
|
|
338
|
+
}
|
|
339
|
+
/** The current SelfEvaluation + ExecutionReport paths, for a schema-sync test. */
|
|
340
|
+
export function allFieldGuidePaths() {
|
|
341
|
+
return GUIDES.map((guide) => guide.path);
|
|
342
|
+
}
|
|
343
|
+
function firstActiveItem(contract) {
|
|
344
|
+
return contract?.items?.[0] ?? null;
|
|
345
|
+
}
|
|
346
|
+
function firstActiveSubGoal(subGoals) {
|
|
347
|
+
return subGoals.find((item) => item.status !== "done" && item.status !== "canceled") ?? null;
|
|
348
|
+
}
|
|
349
|
+
/** A legal minimal example for a field, or null when the current facts make the
|
|
350
|
+
* field unusable (no real id/command to cite). The renderer omits nulls; it
|
|
351
|
+
* never invents an sg-/rci- reference. */
|
|
352
|
+
export function fieldExample(path, ctx) {
|
|
353
|
+
switch (path) {
|
|
354
|
+
case "success": return false;
|
|
355
|
+
case "output_summary": return "<what was done and how it was verified>";
|
|
356
|
+
case "constraint_violations": return [];
|
|
357
|
+
case "should_continue": return true;
|
|
358
|
+
case "execution_report.files_changed":
|
|
359
|
+
return ["<path whose content or type differs from round start>"];
|
|
360
|
+
case "execution_report.tests_reported":
|
|
361
|
+
return { passed: 0, failed: 0, skipped: 0 };
|
|
362
|
+
case "execution_report.contract_item_claims": {
|
|
363
|
+
const item = firstActiveItem(ctx.activeContract);
|
|
364
|
+
return item ? [{ item_id: item.id, outcome: "met" }] : null;
|
|
365
|
+
}
|
|
366
|
+
case "execution_report.criterion_claims":
|
|
367
|
+
return [{ criterion_id: "<criterion text or cr id from the prompt>", outcome: "met" }];
|
|
368
|
+
case "subgoal_updates": {
|
|
369
|
+
const subGoal = firstActiveSubGoal(ctx.activeSubGoals);
|
|
370
|
+
return subGoal ? [{ id: subGoal.id, status: "done" }] : null;
|
|
371
|
+
}
|
|
372
|
+
case "emerged_subtasks":
|
|
373
|
+
return ["<a new sub-problem that surfaced>"];
|
|
374
|
+
case "discovered_constraints":
|
|
375
|
+
return ["<a constraint later rounds must respect>"];
|
|
376
|
+
case "wrong_assumptions":
|
|
377
|
+
return ["<an assumption from an earlier round that was falsified>"];
|
|
378
|
+
case "objective_refinement":
|
|
379
|
+
return "<what you now understand better about the objective>";
|
|
380
|
+
case "retracted_constraints":
|
|
381
|
+
return ["<constraint text or c-XXXXXXXX id that is no longer valid>"];
|
|
382
|
+
case "revised_success_criteria":
|
|
383
|
+
return [{ old: "<old criterion>", new: "<new criterion>" }];
|
|
384
|
+
case "round_contract": {
|
|
385
|
+
if (!ctx.contractVerificationAvailable || ctx.commands.length === 0)
|
|
386
|
+
return null;
|
|
387
|
+
return {
|
|
388
|
+
work_item: "<the next slice, in one line>",
|
|
389
|
+
items: [{
|
|
390
|
+
description: "<machine-checkable outcome for the next slice>",
|
|
391
|
+
criterion_refs: [],
|
|
392
|
+
subgoal_refs: [],
|
|
393
|
+
verify_with: [ctx.commands[0]],
|
|
394
|
+
}],
|
|
395
|
+
scope: ["<workspace-relative file or directory>"],
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
case "worker_results":
|
|
399
|
+
return [{
|
|
400
|
+
agentId: "<worker id>",
|
|
401
|
+
subAgentType: "general-purpose",
|
|
402
|
+
subTask: "<self-contained subtask you delegated>",
|
|
403
|
+
resultSummary: "<what the worker reported>",
|
|
404
|
+
outcome: "success",
|
|
405
|
+
discoveredConstraints: [],
|
|
406
|
+
}];
|
|
407
|
+
case "prompt_requests":
|
|
408
|
+
return {
|
|
409
|
+
emphasize: ["<exact constraint text or stable id>"],
|
|
410
|
+
confusion_points: ["<what is unclear about the current state>"],
|
|
411
|
+
};
|
|
412
|
+
case "compression_checkpoint": return false;
|
|
413
|
+
case "checkpoint_label": return "<short phase label>";
|
|
414
|
+
case "retroactiveClaims":
|
|
415
|
+
return [{ round: 1, claim: "<what that earlier round satisfied>" }];
|
|
416
|
+
case "gate_ids":
|
|
417
|
+
return ["<approved gateId from loopforge_gate_check>"];
|
|
418
|
+
case "outcome": return "partial";
|
|
419
|
+
case "blocker": return "<what cannot proceed and why>";
|
|
420
|
+
case "stop_reason": return "blocked";
|
|
421
|
+
case "no_change_reason": return "<why no workspace change was needed>";
|
|
422
|
+
default: return null;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
/** Which optional fields are worth showing at this submission point. Core
|
|
426
|
+
* fields and the execution report always are. */
|
|
427
|
+
export function isFieldApplicable(path, facts) {
|
|
428
|
+
const guide = GUIDE_BY_PATH.get(path);
|
|
429
|
+
if (!guide)
|
|
430
|
+
return false;
|
|
431
|
+
if (guide.core || path.startsWith("execution_report.")) {
|
|
432
|
+
if (path === "execution_report.contract_item_claims") {
|
|
433
|
+
return facts.activeContract !== null;
|
|
434
|
+
}
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
switch (path) {
|
|
438
|
+
case "subgoal_updates":
|
|
439
|
+
return firstActiveSubGoal(facts.subGoals) !== null;
|
|
440
|
+
case "round_contract":
|
|
441
|
+
// Applicable either for a first declaration or for the closing round's
|
|
442
|
+
// successor. The example is null while an active contract is open.
|
|
443
|
+
return facts.contractVerificationAvailable;
|
|
444
|
+
case "gate_ids":
|
|
445
|
+
return facts.gateEnabled;
|
|
446
|
+
default:
|
|
447
|
+
return true;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
function statusOfItem(itemId, statuses) {
|
|
451
|
+
return statuses?.items.find((item) => item.itemId === itemId)?.status ?? "pending";
|
|
452
|
+
}
|
|
453
|
+
function renderContractGuidance(ctx) {
|
|
454
|
+
const contract = ctx.activeContract;
|
|
455
|
+
if (contract) {
|
|
456
|
+
const lines = [
|
|
457
|
+
"Active Round Contract — continue it; you do NOT need to restate it:",
|
|
458
|
+
`- ${contract.work_item ? `${contract.work_item} ` : ""}(${contract.id})`,
|
|
459
|
+
];
|
|
460
|
+
const shown = contract.items.slice(0, 5);
|
|
461
|
+
for (const item of shown) {
|
|
462
|
+
const status = statusOfItem(item.id, ctx.itemStatuses);
|
|
463
|
+
const commands = item.verify_with.join(", ") || "<none>";
|
|
464
|
+
lines.push(` - [${item.id}] ${item.description} — ${status}; verify via: ${commands}`);
|
|
465
|
+
}
|
|
466
|
+
if (contract.items.length > shown.length) {
|
|
467
|
+
lines.push(` - … and ${contract.items.length - shown.length} more in the Current Task.`);
|
|
468
|
+
}
|
|
469
|
+
lines.push("Claim completed items with `execution_report.contract_item_claims` using the", "rci- ids above. A claim alone leaves an item insufficient; its bound command", "must be observed passing. Omit `round_contract` to continue this contract; a", "different proposal is ignored (contract_premature). If this round closes the", "contract and another slice follows, declare the successor proposal here.");
|
|
470
|
+
return lines;
|
|
471
|
+
}
|
|
472
|
+
if (!ctx.contractVerificationAvailable || ctx.commands.length === 0) {
|
|
473
|
+
return [
|
|
474
|
+
"No enabled after-capable evidence command is configured. Contract items cannot",
|
|
475
|
+
"be machine-verified, so run without a contract and do not declare items.",
|
|
476
|
+
];
|
|
477
|
+
}
|
|
478
|
+
const commands = ctx.commands.slice(0, 3).join(", ");
|
|
479
|
+
return [
|
|
480
|
+
"No active contract. If you can define a machine-checkable next slice, propose one:",
|
|
481
|
+
"```json",
|
|
482
|
+
JSON.stringify({
|
|
483
|
+
round_contract: {
|
|
484
|
+
work_item: "<next slice, one line>",
|
|
485
|
+
items: [{
|
|
486
|
+
description: "<machine-checkable outcome>",
|
|
487
|
+
criterion_refs: [],
|
|
488
|
+
subgoal_refs: [],
|
|
489
|
+
verify_with: [ctx.commands[0]],
|
|
490
|
+
}],
|
|
491
|
+
scope: ["<workspace-relative path>"],
|
|
492
|
+
},
|
|
493
|
+
}, null, 1),
|
|
494
|
+
"```",
|
|
495
|
+
`Usable commands: ${commands}. The proposal activates only after this round commits.`,
|
|
496
|
+
];
|
|
497
|
+
}
|
|
498
|
+
function renderSubGoalGuidance(ctx) {
|
|
499
|
+
const active = ctx.subGoals.filter((item) => item.status !== "done" && item.status !== "canceled");
|
|
500
|
+
if (active.length === 0)
|
|
501
|
+
return [];
|
|
502
|
+
const shown = active.slice(0, 5);
|
|
503
|
+
return [
|
|
504
|
+
"Active sub-goals — update only with their real ids:",
|
|
505
|
+
...shown.map((item) => `- [${item.id}] ${item.description} — ${item.status}`),
|
|
506
|
+
"Use `subgoal_updates` for status changes; done/canceled are terminal.",
|
|
507
|
+
];
|
|
508
|
+
}
|
|
509
|
+
function renderOptionalGuidance(ctx) {
|
|
510
|
+
const lines = [];
|
|
511
|
+
const add = (path, ctxForExample) => {
|
|
512
|
+
const example = fieldExample(path, ctxForExample);
|
|
513
|
+
if (example === null)
|
|
514
|
+
return;
|
|
515
|
+
const guide = GUIDE_BY_PATH.get(path);
|
|
516
|
+
if (!guide)
|
|
517
|
+
return;
|
|
518
|
+
lines.push(`- \`${path}\` — ${guide.when}`);
|
|
519
|
+
lines.push(` ${JSON.stringify(example)}`);
|
|
520
|
+
};
|
|
521
|
+
const exampleCtx = {
|
|
522
|
+
activeContract: ctx.activeContract,
|
|
523
|
+
activeSubGoals: ctx.subGoals,
|
|
524
|
+
commands: ctx.commands,
|
|
525
|
+
contractVerificationAvailable: ctx.contractVerificationAvailable,
|
|
526
|
+
};
|
|
527
|
+
add("discovered_constraints", exampleCtx);
|
|
528
|
+
add("wrong_assumptions", exampleCtx);
|
|
529
|
+
if (ctx.level !== "l0") {
|
|
530
|
+
add("objective_refinement", exampleCtx);
|
|
531
|
+
add("emerged_subtasks", exampleCtx);
|
|
532
|
+
add("retracted_constraints", exampleCtx);
|
|
533
|
+
add("revised_success_criteria", exampleCtx);
|
|
534
|
+
add("worker_results", exampleCtx);
|
|
535
|
+
add("prompt_requests", exampleCtx);
|
|
536
|
+
add("compression_checkpoint", exampleCtx);
|
|
537
|
+
add("checkpoint_label", exampleCtx);
|
|
538
|
+
add("retroactiveClaims", exampleCtx);
|
|
539
|
+
add("outcome", exampleCtx);
|
|
540
|
+
add("blocker", exampleCtx);
|
|
541
|
+
add("stop_reason", exampleCtx);
|
|
542
|
+
add("no_change_reason", exampleCtx);
|
|
543
|
+
if (ctx.gateEnabled)
|
|
544
|
+
add("gate_ids", exampleCtx);
|
|
545
|
+
}
|
|
546
|
+
return lines;
|
|
547
|
+
}
|
|
548
|
+
function renderFlagGuidance(flags) {
|
|
549
|
+
if (flags.length === 0)
|
|
550
|
+
return [];
|
|
551
|
+
const fields = [...new Set(flags.map((flag) => flag.field).filter(Boolean))];
|
|
552
|
+
const lines = [
|
|
553
|
+
"This submission is a retry or recovery. The previous findings name these fields:",
|
|
554
|
+
...fields.slice(0, 8).map((field) => {
|
|
555
|
+
const guide = GUIDE_BY_PATH.get(field);
|
|
556
|
+
return `- \`${field}\`${guide ? ` — ${guide.purpose}` : ""}`;
|
|
557
|
+
}),
|
|
558
|
+
];
|
|
559
|
+
lines.push("Correct the relevant field(s) in the same round. If this attempt falsified an", "earlier assumption, record it in `wrong_assumptions`; otherwise omit it.");
|
|
560
|
+
return lines;
|
|
561
|
+
}
|
|
562
|
+
/** Render the evaluation block appended to every prompt. */
|
|
563
|
+
export function renderSelfEvalBlock(ctx) {
|
|
564
|
+
const base = {
|
|
565
|
+
success: false,
|
|
566
|
+
output_summary: "<what was done and how it was verified>",
|
|
567
|
+
constraint_violations: [],
|
|
568
|
+
should_continue: true,
|
|
569
|
+
};
|
|
570
|
+
const reportCtx = {
|
|
571
|
+
activeContract: ctx.activeContract,
|
|
572
|
+
activeSubGoals: ctx.subGoals,
|
|
573
|
+
commands: ctx.commands,
|
|
574
|
+
contractVerificationAvailable: ctx.contractVerificationAvailable,
|
|
575
|
+
};
|
|
576
|
+
const lines = [
|
|
577
|
+
"### LoopForge Evaluation (Required)",
|
|
578
|
+
"",
|
|
579
|
+
`After completing Round ${ctx.round}, submit one evaluation to ` +
|
|
580
|
+
"`loopforge_next.evaluation`.",
|
|
581
|
+
"",
|
|
582
|
+
"Base (always):",
|
|
583
|
+
"```json",
|
|
584
|
+
JSON.stringify(base, null, 2),
|
|
585
|
+
"```",
|
|
586
|
+
"Add the execution report when the round changed files or ran tests:",
|
|
587
|
+
"```json",
|
|
588
|
+
JSON.stringify({
|
|
589
|
+
execution_report: {
|
|
590
|
+
files_changed: fieldExample("execution_report.files_changed", reportCtx),
|
|
591
|
+
tests_reported: fieldExample("execution_report.tests_reported", reportCtx),
|
|
592
|
+
},
|
|
593
|
+
}, null, 1),
|
|
594
|
+
"```",
|
|
595
|
+
"`files_changed` is the net boundary change from round start (content or",
|
|
596
|
+
"file type), including deletions. A commit alone adds no entry when content",
|
|
597
|
+
"is unchanged. Do not list gitignored paths merely to look complete.",
|
|
598
|
+
];
|
|
599
|
+
const optional = renderOptionalGuidance(ctx);
|
|
600
|
+
if (optional.length > 0) {
|
|
601
|
+
lines.push("Optional fields — include ONLY when the event happened; omit otherwise:", ...optional);
|
|
602
|
+
}
|
|
603
|
+
lines.push(...renderContractGuidance(ctx));
|
|
604
|
+
lines.push(...renderSubGoalGuidance(ctx));
|
|
605
|
+
if (ctx.recovery || ctx.verificationFlags.length > 0) {
|
|
606
|
+
lines.push(...renderFlagGuidance(ctx.verificationFlags));
|
|
607
|
+
}
|
|
608
|
+
lines.push("Never invent an id. Use only ids rendered in this prompt; when an id is", "absent, omit the field rather than writing a placeholder id.");
|
|
609
|
+
return lines.join("\n");
|
|
610
|
+
}
|
|
611
|
+
function activeSubGoals(subGoals) {
|
|
612
|
+
return subGoals.filter((item) => item.status !== "done" && item.status !== "canceled");
|
|
613
|
+
}
|
|
614
|
+
/** Derive `submission_guidance` from current facts. Pure: no I/O, no writes,
|
|
615
|
+
* no persistence. The same inputs produce the same object. */
|
|
616
|
+
export function deriveSubmissionGuidance(session, options) {
|
|
617
|
+
const policy = getPolicy();
|
|
618
|
+
const commandsPolicy = policy.evidence?.commands ?? [];
|
|
619
|
+
const capability = deriveConfiguredCapability(policy);
|
|
620
|
+
const commandNames = capability.commands
|
|
621
|
+
.filter((command) => command.enabled)
|
|
622
|
+
.map((command) => command.commandId);
|
|
623
|
+
const level = session.currentLevel === "l0" || session.currentLevel === "l1" ||
|
|
624
|
+
session.currentLevel === "l2"
|
|
625
|
+
? session.currentLevel
|
|
626
|
+
: (session.roundSnapshot?.promptArtifact?.level ??
|
|
627
|
+
session.lastCompileResponse?.prompt_artifact?.level ?? "l2");
|
|
628
|
+
const subGoals = session.lastCompileResponse?.sub_goals ??
|
|
629
|
+
deriveSubGoals({
|
|
630
|
+
loopId: session.loopId,
|
|
631
|
+
currentRound: session.currentRound,
|
|
632
|
+
rounds: options.rounds,
|
|
633
|
+
});
|
|
634
|
+
const facts = deriveRoundFacts({
|
|
635
|
+
rounds: options.rounds,
|
|
636
|
+
currentRound: session.currentRound,
|
|
637
|
+
inFlight: NO_IN_FLIGHT_ROUND,
|
|
638
|
+
subGoals,
|
|
639
|
+
commands: commandsPolicy,
|
|
640
|
+
});
|
|
641
|
+
const activeContract = facts.activeContract;
|
|
642
|
+
const itemStatuses = facts.itemStatuses;
|
|
643
|
+
const guidanceFacts = {
|
|
644
|
+
level,
|
|
645
|
+
activeContract,
|
|
646
|
+
itemStatuses,
|
|
647
|
+
subGoals,
|
|
648
|
+
commands: commandNames,
|
|
649
|
+
contractVerificationAvailable: capability.contractVerificationAvailable,
|
|
650
|
+
gateEnabled: policy.gate?.enabled === true,
|
|
651
|
+
};
|
|
652
|
+
const exampleCtx = {
|
|
653
|
+
activeContract,
|
|
654
|
+
activeSubGoals: activeSubGoals(subGoals),
|
|
655
|
+
commands: commandNames,
|
|
656
|
+
contractVerificationAvailable: capability.contractVerificationAvailable,
|
|
657
|
+
};
|
|
658
|
+
const artifact = session.roundSnapshot?.promptArtifact ??
|
|
659
|
+
session.lastCompileResponse?.prompt_artifact;
|
|
660
|
+
const roundId = session.roundSnapshot?.roundId ??
|
|
661
|
+
`loop:${session.loopId}:round:${session.currentRound}`;
|
|
662
|
+
return {
|
|
663
|
+
round_id: roundId,
|
|
664
|
+
active_contract: activeContract
|
|
665
|
+
? {
|
|
666
|
+
id: activeContract.id,
|
|
667
|
+
...(activeContract.work_item ? { work_item: activeContract.work_item } : {}),
|
|
668
|
+
declared_at_round: activeContract.declared_at_round,
|
|
669
|
+
items: activeContract.items.map((item) => ({
|
|
670
|
+
id: item.id,
|
|
671
|
+
description: item.description,
|
|
672
|
+
status: statusOfItem(item.id, itemStatuses),
|
|
673
|
+
verify_with: [...item.verify_with],
|
|
674
|
+
})),
|
|
675
|
+
}
|
|
676
|
+
: null,
|
|
677
|
+
contract_commands: commandNames,
|
|
678
|
+
contract_verification_available: capability.contractVerificationAvailable,
|
|
679
|
+
subgoals: activeSubGoals(subGoals).map((item) => ({
|
|
680
|
+
id: item.id,
|
|
681
|
+
description: item.description,
|
|
682
|
+
status: item.status,
|
|
683
|
+
})),
|
|
684
|
+
recovery: options.recovery ?? (session.backtrackTargetGitHead
|
|
685
|
+
? {
|
|
686
|
+
required: true,
|
|
687
|
+
restore_point: Math.max(1, session.currentRound - 1),
|
|
688
|
+
target_head: session.backtrackTargetGitHead,
|
|
689
|
+
}
|
|
690
|
+
: null),
|
|
691
|
+
prompt: {
|
|
692
|
+
level,
|
|
693
|
+
dropped_sections: [...(artifact?.droppedSections ?? [])],
|
|
694
|
+
protected_overflow: artifact?.protectedOverflow === true,
|
|
695
|
+
},
|
|
696
|
+
fields: FIELD_ORDER
|
|
697
|
+
.filter((path) => isFieldApplicable(path, guidanceFacts))
|
|
698
|
+
.map((path) => {
|
|
699
|
+
const guide = GUIDE_BY_PATH.get(path);
|
|
700
|
+
return {
|
|
701
|
+
path,
|
|
702
|
+
when: guide.when,
|
|
703
|
+
example: fieldExample(path, exampleCtx),
|
|
704
|
+
effect: guide.downstream,
|
|
705
|
+
};
|
|
706
|
+
}),
|
|
707
|
+
findings: (options.verificationFlags ?? []).map((flag) => ({
|
|
708
|
+
field: flag.field,
|
|
709
|
+
check: flag.check,
|
|
710
|
+
severity: flag.severity,
|
|
711
|
+
detail: flag.detail,
|
|
712
|
+
})),
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
716
|
+
// Submitted-field manifest (used by diagnostics/receipts)
|
|
717
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
718
|
+
const TOP_LEVEL_KNOWN = new Set(GUIDES.map((guide) => guide.path.split(".")[0]));
|
|
719
|
+
const EXECUTION_REPORT_KNOWN = new Set(GUIDES
|
|
720
|
+
.filter((guide) => guide.path.startsWith("execution_report."))
|
|
721
|
+
.map((guide) => guide.path.slice("execution_report.".length)));
|
|
722
|
+
/** The ATTEMPTED manifest: known paths present in the raw payload, in
|
|
723
|
+
* FIELD_ORDER. Presence means the key is an own property with a defined
|
|
724
|
+
* value; an explicit `null` is still an attempt (the normalizer diagnoses
|
|
725
|
+
* whether it survived). Unknown fields are NOT in the manifest; the
|
|
726
|
+
* diagnostic channel owns them. */
|
|
727
|
+
export function submittedFieldPaths(raw) {
|
|
728
|
+
const paths = [];
|
|
729
|
+
const report = raw.execution_report;
|
|
730
|
+
const reportRecord = report && typeof report === "object" && !Array.isArray(report)
|
|
731
|
+
? report
|
|
732
|
+
: null;
|
|
733
|
+
for (const path of FIELD_ORDER) {
|
|
734
|
+
if (path.startsWith("execution_report.")) {
|
|
735
|
+
const key = path.slice("execution_report.".length);
|
|
736
|
+
if (reportRecord &&
|
|
737
|
+
Object.hasOwn(reportRecord, key) &&
|
|
738
|
+
reportRecord[key] !== undefined &&
|
|
739
|
+
EXECUTION_REPORT_KNOWN.has(key)) {
|
|
740
|
+
paths.push(path);
|
|
741
|
+
}
|
|
742
|
+
continue;
|
|
743
|
+
}
|
|
744
|
+
if (Object.hasOwn(raw, path) && raw[path] !== undefined && TOP_LEVEL_KNOWN.has(path)) {
|
|
745
|
+
paths.push(path);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
return paths;
|
|
749
|
+
}
|
|
750
|
+
export function unknownExecutionReportEntryFields(report) {
|
|
751
|
+
return Object.keys(report)
|
|
752
|
+
.filter((key) => !EXECUTION_REPORT_KNOWN.has(key))
|
|
753
|
+
.sort();
|
|
754
|
+
}
|
|
755
|
+
export function unknownExecutionReportFields(raw) {
|
|
756
|
+
const report = raw.execution_report;
|
|
757
|
+
if (!report || typeof report !== "object" || Array.isArray(report))
|
|
758
|
+
return [];
|
|
759
|
+
return unknownExecutionReportEntryFields(report);
|
|
760
|
+
}
|
|
761
|
+
export function unknownTopLevelFields(raw) {
|
|
762
|
+
return Object.keys(raw)
|
|
763
|
+
.filter((key) => !TOP_LEVEL_KNOWN.has(key))
|
|
764
|
+
.sort();
|
|
765
|
+
}
|
|
766
|
+
//# sourceMappingURL=submission-guidance.js.map
|