loopforge 3.9.4 → 4.0.7
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 +236 -112
- package/dist/audit.d.ts +73 -15
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js +131 -61
- package/dist/audit.js.map +1 -1
- package/dist/canonical-state.d.ts +114 -40
- package/dist/canonical-state.d.ts.map +1 -1
- package/dist/canonical-state.js +276 -182
- package/dist/canonical-state.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +41 -12
- package/dist/cli.js.map +1 -1
- package/dist/cognitive-governance.d.ts +0 -2
- package/dist/cognitive-governance.d.ts.map +1 -1
- package/dist/cognitive-governance.js +0 -4
- package/dist/cognitive-governance.js.map +1 -1
- package/dist/committed-round.d.ts +97 -156
- package/dist/committed-round.d.ts.map +1 -1
- package/dist/committed-round.js +223 -419
- package/dist/committed-round.js.map +1 -1
- package/dist/constraint-lifecycle.d.ts +73 -0
- package/dist/constraint-lifecycle.d.ts.map +1 -0
- package/dist/constraint-lifecycle.js +174 -0
- package/dist/constraint-lifecycle.js.map +1 -0
- package/dist/context-boundary.d.ts +83 -0
- package/dist/context-boundary.d.ts.map +1 -0
- package/dist/context-boundary.js +101 -0
- package/dist/context-boundary.js.map +1 -0
- package/dist/contract-items.d.ts +12 -8
- package/dist/contract-items.d.ts.map +1 -1
- package/dist/contract-items.js +31 -26
- package/dist/contract-items.js.map +1 -1
- package/dist/contract-requirement.d.ts +47 -0
- package/dist/contract-requirement.d.ts.map +1 -0
- package/dist/contract-requirement.js +51 -0
- package/dist/contract-requirement.js.map +1 -0
- package/dist/criterion-status.d.ts +35 -0
- package/dist/criterion-status.d.ts.map +1 -0
- package/dist/criterion-status.js +89 -0
- package/dist/criterion-status.js.map +1 -0
- package/dist/enforcement-gate.d.ts +26 -38
- package/dist/enforcement-gate.d.ts.map +1 -1
- package/dist/enforcement-gate.js +196 -319
- package/dist/enforcement-gate.js.map +1 -1
- package/dist/engine.d.ts +9 -103
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +27 -897
- package/dist/engine.js.map +1 -1
- package/dist/errors.d.ts +41 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +69 -0
- package/dist/errors.js.map +1 -0
- package/dist/evidence-claims.d.ts +33 -31
- package/dist/evidence-claims.d.ts.map +1 -1
- package/dist/evidence-claims.js +58 -72
- package/dist/evidence-claims.js.map +1 -1
- package/dist/evidence-posture-view.d.ts +19 -0
- package/dist/evidence-posture-view.d.ts.map +1 -0
- package/dist/evidence-posture-view.js +116 -0
- package/dist/evidence-posture-view.js.map +1 -0
- package/dist/evidence-posture.d.ts +73 -0
- package/dist/evidence-posture.d.ts.map +1 -0
- package/dist/evidence-posture.js +281 -0
- package/dist/evidence-posture.js.map +1 -0
- package/dist/evidence-provider.d.ts +55 -37
- package/dist/evidence-provider.d.ts.map +1 -1
- package/dist/evidence-provider.js +182 -332
- package/dist/evidence-provider.js.map +1 -1
- package/dist/explain.d.ts +166 -27
- package/dist/explain.d.ts.map +1 -1
- package/dist/explain.js +372 -58
- package/dist/explain.js.map +1 -1
- package/dist/field-accounting.d.ts.map +1 -1
- package/dist/field-accounting.js +3 -22
- package/dist/field-accounting.js.map +1 -1
- package/dist/generate-schema.js +13 -8
- package/dist/generate-schema.js.map +1 -1
- package/dist/git-boundary.d.ts +128 -0
- package/dist/git-boundary.d.ts.map +1 -0
- package/dist/git-boundary.js +625 -0
- package/dist/git-boundary.js.map +1 -0
- package/dist/git-facts.d.ts +22 -0
- package/dist/git-facts.d.ts.map +1 -0
- package/dist/git-facts.js +29 -0
- package/dist/git-facts.js.map +1 -0
- package/dist/git-motion.d.ts +37 -0
- package/dist/git-motion.d.ts.map +1 -0
- package/dist/git-motion.js +59 -0
- package/dist/git-motion.js.map +1 -0
- package/dist/history.d.ts +44 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +77 -0
- package/dist/history.js.map +1 -0
- package/dist/index.d.ts +19 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -4
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +16 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +80 -14
- package/dist/init.js.map +1 -1
- package/dist/loop-compiler.d.ts +39 -23
- package/dist/loop-compiler.d.ts.map +1 -1
- package/dist/loop-compiler.js +368 -565
- package/dist/loop-compiler.js.map +1 -1
- package/dist/loop-store.d.ts +6 -5
- package/dist/loop-store.d.ts.map +1 -1
- package/dist/loop-store.js +153 -35
- package/dist/loop-store.js.map +1 -1
- package/dist/mcp/round-lifecycle.d.ts +255 -81
- package/dist/mcp/round-lifecycle.d.ts.map +1 -1
- package/dist/mcp/round-lifecycle.js +1552 -539
- package/dist/mcp/round-lifecycle.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +42 -18
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/session.d.ts +81 -39
- package/dist/mcp/session.d.ts.map +1 -1
- package/dist/mcp/session.js +956 -282
- package/dist/mcp/session.js.map +1 -1
- package/dist/mcp/submission-boundary.d.ts +23 -31
- package/dist/mcp/submission-boundary.d.ts.map +1 -1
- package/dist/mcp/submission-boundary.js +242 -92
- package/dist/mcp/submission-boundary.js.map +1 -1
- package/dist/mcp/submission-handle.d.ts +66 -0
- package/dist/mcp/submission-handle.d.ts.map +1 -0
- package/dist/mcp/submission-handle.js +173 -0
- package/dist/mcp/submission-handle.js.map +1 -0
- package/dist/mcp/tools.d.ts +17 -7
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +707 -244
- package/dist/mcp/tools.js.map +1 -1
- package/dist/open-question.d.ts +7 -0
- package/dist/open-question.d.ts.map +1 -0
- package/dist/open-question.js +14 -0
- package/dist/open-question.js.map +1 -0
- package/dist/policy-metrics.d.ts +31 -21
- package/dist/policy-metrics.d.ts.map +1 -1
- package/dist/policy-metrics.js +117 -64
- package/dist/policy-metrics.js.map +1 -1
- package/dist/policy.d.ts +11 -39
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +12 -12
- package/dist/policy.js.map +1 -1
- package/dist/progress.d.ts +45 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +136 -0
- package/dist/progress.js.map +1 -0
- package/dist/prompt-assembler.d.ts +20 -6
- package/dist/prompt-assembler.d.ts.map +1 -1
- package/dist/prompt-assembler.js +475 -479
- package/dist/prompt-assembler.js.map +1 -1
- package/dist/prompt-coverage.d.ts +0 -6
- package/dist/prompt-coverage.d.ts.map +1 -1
- package/dist/prompt-coverage.js +4 -8
- package/dist/prompt-coverage.js.map +1 -1
- package/dist/prompt-freshness.d.ts +6 -17
- package/dist/prompt-freshness.d.ts.map +1 -1
- package/dist/prompt-freshness.js +27 -22
- package/dist/prompt-freshness.js.map +1 -1
- package/dist/prompt-policy.d.ts +14 -7
- package/dist/prompt-policy.d.ts.map +1 -1
- package/dist/prompt-policy.js +21 -5
- package/dist/prompt-policy.js.map +1 -1
- package/dist/protocol.d.ts +843 -424
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +73 -102
- package/dist/protocol.js.map +1 -1
- package/dist/recovery-guidance.d.ts +13 -0
- package/dist/recovery-guidance.d.ts.map +1 -0
- package/dist/recovery-guidance.js +15 -0
- package/dist/recovery-guidance.js.map +1 -0
- package/dist/recovery.d.ts +68 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +234 -0
- package/dist/recovery.js.map +1 -0
- package/dist/replay.d.ts +42 -8
- package/dist/replay.d.ts.map +1 -1
- package/dist/replay.js +311 -84
- package/dist/replay.js.map +1 -1
- package/dist/result-facts.d.ts +45 -0
- package/dist/result-facts.d.ts.map +1 -0
- package/dist/result-facts.js +86 -0
- package/dist/result-facts.js.map +1 -0
- package/dist/round-contract.d.ts +38 -8
- package/dist/round-contract.d.ts.map +1 -1
- package/dist/round-contract.js +71 -31
- package/dist/round-contract.js.map +1 -1
- package/dist/round-coordinator.d.ts +41 -89
- package/dist/round-coordinator.d.ts.map +1 -1
- package/dist/round-coordinator.js +250 -267
- package/dist/round-coordinator.js.map +1 -1
- package/dist/round-driver.d.ts +56 -16
- package/dist/round-driver.d.ts.map +1 -1
- package/dist/round-driver.js +225 -39
- package/dist/round-driver.js.map +1 -1
- package/dist/round-facts.d.ts +33 -52
- package/dist/round-facts.d.ts.map +1 -1
- package/dist/round-facts.js +51 -160
- package/dist/round-facts.js.map +1 -1
- package/dist/round-guidance.d.ts +56 -0
- package/dist/round-guidance.d.ts.map +1 -0
- package/dist/round-guidance.js +161 -0
- package/dist/round-guidance.js.map +1 -0
- package/dist/round-outcome.d.ts +21 -0
- package/dist/round-outcome.d.ts.map +1 -0
- package/dist/round-outcome.js +31 -0
- package/dist/round-outcome.js.map +1 -0
- package/dist/round-transaction.d.ts +168 -21
- package/dist/round-transaction.d.ts.map +1 -1
- package/dist/round-transaction.js +837 -38
- package/dist/round-transaction.js.map +1 -1
- package/dist/self-eval.d.ts +37 -61
- package/dist/self-eval.d.ts.map +1 -1
- package/dist/self-eval.js +413 -392
- package/dist/self-eval.js.map +1 -1
- package/dist/storage.d.ts +16 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +54 -4
- package/dist/storage.js.map +1 -1
- package/dist/subgoal-state.d.ts +2 -3
- package/dist/subgoal-state.d.ts.map +1 -1
- package/dist/subgoal-state.js +2 -3
- package/dist/subgoal-state.js.map +1 -1
- package/dist/submission-guidance.d.ts +29 -21
- package/dist/submission-guidance.d.ts.map +1 -1
- package/dist/submission-guidance.js +308 -260
- package/dist/submission-guidance.js.map +1 -1
- package/dist/submission-receipt.d.ts +16 -8
- package/dist/submission-receipt.d.ts.map +1 -1
- package/dist/submission-receipt.js +145 -51
- package/dist/submission-receipt.js.map +1 -1
- package/dist/token-utils.d.ts +28 -7
- package/dist/token-utils.d.ts.map +1 -1
- package/dist/token-utils.js +27 -11
- package/dist/token-utils.js.map +1 -1
- package/dist/transaction-identity.d.ts +9 -0
- package/dist/transaction-identity.d.ts.map +1 -0
- package/dist/transaction-identity.js +69 -0
- package/dist/transaction-identity.js.map +1 -0
- package/dist/verification-actions.d.ts.map +1 -1
- package/dist/verification-actions.js +10 -11
- package/dist/verification-actions.js.map +1 -1
- package/dist/verification-gate.d.ts +23 -47
- package/dist/verification-gate.d.ts.map +1 -1
- package/dist/verification-gate.js +202 -423
- package/dist/verification-gate.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/working-memory.d.ts +187 -0
- package/dist/working-memory.d.ts.map +1 -0
- package/dist/working-memory.js +767 -0
- package/dist/working-memory.js.map +1 -0
- package/dist/workspace-checkpoint.d.ts +88 -0
- package/dist/workspace-checkpoint.d.ts.map +1 -0
- package/dist/workspace-checkpoint.js +326 -0
- package/dist/workspace-checkpoint.js.map +1 -0
- package/dist/workspace-restore.d.ts +68 -0
- package/dist/workspace-restore.d.ts.map +1 -0
- package/dist/workspace-restore.js +604 -0
- package/dist/workspace-restore.js.map +1 -0
- package/dist/workspace.d.ts +0 -9
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +0 -17
- package/dist/workspace.js.map +1 -1
- package/loop_policy.json +4 -18
- package/package.json +68 -68
- package/skills/forge/SKILL.md +212 -0
- package/skills/forge/references/evidence-and-contracts.md +204 -0
- package/skills/forge/references/recovery-and-views.md +188 -0
- package/dist/cognitive-facts.d.ts +0 -30
- package/dist/cognitive-facts.d.ts.map +0 -1
- package/dist/cognitive-facts.js +0 -113
- package/dist/cognitive-facts.js.map +0 -1
- package/dist/loop-extras-parser.d.ts +0 -81
- package/dist/loop-extras-parser.d.ts.map +0 -1
- package/dist/loop-extras-parser.js +0 -213
- package/dist/loop-extras-parser.js.map +0 -1
- package/dist/loop-projection.d.ts +0 -6
- package/dist/loop-projection.d.ts.map +0 -1
- package/dist/loop-projection.js +0 -28
- package/dist/loop-projection.js.map +0 -1
- package/skills/perception/SKILL.md +0 -389
|
@@ -11,48 +11,58 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { deriveConfiguredCapability, getPolicy, } from "./policy.js";
|
|
13
13
|
import { deriveRoundFacts, NO_IN_FLIGHT_ROUND } from "./round-facts.js";
|
|
14
|
+
import { deriveCriterionStatuses } from "./criterion-status.js";
|
|
14
15
|
import { deriveSubGoals } from "./subgoal-state.js";
|
|
15
16
|
import { verificationActionFor } from "./verification-actions.js";
|
|
17
|
+
import { deriveContractRequirement } from "./contract-requirement.js";
|
|
16
18
|
/** Field order used by the prompt, guidance and receipts. Core fields first,
|
|
17
19
|
* then the execution report, then contract/sub-goal state, then the
|
|
18
20
|
* cognitive/report fields, then terminal fields. Deterministic by design. */
|
|
21
|
+
/** v4.0.3: THE four structural evaluation fields. The MCP input schema, the
|
|
22
|
+
* prompt template and field accounting read this one set. */
|
|
23
|
+
export const CORE_SELF_EVALUATION_FIELDS = new Set([
|
|
24
|
+
"outcome",
|
|
25
|
+
"output_summary",
|
|
26
|
+
"constraint_violations",
|
|
27
|
+
"should_continue",
|
|
28
|
+
]);
|
|
19
29
|
export const FIELD_ORDER = [
|
|
20
|
-
"
|
|
30
|
+
"outcome",
|
|
21
31
|
"output_summary",
|
|
22
32
|
"constraint_violations",
|
|
23
33
|
"should_continue",
|
|
24
34
|
"execution_report.files_changed",
|
|
25
|
-
"execution_report.
|
|
26
|
-
"
|
|
27
|
-
"execution_report.criterion_claims",
|
|
35
|
+
"execution_report.claims",
|
|
36
|
+
"objective_refinement",
|
|
28
37
|
"subgoal_updates",
|
|
29
38
|
"emerged_subtasks",
|
|
30
39
|
"discovered_constraints",
|
|
31
40
|
"wrong_assumptions",
|
|
32
|
-
"
|
|
41
|
+
"open_questions",
|
|
42
|
+
"resolved_open_question_ids",
|
|
33
43
|
"retracted_constraints",
|
|
34
|
-
"revised_success_criteria",
|
|
35
44
|
"round_contract",
|
|
36
45
|
"worker_results",
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"checkpoint_label",
|
|
46
|
+
"subtask_boundary",
|
|
47
|
+
"subtask_boundary_label",
|
|
40
48
|
"retroactiveClaims",
|
|
41
49
|
"gate_ids",
|
|
42
|
-
"outcome",
|
|
43
50
|
"blocker",
|
|
44
|
-
"stop_reason",
|
|
45
51
|
"no_change_reason",
|
|
46
52
|
];
|
|
47
53
|
const GUIDES = [
|
|
48
54
|
{
|
|
49
|
-
path: "
|
|
50
|
-
purpose: "
|
|
51
|
-
when: "Every round.
|
|
55
|
+
path: "outcome",
|
|
56
|
+
purpose: "The ONE round conclusion.",
|
|
57
|
+
when: "Every round. success requires should_continue=false; blocked requires " +
|
|
58
|
+
"should_continue=false and a blocker; partial/failed may continue or stop.",
|
|
52
59
|
nature: "claim",
|
|
53
|
-
downstream: "Stop decision, success trajectory, verification posture
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
downstream: "Stop decision, success trajectory, verification posture, and every read " +
|
|
61
|
+
"surface. It is a claim; a machine observation is what backs it.",
|
|
62
|
+
toolDescription: "Required. success | partial | failed | blocked. success requires " +
|
|
63
|
+
"should_continue=false; blocked requires should_continue=false and a " +
|
|
64
|
+
"non-empty blocker. partial/failed may continue or stop. This is the ONE " +
|
|
65
|
+
"round conclusion.",
|
|
56
66
|
core: true,
|
|
57
67
|
},
|
|
58
68
|
{
|
|
@@ -60,13 +70,15 @@ const GUIDES = [
|
|
|
60
70
|
purpose: "What was actually done this round, not what was attempted.",
|
|
61
71
|
when: "Every round.",
|
|
62
72
|
nature: "report",
|
|
63
|
-
downstream: "
|
|
73
|
+
downstream: "Committed record, state file, audit/replay/explain, and backtrack " +
|
|
74
|
+
"failed-approach facts — never machine evidence or a current-prompt narrative.",
|
|
64
75
|
toolDescription: "Specific, actionable summary of what was DONE this round — not what was " +
|
|
65
76
|
"attempted. Do not restate the plan.",
|
|
66
77
|
core: true,
|
|
67
78
|
},
|
|
68
79
|
{
|
|
69
80
|
path: "constraint_violations",
|
|
81
|
+
array: true,
|
|
70
82
|
purpose: "Hard constraints actually violated this round.",
|
|
71
83
|
when: "Every round; empty when none were violated.",
|
|
72
84
|
nature: "report",
|
|
@@ -87,6 +99,7 @@ const GUIDES = [
|
|
|
87
99
|
},
|
|
88
100
|
{
|
|
89
101
|
path: "execution_report.files_changed",
|
|
102
|
+
array: true,
|
|
90
103
|
purpose: "The boundary net change: paths whose content or file type differs between " +
|
|
91
104
|
"round preparation and this submission, including deleted paths.",
|
|
92
105
|
when: "Every round that changed the workspace. A commit alone adds no entry when content is unchanged.",
|
|
@@ -99,42 +112,43 @@ const GUIDES = [
|
|
|
99
112
|
reportOnly: false,
|
|
100
113
|
},
|
|
101
114
|
{
|
|
102
|
-
path: "execution_report.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
toolDescription: "Self-reported test counts. Informational: the runtime never translates " +
|
|
108
|
-
"an exit code into a test count, and the receipt shows self-report and " +
|
|
109
|
-
"command observation separately.",
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
path: "execution_report.contract_item_claims",
|
|
113
|
-
purpose: "Claims about items of the ACTIVE Round Contract.",
|
|
114
|
-
when: "Only when an active contract is open; cite the rci-XXXXXXXX ids rendered in the prompt.",
|
|
115
|
+
path: "execution_report.claims",
|
|
116
|
+
array: true,
|
|
117
|
+
purpose: "Claims about objective criteria and ACTIVE contract items, in one channel.",
|
|
118
|
+
when: "When you want to declare which criteria or active contract items are met " +
|
|
119
|
+
"or still remaining; cite real cr-/rci- ids from this prompt.",
|
|
115
120
|
nature: "claim",
|
|
116
|
-
decision: "Claim
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
"
|
|
121
|
+
decision: "Claim criteria or active contract items with their real cr-/rci- ids",
|
|
122
|
+
compact: true,
|
|
123
|
+
promptRank: 10,
|
|
124
|
+
downstream: "`cr-` advisory; `rci-` strict; only machine commands verify.",
|
|
125
|
+
toolDescription: "One claims channel. Each entry is { id, outcome } where id is a " +
|
|
126
|
+
"cr-XXXXXXXX objective criterion id or an rci-XXXXXXXX item id of the " +
|
|
127
|
+
"ACTIVE contract, and outcome is met | remaining. cr- claims are " +
|
|
128
|
+
"advisory (unknown/malformed entries are dropped); rci- claims are strict " +
|
|
129
|
+
"(unknown/duplicate ids are contract_invalid). A claim never verifies " +
|
|
130
|
+
"anything by itself — the runtime marks an item verified only when its " +
|
|
131
|
+
"bound commands are observed passing.",
|
|
122
132
|
},
|
|
123
133
|
{
|
|
124
|
-
path: "
|
|
125
|
-
purpose: "
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
134
|
+
path: "objective_refinement",
|
|
135
|
+
purpose: "The Agent's working version of the OVERALL starting objective — not the " +
|
|
136
|
+
"current round, not the contract.",
|
|
137
|
+
when: "Only when the overall objective genuinely evolved. Omit when unchanged; " +
|
|
138
|
+
"this is event-driven, not a per-round field.",
|
|
139
|
+
nature: "report",
|
|
140
|
+
decision: "Overall objective genuinely evolved (omit when unchanged)",
|
|
129
141
|
compact: true,
|
|
130
|
-
promptRank:
|
|
131
|
-
downstream: "
|
|
132
|
-
toolDescription: "
|
|
133
|
-
"
|
|
134
|
-
"
|
|
142
|
+
promptRank: 15,
|
|
143
|
+
downstream: "Updates the working objective text; never acceptance, criteria or constraints.",
|
|
144
|
+
toolDescription: "Optional, at most 1000 chars. A refined statement of the OVERALL " +
|
|
145
|
+
"starting objective when understanding genuinely changed. It never " +
|
|
146
|
+
"rewrites the operator acceptance, criteria or hard constraints, and it " +
|
|
147
|
+
"is not the round task or contract. Omit when the objective is unchanged.",
|
|
135
148
|
},
|
|
136
149
|
{
|
|
137
150
|
path: "subgoal_updates",
|
|
151
|
+
array: true,
|
|
138
152
|
purpose: "Explicit status transitions for existing sub-goals.",
|
|
139
153
|
when: "When an active sg-XXXXXXXX sub-goal starts, is blocked, completes, or is canceled.",
|
|
140
154
|
nature: "transition",
|
|
@@ -148,143 +162,171 @@ const GUIDES = [
|
|
|
148
162
|
},
|
|
149
163
|
{
|
|
150
164
|
path: "emerged_subtasks",
|
|
151
|
-
|
|
152
|
-
|
|
165
|
+
array: true,
|
|
166
|
+
purpose: "New execution-plan work that the active criteria/contract do not already cover.",
|
|
167
|
+
when: "Only when new work appears or an existing work item must be split. Zero " +
|
|
168
|
+
"is correct when the current criteria/contract already cover the round.",
|
|
153
169
|
nature: "transition",
|
|
154
170
|
decision: "A new sub-problem surfaced (plain text, never sg- ids)",
|
|
155
171
|
compact: true,
|
|
156
172
|
promptRank: 40,
|
|
157
173
|
downstream: "The only sub-goal creation channel; the runtime derives stable sg- ids.",
|
|
158
|
-
toolDescription: "
|
|
159
|
-
"
|
|
174
|
+
toolDescription: "New work that surfaced during execution and was not already covered by " +
|
|
175
|
+
"the active criteria or current contract. The ONLY sub-goal creation " +
|
|
176
|
+
"channel. Plain descriptions, never sg-XXXXXXXX ids. Do not restate the " +
|
|
177
|
+
"criteria as sub-goals; zero entries is a valid result.",
|
|
160
178
|
},
|
|
161
179
|
{
|
|
162
180
|
path: "discovered_constraints",
|
|
181
|
+
array: true,
|
|
163
182
|
purpose: "New constraints that later rounds must respect.",
|
|
164
183
|
when: "When this round discovered a limit that was not known before.",
|
|
165
184
|
nature: "report",
|
|
166
185
|
decision: "You discovered a limit later rounds must respect",
|
|
167
186
|
compact: true,
|
|
168
187
|
promptRank: 20,
|
|
169
|
-
downstream: "Merged into the active constraint set by the compiler
|
|
188
|
+
downstream: "Merged into the active constraint set by the compiler; entries over " +
|
|
189
|
+
"max_discovered_constraints_per_round are diagnosed and dropped at the " +
|
|
190
|
+
"submission boundary.",
|
|
170
191
|
toolDescription: "New constraints that must apply to later rounds. This is the ONLY " +
|
|
171
192
|
"promotion channel for a worker-discovered constraint: a worker result " +
|
|
172
193
|
"stays a report until the main agent states the constraint here.",
|
|
173
194
|
},
|
|
174
195
|
{
|
|
175
196
|
path: "wrong_assumptions",
|
|
197
|
+
array: true,
|
|
176
198
|
purpose: "Assumptions from earlier rounds that this round falsified.",
|
|
177
199
|
when: "When evidence proved an earlier assumption wrong; omit when none.",
|
|
178
200
|
nature: "report",
|
|
179
201
|
decision: "Evidence falsified an earlier assumption",
|
|
180
202
|
compact: true,
|
|
181
203
|
promptRank: 30,
|
|
182
|
-
downstream: "
|
|
204
|
+
downstream: "Bounded Working Memory (fresh prompts and the committed projection), " +
|
|
205
|
+
"recovery brief, replay and explain. Only committed reports reach the " +
|
|
206
|
+
"next prompt.",
|
|
183
207
|
toolDescription: "Assumptions from earlier rounds that turned out to be wrong. Record one " +
|
|
184
208
|
"only when this round actually falsified it; otherwise omit. This is not " +
|
|
185
209
|
"a reflection quota.",
|
|
186
210
|
},
|
|
187
211
|
{
|
|
188
|
-
path: "
|
|
189
|
-
|
|
190
|
-
|
|
212
|
+
path: "open_questions",
|
|
213
|
+
array: true,
|
|
214
|
+
purpose: "Unresolved questions that still affect later slices (a question list, " +
|
|
215
|
+
"not a todo list).",
|
|
216
|
+
when: "Only when a real open question affects how later work should proceed; " +
|
|
217
|
+
"omit when none.",
|
|
191
218
|
nature: "report",
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
219
|
+
reportOnly: true,
|
|
220
|
+
decision: "A question remains open that later slices must resolve",
|
|
221
|
+
compact: true,
|
|
222
|
+
promptRank: 35,
|
|
223
|
+
downstream: "Bounded Working Memory (fresh prompts and the committed projection), " +
|
|
224
|
+
"replay and explain. Strictly report-only: it never enters the " +
|
|
225
|
+
"verification gate, success, contract closure or machine evidence.",
|
|
226
|
+
toolDescription: "Optional. At most 3 unresolved questions, 300 chars each. Record only " +
|
|
227
|
+
"questions that still affect later slices — not a todo list, not a " +
|
|
228
|
+
"completion checklist, and not a substitute for a blocker or decision. " +
|
|
229
|
+
"Report-only: LoopForge never acts on these entries.",
|
|
195
230
|
},
|
|
196
231
|
{
|
|
197
|
-
path: "
|
|
198
|
-
|
|
199
|
-
|
|
232
|
+
path: "resolved_open_question_ids",
|
|
233
|
+
array: true,
|
|
234
|
+
purpose: "Open-question ids that this round resolved.",
|
|
235
|
+
when: "When a previously rendered open question is no longer unresolved.",
|
|
200
236
|
nature: "report",
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
237
|
+
reportOnly: true,
|
|
238
|
+
decision: "A rendered open question was resolved",
|
|
239
|
+
compact: true,
|
|
240
|
+
promptRank: 36,
|
|
241
|
+
downstream: "Working Memory removes the cited question; replay and explain retain the report.",
|
|
242
|
+
toolDescription: "Optional. Use only stable oq-... ids rendered beside open questions in " +
|
|
243
|
+
"Working Memory or the state file. Report-only; it never changes the " +
|
|
244
|
+
"verification gate or acceptance criteria.",
|
|
204
245
|
},
|
|
205
246
|
{
|
|
206
|
-
path: "
|
|
207
|
-
|
|
208
|
-
|
|
247
|
+
path: "retracted_constraints",
|
|
248
|
+
array: true,
|
|
249
|
+
purpose: "Existing constraints that are no longer correct or relevant.",
|
|
250
|
+
when: "When a prior constraint is proven wrong or obsolete.",
|
|
209
251
|
nature: "report",
|
|
210
|
-
downstream: "
|
|
211
|
-
|
|
212
|
-
"
|
|
252
|
+
downstream: "Only active Agent-discovered constraints (including recovery-preserved " +
|
|
253
|
+
"discoveries) are retractable, by c-XXXXXXXX id or normalized-exact text. " +
|
|
254
|
+
"Operator criteria/hard constraints and plan constraints are rejected. " +
|
|
255
|
+
"Unknown/inactive targets are no-ops with a diagnostic.",
|
|
256
|
+
toolDescription: "Optional. Active Agent-discovered constraints that are no longer valid, " +
|
|
257
|
+
"by c-XXXXXXXX id or exact text. Operator criteria/hard constraints and " +
|
|
258
|
+
"plan constraints cannot be retracted. Omit when none.",
|
|
213
259
|
},
|
|
214
260
|
{
|
|
215
261
|
path: "round_contract",
|
|
216
|
-
purpose: "
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
"
|
|
262
|
+
purpose: "THE contract channel: the NEXT round's bounded deliverable and its " +
|
|
263
|
+
"acceptance conditions.",
|
|
264
|
+
when: "When contract coverage requires a next-round contract, or when you want " +
|
|
265
|
+
"to start or replace a slice. With after-capable commands, a continuing " +
|
|
266
|
+
"round with a successor available must leave an active contract; omit to " +
|
|
267
|
+
"continue the current one. The final configured round has no successor.",
|
|
220
268
|
nature: "proposal",
|
|
221
|
-
decision: "
|
|
269
|
+
decision: "The Agent decides the next slice; LoopForge only validates the declaration",
|
|
222
270
|
downstream: "Becomes active only after this round commits; item ids rci-XXXXXXXX are " +
|
|
223
|
-
"derived by the runtime."
|
|
224
|
-
|
|
225
|
-
"
|
|
226
|
-
|
|
227
|
-
"
|
|
228
|
-
"
|
|
229
|
-
"
|
|
230
|
-
"
|
|
271
|
+
"derived by the runtime. `scope` is a report-only intent statement and " +
|
|
272
|
+
"never rejects or blocks a round. `supersedes` closes the named ACTIVE " +
|
|
273
|
+
"contract as `superseded` and activates this proposal next round.",
|
|
274
|
+
toolDescription: "THE contract channel for the NEXT round. work_item is the bounded " +
|
|
275
|
+
"deliverable this slice produces (an outcome, not an activity) and is " +
|
|
276
|
+
"required for a new proposal. items are acceptance conditions; each item " +
|
|
277
|
+
"binds its own verify_with commands and may cite cr- ids in " +
|
|
278
|
+
"criterion_refs. scope is an OPTIONAL, report-only declaration of " +
|
|
279
|
+
"intended files — it is not enforced and is not part of the rc- id. " +
|
|
280
|
+
"While a contract is open, omit this field to continue it unchanged. To " +
|
|
281
|
+
"replace the active slice, add supersedes { contract_id, reason? } with " +
|
|
282
|
+
"the active rc- id and different acceptance items. If the active " +
|
|
283
|
+
"contract closes this round and a successor is available, a successor " +
|
|
284
|
+
"is REQUIRED. The final configured round has no successor consumer. " +
|
|
285
|
+
"DECLARATION IS STRICT: a missing work_item, an item with no bound " +
|
|
286
|
+
"command, an unknown/disabled command, a malformed reference, an " +
|
|
287
|
+
"unknown field, or a count over the limits returns contract_invalid.",
|
|
231
288
|
},
|
|
232
289
|
{
|
|
233
290
|
path: "worker_results",
|
|
291
|
+
array: true,
|
|
234
292
|
purpose: "Results of sub-agent / worker delegations.",
|
|
235
293
|
when: "Only when work was actually delegated.",
|
|
236
294
|
nature: "report",
|
|
237
295
|
decision: "You delegated work",
|
|
238
296
|
compact: true,
|
|
239
297
|
promptRank: 50,
|
|
240
|
-
downstream: "Saved
|
|
241
|
-
"
|
|
298
|
+
downstream: "Saved inside the committed transaction as an audit report. A worker " +
|
|
299
|
+
"finding is not auto-promoted.",
|
|
242
300
|
toolDescription: "Optional. Results of sub-agent / Worker delegations this round. Each " +
|
|
243
301
|
"entry must declare an outcome. Entries without a valid outcome are " +
|
|
244
|
-
"dropped with a diagnostic.
|
|
245
|
-
"
|
|
246
|
-
"discovered_constraints.",
|
|
302
|
+
"dropped with a diagnostic. To make a worker finding a global " +
|
|
303
|
+
"constraint, submit it in top-level discovered_constraints.",
|
|
247
304
|
reportOnly: true,
|
|
248
305
|
},
|
|
249
306
|
{
|
|
250
|
-
path: "
|
|
251
|
-
purpose: "Information needs for the next round's prompt.",
|
|
252
|
-
when: "When you know what context the next round will need.",
|
|
253
|
-
nature: "control",
|
|
254
|
-
decision: "You know what the next prompt needs",
|
|
255
|
-
compact: true,
|
|
256
|
-
promptRank: 70,
|
|
257
|
-
downstream: "Matched exactly against state items; applied to the NEXT round's prompt. " +
|
|
258
|
-
"If that prompt is L0 it is ignored. Unmatched entries have no effect.",
|
|
259
|
-
toolDescription: "Optional. Information needs for the NEXT prompt. emphasize entries are " +
|
|
260
|
-
"matched by stable id or normalized-exact text; a paraphrase matches " +
|
|
261
|
-
"nothing. confusion_points are echoed at the top. They are applied to the " +
|
|
262
|
-
"next round's prompt; if that prompt is L0 they are ignored. This never " +
|
|
263
|
-
"becomes long-term knowledge.",
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
path: "compression_checkpoint",
|
|
307
|
+
path: "subtask_boundary",
|
|
267
308
|
purpose: "Mark a meaningful work boundary.",
|
|
268
|
-
when: "At a
|
|
309
|
+
when: "At a subtask boundary that warrants an L2 rehydration.",
|
|
269
310
|
nature: "report",
|
|
270
|
-
decision: "This round reached a real phase boundary; pair with
|
|
311
|
+
decision: "This round reached a real phase boundary; pair with subtask_boundary_label",
|
|
271
312
|
compact: true,
|
|
272
313
|
promptRank: 60,
|
|
273
|
-
downstream: "
|
|
274
|
-
toolDescription: "Optional. true at a subtask boundary to
|
|
275
|
-
"
|
|
314
|
+
downstream: "Forces an L2 rehydration boundary. It creates no milestone or phase narrative.",
|
|
315
|
+
toolDescription: "Optional. true at a subtask boundary to force an L2 rehydration boundary. " +
|
|
316
|
+
"Pair with subtask_boundary_label.",
|
|
276
317
|
},
|
|
277
318
|
{
|
|
278
|
-
path: "
|
|
279
|
-
purpose: "A human-readable label for the
|
|
280
|
-
when: "Only together with
|
|
319
|
+
path: "subtask_boundary_label",
|
|
320
|
+
purpose: "A human-readable label for the subtask boundary.",
|
|
321
|
+
when: "Only together with subtask_boundary=true.",
|
|
281
322
|
nature: "report",
|
|
282
|
-
downstream: "
|
|
283
|
-
toolDescription: "Optional. Short label for the
|
|
284
|
-
"'core-model-complete'). Meaningful only when
|
|
323
|
+
downstream: "Stored on the committed report; it does not create a later prompt heading.",
|
|
324
|
+
toolDescription: "Optional. Short label for the subtask boundary (for example " +
|
|
325
|
+
"'core-model-complete'). Meaningful only when subtask_boundary=true.",
|
|
285
326
|
},
|
|
286
327
|
{
|
|
287
328
|
path: "retroactiveClaims",
|
|
329
|
+
array: true,
|
|
288
330
|
purpose: "A claim that an earlier round satisfied a criterion.",
|
|
289
331
|
when: "When you can point at an earlier round's evidence.",
|
|
290
332
|
nature: "claim",
|
|
@@ -295,6 +337,7 @@ const GUIDES = [
|
|
|
295
337
|
},
|
|
296
338
|
{
|
|
297
339
|
path: "gate_ids",
|
|
340
|
+
array: true,
|
|
298
341
|
purpose: "Approved gate ids this round's work depended on.",
|
|
299
342
|
when: "Only when policy.gate.enabled is true and an approval was actually obtained.",
|
|
300
343
|
nature: "control",
|
|
@@ -303,34 +346,16 @@ const GUIDES = [
|
|
|
303
346
|
"Enforced only when policy.gate.enabled: a cited, unapproved gate rejects " +
|
|
304
347
|
"the round. Without the gate layer this is saved but has no effect.",
|
|
305
348
|
},
|
|
306
|
-
{
|
|
307
|
-
path: "outcome",
|
|
308
|
-
purpose: "The declared round outcome.",
|
|
309
|
-
when: "When the round is partial, failed, or blocked (success is derivable).",
|
|
310
|
-
nature: "claim",
|
|
311
|
-
downstream: "Wins over `success` for the stop decision and success-class checks.",
|
|
312
|
-
toolDescription: "Optional. success | partial | failed | blocked. When absent, derived " +
|
|
313
|
-
"from success. A declared non-success outcome suppresses the " +
|
|
314
|
-
"success-class checks even when success=true.",
|
|
315
|
-
},
|
|
316
349
|
{
|
|
317
350
|
path: "blocker",
|
|
318
351
|
purpose: "A concrete description of what blocks the work.",
|
|
319
|
-
when: "Required when outcome=blocked;
|
|
352
|
+
when: "Required when outcome=blocked; ignored (with a diagnostic) otherwise.",
|
|
320
353
|
nature: "report",
|
|
321
|
-
downstream: "Stop
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
"
|
|
325
|
-
|
|
326
|
-
{
|
|
327
|
-
path: "stop_reason",
|
|
328
|
-
purpose: "Why the agent is stopping.",
|
|
329
|
-
when: "Only when should_continue=false and success=false.",
|
|
330
|
-
nature: "control",
|
|
331
|
-
downstream: "blocked/needs_human_input stop without claiming success; gave_up is the default stop behavior.",
|
|
332
|
-
toolDescription: "Optional. Why the agent is stopping: gave_up | blocked | needs_human_input. " +
|
|
333
|
-
"Only meaningful when should_continue=false and success=false.",
|
|
354
|
+
downstream: "Stop reason, blocked-contract closure, and gate classification when enabled. " +
|
|
355
|
+
"When work needs human input, say so here with outcome=blocked.",
|
|
356
|
+
toolDescription: "Required when outcome=blocked (trim non-empty, at most 500 chars). State " +
|
|
357
|
+
"what cannot proceed and why. When another outcome is declared it is " +
|
|
358
|
+
"dropped with a diagnostic and never rejects the round.",
|
|
334
359
|
},
|
|
335
360
|
{
|
|
336
361
|
path: "no_change_reason",
|
|
@@ -345,13 +370,31 @@ const GUIDES = [
|
|
|
345
370
|
},
|
|
346
371
|
];
|
|
347
372
|
const GUIDE_BY_PATH = new Map(GUIDES.map((guide) => [guide.path, guide]));
|
|
373
|
+
/** v4.0.3: array-valued evaluation paths, derived from the SAME field
|
|
374
|
+
* metadata the prompt, MCP schema and receipts read. Field accounting uses
|
|
375
|
+
* this set instead of a second hardcoded list. */
|
|
376
|
+
export const ARRAY_SELF_EVALUATION_FIELDS = new Set(GUIDES.filter((guide) => guide.array === true).map((guide) => guide.path));
|
|
348
377
|
/** Fields that existed in earlier releases and are now unknown. A diagnostic
|
|
349
378
|
* for one of these names explains the removal instead of silently dropping. */
|
|
350
379
|
const RETIRED_FIELDS = {
|
|
351
380
|
progress_estimate: "removed in 3.9.0 — progress is machine-derived; remove this field",
|
|
352
381
|
progress_at_boundary: "removed in 3.9.0 — milestones render a round range, not a percentage",
|
|
353
|
-
success_criteria_remaining: "removed in 3.8 — report criterion claims under execution_report.
|
|
382
|
+
success_criteria_remaining: "removed in 3.8 — report criterion claims under execution_report.claims",
|
|
354
383
|
next_action: "removed in 3.8 — the agent plans; LoopForge does not accept a next-action field",
|
|
384
|
+
revised_success_criteria: "removed in 3.9.6 — operator acceptance is immutable; report a conflict in " +
|
|
385
|
+
"wrong_assumptions or stop with outcome=blocked/needs_human_input",
|
|
386
|
+
prompt_requests: "removed in 4.0.1 — the next prompt is compiled from committed facts; " +
|
|
387
|
+
"there is no per-round prompt-steering channel",
|
|
388
|
+
success: "removed in 4.0.6 — use `outcome` (success | partial | failed | blocked)",
|
|
389
|
+
agent_stop_reason: "removed in 4.0.6 — use outcome=blocked with `blocker`; stop with " +
|
|
390
|
+
"outcome=failed and should_continue=false",
|
|
391
|
+
contract_transition: "removed in 4.0.6 — use round_contract.supersedes { contract_id, reason? }",
|
|
392
|
+
tests_reported: "removed in 4.0.6 — command observations are the test fact; do not report counts",
|
|
393
|
+
criterion_claims: "removed in 4.0.6 — use execution_report.claims with cr- ids",
|
|
394
|
+
contract_item_claims: "removed in 4.0.6 — use execution_report.claims with rci- ids",
|
|
395
|
+
"execution_report.tests_reported": "removed in 4.0.6 — command observations are the test fact; remove tests_reported",
|
|
396
|
+
"execution_report.criterion_claims": "removed in 4.0.6 — move these claims into execution_report.claims with cr- ids",
|
|
397
|
+
"execution_report.contract_item_claims": "removed in 4.0.6 — move these claims into execution_report.claims with rci- ids",
|
|
355
398
|
};
|
|
356
399
|
export function fieldGuide(path) {
|
|
357
400
|
return GUIDE_BY_PATH.get(path);
|
|
@@ -372,39 +415,26 @@ function firstActiveItem(contract) {
|
|
|
372
415
|
function firstActiveSubGoal(subGoals) {
|
|
373
416
|
return subGoals.find((item) => item.status !== "done" && item.status !== "canceled") ?? null;
|
|
374
417
|
}
|
|
375
|
-
/** The first criterion the next slice can still work on: `remaining` or
|
|
376
|
-
* `unknown`. `claimed` is the Agent's own completion claim (machine
|
|
377
|
-
* unverified), so it is not a natural NEXT work item. */
|
|
378
|
-
export function outstandingCriterion(criteria) {
|
|
379
|
-
return (criteria ?? []).find((criterion) => criterion.status === "remaining" || criterion.status === "unknown") ?? null;
|
|
380
|
-
}
|
|
381
|
-
function clipContractText(text) {
|
|
382
|
-
const collapsed = (text ?? "").trim().replace(/\s+/g, " ");
|
|
383
|
-
return collapsed.length > 200 ? collapsed.slice(0, 200) : collapsed;
|
|
384
|
-
}
|
|
385
418
|
/** A legal minimal example for a field, or null when the current facts make the
|
|
386
419
|
* field unusable (no real id/command to cite). The renderer omits nulls; it
|
|
387
420
|
* never invents an sg-/rci- reference. */
|
|
388
421
|
export function fieldExample(path, ctx) {
|
|
389
422
|
switch (path) {
|
|
390
|
-
case "
|
|
423
|
+
case "outcome": return "partial";
|
|
391
424
|
case "output_summary": return "<what was done and how it was verified>";
|
|
392
425
|
case "constraint_violations": return [];
|
|
393
426
|
case "should_continue": return true;
|
|
394
427
|
case "execution_report.files_changed":
|
|
395
428
|
return ["<path whose content or type differs from round start>"];
|
|
396
|
-
case "execution_report.
|
|
397
|
-
return { passed: 0, failed: 0, skipped: 0 };
|
|
398
|
-
case "execution_report.contract_item_claims": {
|
|
429
|
+
case "execution_report.claims": {
|
|
399
430
|
const item = firstActiveItem(ctx.activeContract);
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
case "execution_report.criterion_claims": {
|
|
431
|
+
if (item)
|
|
432
|
+
return [{ id: item.id, outcome: "met" }];
|
|
403
433
|
const criterion = ctx.criteria?.[0];
|
|
404
|
-
return criterion
|
|
405
|
-
? [{ criterion_id: criterion.id, outcome: "met" }]
|
|
406
|
-
: null;
|
|
434
|
+
return criterion ? [{ id: criterion.id, outcome: "met" }] : null;
|
|
407
435
|
}
|
|
436
|
+
case "objective_refinement":
|
|
437
|
+
return "<the overall objective as it now stands>";
|
|
408
438
|
case "subgoal_updates": {
|
|
409
439
|
const subGoal = firstActiveSubGoal(ctx.activeSubGoals);
|
|
410
440
|
return subGoal ? [{ id: subGoal.id, status: "done" }] : null;
|
|
@@ -415,54 +445,38 @@ export function fieldExample(path, ctx) {
|
|
|
415
445
|
return ["<a constraint later rounds must respect>"];
|
|
416
446
|
case "wrong_assumptions":
|
|
417
447
|
return ["<an assumption from an earlier round that was falsified>"];
|
|
418
|
-
case "
|
|
419
|
-
return "<
|
|
448
|
+
case "open_questions":
|
|
449
|
+
return ["<an unresolved question that still affects later slices>"];
|
|
450
|
+
case "resolved_open_question_ids":
|
|
451
|
+
return ["oq-<stable id rendered for a question>"];
|
|
420
452
|
case "retracted_constraints":
|
|
421
453
|
return ["<constraint text or c-XXXXXXXX id that is no longer valid>"];
|
|
422
|
-
case "revised_success_criteria":
|
|
423
|
-
return [{ old: "<old criterion>", new: "<new criterion>" }];
|
|
424
454
|
case "round_contract": {
|
|
425
455
|
if (!ctx.contractVerificationAvailable || ctx.commands.length === 0)
|
|
426
456
|
return null;
|
|
427
|
-
const criterion = outstandingCriterion(ctx.criteria);
|
|
428
|
-
const workItem = clipContractText(ctx.currentRequirement) ||
|
|
429
|
-
"<the current requirement, one line>";
|
|
430
457
|
return {
|
|
431
|
-
work_item:
|
|
458
|
+
work_item: "<bounded deliverable this slice produces>",
|
|
432
459
|
items: [{
|
|
433
|
-
description:
|
|
434
|
-
|
|
435
|
-
: "<machine-checkable outcome for this requirement>",
|
|
436
|
-
criterion_refs: criterion ? [criterion.id] : [],
|
|
437
|
-
subgoal_refs: [],
|
|
460
|
+
description: "<machine-checkable acceptance condition>",
|
|
461
|
+
criterion_refs: [],
|
|
438
462
|
verify_with: [ctx.commands[0]],
|
|
439
463
|
}],
|
|
440
|
-
scope: ["<workspace-relative file or directory>"],
|
|
441
464
|
};
|
|
442
465
|
}
|
|
443
466
|
case "worker_results":
|
|
444
467
|
return [{
|
|
445
468
|
agentId: "<worker id>",
|
|
446
|
-
subAgentType: "general-purpose",
|
|
447
469
|
subTask: "<self-contained subtask you delegated>",
|
|
448
470
|
resultSummary: "<what the worker reported>",
|
|
449
471
|
outcome: "success",
|
|
450
|
-
discoveredConstraints: [],
|
|
451
472
|
}];
|
|
452
|
-
case "
|
|
453
|
-
|
|
454
|
-
emphasize: ["<exact constraint text or stable id>"],
|
|
455
|
-
confusion_points: ["<what is unclear about the current state>"],
|
|
456
|
-
};
|
|
457
|
-
case "compression_checkpoint": return false;
|
|
458
|
-
case "checkpoint_label": return "<short phase label>";
|
|
473
|
+
case "subtask_boundary": return false;
|
|
474
|
+
case "subtask_boundary_label": return "<short phase label>";
|
|
459
475
|
case "retroactiveClaims":
|
|
460
476
|
return [{ round: 1, claim: "<what that earlier round satisfied>" }];
|
|
461
477
|
case "gate_ids":
|
|
462
478
|
return ["<approved gateId from loopforge_gate_check>"];
|
|
463
|
-
case "outcome": return "partial";
|
|
464
479
|
case "blocker": return "<what cannot proceed and why>";
|
|
465
|
-
case "stop_reason": return "blocked";
|
|
466
480
|
case "no_change_reason": return "<why no workspace change was needed>";
|
|
467
481
|
default: return null;
|
|
468
482
|
}
|
|
@@ -470,7 +484,7 @@ export function fieldExample(path, ctx) {
|
|
|
470
484
|
/** Semantic applicability — the ONE rule, deliberately independent of prompt
|
|
471
485
|
* level. Core fields and the two baseline execution-report fields are always
|
|
472
486
|
* applicable; the rest depend on facts the runtime can actually observe.
|
|
473
|
-
* Future events (delegation, a
|
|
487
|
+
* Future events (delegation, a subtask boundary, a falsified assumption)
|
|
474
488
|
* remain conditional opportunities, not render-time facts. */
|
|
475
489
|
export function isFieldApplicable(path, facts) {
|
|
476
490
|
const guide = GUIDE_BY_PATH.get(path);
|
|
@@ -480,21 +494,18 @@ export function isFieldApplicable(path, facts) {
|
|
|
480
494
|
return true;
|
|
481
495
|
switch (path) {
|
|
482
496
|
case "execution_report.files_changed":
|
|
483
|
-
case "execution_report.tests_reported":
|
|
484
497
|
return true;
|
|
485
|
-
case "execution_report.
|
|
486
|
-
return facts.activeContract !== null;
|
|
487
|
-
case "
|
|
488
|
-
return
|
|
498
|
+
case "execution_report.claims":
|
|
499
|
+
return facts.activeContract !== null || (facts.criteria ?? []).length > 0;
|
|
500
|
+
case "objective_refinement":
|
|
501
|
+
return true;
|
|
489
502
|
case "subgoal_updates":
|
|
490
503
|
return firstActiveSubGoal(facts.subGoals) !== null;
|
|
491
504
|
case "round_contract":
|
|
492
|
-
//
|
|
493
|
-
//
|
|
494
|
-
//
|
|
495
|
-
return facts.
|
|
496
|
-
facts.contractVerificationAvailable &&
|
|
497
|
-
facts.commands.length > 0;
|
|
505
|
+
// v4.0.6: the contract channel is usable whenever a contract can be
|
|
506
|
+
// verified. The dedicated contract block decides REQUIRED vs continue vs
|
|
507
|
+
// redirect for the current facts.
|
|
508
|
+
return facts.contractVerificationAvailable && facts.commands.length > 0;
|
|
498
509
|
case "gate_ids":
|
|
499
510
|
return facts.gateEnabled;
|
|
500
511
|
case "no_change_reason":
|
|
@@ -506,8 +517,8 @@ export function isFieldApplicable(path, facts) {
|
|
|
506
517
|
/** Compact-checklist membership: the explicit `compact` marker plus semantic
|
|
507
518
|
* applicability. The level is deliberately absent — L0/L1/L2 offer the same
|
|
508
519
|
* evaluation fields; only state density changes. Dedicated renderer fields
|
|
509
|
-
* (`round_contract`, `subgoal_updates
|
|
510
|
-
*
|
|
520
|
+
* (`round_contract`, `subgoal_updates`) are never compact members, so they
|
|
521
|
+
* cannot duplicate their own blocks. */
|
|
511
522
|
export function isFieldPrompted(path, facts) {
|
|
512
523
|
const guide = GUIDE_BY_PATH.get(path);
|
|
513
524
|
if (!guide?.compact)
|
|
@@ -526,10 +537,23 @@ function statusOfItem(itemId, statuses) {
|
|
|
526
537
|
}
|
|
527
538
|
function renderContractGuidance(ctx) {
|
|
528
539
|
const contract = ctx.activeContract;
|
|
540
|
+
const hasCommand = ctx.contractVerificationAvailable && ctx.commands.length > 0;
|
|
541
|
+
// v4.0.6: coverage guidance uses the SAME shared rule as the submission
|
|
542
|
+
// boundary and the post-evidence gate. `proposalPresent:false` describes
|
|
543
|
+
// this prompt (no next-round proposal has been committed yet).
|
|
544
|
+
const requirement = deriveContractRequirement({
|
|
545
|
+
shouldContinue: true,
|
|
546
|
+
blocked: false,
|
|
547
|
+
proposalPresent: false,
|
|
548
|
+
activeContract: contract,
|
|
549
|
+
closure: ctx.itemStatuses?.closure ?? "open",
|
|
550
|
+
contractCapability: hasCommand,
|
|
551
|
+
successorRoundAvailable: ctx.maxRounds === undefined || ctx.round < ctx.maxRounds,
|
|
552
|
+
});
|
|
529
553
|
if (contract) {
|
|
530
554
|
const lines = [
|
|
531
|
-
"Active Round Contract —
|
|
532
|
-
`- ${contract.work_item
|
|
555
|
+
"Active Round Contract — it governs this round:",
|
|
556
|
+
`- Deliverable: ${contract.work_item ?? "(not named; legacy contract)"} (${contract.id})`,
|
|
533
557
|
];
|
|
534
558
|
const shown = contract.items.slice(0, 5);
|
|
535
559
|
for (const item of shown) {
|
|
@@ -540,38 +564,48 @@ function renderContractGuidance(ctx) {
|
|
|
540
564
|
if (contract.items.length > shown.length) {
|
|
541
565
|
lines.push(` - … and ${contract.items.length - shown.length} more in the Current Task.`);
|
|
542
566
|
}
|
|
543
|
-
const claimDecision = GUIDE_BY_PATH.get("execution_report.
|
|
544
|
-
?? "Claim
|
|
545
|
-
lines.push(`${claimDecision} via \`execution_report.
|
|
567
|
+
const claimDecision = GUIDE_BY_PATH.get("execution_report.claims")?.decision
|
|
568
|
+
?? "Claim criteria or active contract items with their real cr-/rci- ids";
|
|
569
|
+
lines.push(`${claimDecision} via \`execution_report.claims\`.`, "A claim alone leaves an item insufficient; its bound command must be observed", "passing. Omit `round_contract` to CONTINUE this contract unchanged — a", "different proposal without `supersedes` is rejected as contract_premature.", "To replace this slice, add `round_contract.supersedes` with", `{ contract_id: "${contract.id}" } and DIFFERENT acceptance items in the`, "same proposal. The old contract closes as superseded, its unverified items", "remain in the audit record, the workspace is not restored, and this round", "cannot be completed.", "`scope` is your declared intent — a report, not permission. It is not", "enforced and it is not part of the rc- id.");
|
|
570
|
+
if (requirement.reason === "no_contract_capability") {
|
|
571
|
+
lines.push("No enabled after-capable command is configured now, so this contract's", "items cannot be machine-verified this round and no successor is required.");
|
|
572
|
+
}
|
|
573
|
+
else if (requirement.reason === "no_successor_round") {
|
|
574
|
+
lines.push("This is the final configured round. Do not submit a successor " +
|
|
575
|
+
"round_contract; there is no next round to consume it.");
|
|
576
|
+
}
|
|
577
|
+
else if (requirement.reason === "active_contract_closed") {
|
|
578
|
+
lines.push("This contract is already closed. If you continue, a successor", "`round_contract` is REQUIRED for the next round.");
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
lines.push("If this round closes the contract (every item verified) and you continue,", "a successor `round_contract` is REQUIRED for the next round.");
|
|
582
|
+
}
|
|
546
583
|
return lines;
|
|
547
584
|
}
|
|
548
|
-
if (
|
|
585
|
+
if (requirement.reason === "no_contract_capability") {
|
|
586
|
+
return [
|
|
587
|
+
"No enabled after-capable evidence command is configured — no contract is possible.",
|
|
588
|
+
"If the OVERALL starting objective genuinely evolved, submit `objective_refinement`.",
|
|
589
|
+
];
|
|
590
|
+
}
|
|
591
|
+
if (requirement.reason === "no_successor_round") {
|
|
549
592
|
return [
|
|
550
|
-
"
|
|
551
|
-
"
|
|
593
|
+
"This is the final configured round. Do not submit `round_contract`;",
|
|
594
|
+
"there is no successor round to consume a proposal.",
|
|
552
595
|
];
|
|
553
596
|
}
|
|
554
597
|
const commands = ctx.commands.slice(0, 3).join(", ");
|
|
555
|
-
const proposalDecision = GUIDE_BY_PATH.get("round_contract")?.decision
|
|
556
|
-
?? "No active contract: if the next slice is machine-checkable, declare it";
|
|
557
|
-
// The current requirement — not an invented slice — is the natural work
|
|
558
|
-
// item. Real criterion ids/text and the real command are rendered; the
|
|
559
|
-
// runtime still derives rci- ids and the Agent still decides whether this
|
|
560
|
-
// is the right machine-checkable outcome.
|
|
561
598
|
const example = fieldExample("round_contract", {
|
|
562
599
|
activeContract: null,
|
|
563
600
|
activeSubGoals: ctx.subGoals,
|
|
564
601
|
commands: [...ctx.commands],
|
|
565
602
|
contractVerificationAvailable: true,
|
|
566
603
|
criteria: ctx.criteria,
|
|
567
|
-
currentRequirement: ctx.currentRequirement,
|
|
568
604
|
});
|
|
569
605
|
return [
|
|
570
|
-
"
|
|
571
|
-
"
|
|
572
|
-
"
|
|
573
|
-
"verifies it. The proposal activates only after this round commits.",
|
|
574
|
-
`${proposalDecision} → proposal below:`,
|
|
606
|
+
"No active Round Contract. If you continue, one is REQUIRED for the next",
|
|
607
|
+
"round. You decide the slice and acceptance conditions; LoopForge validates",
|
|
608
|
+
"structure, references and command bindings. Legal shape:",
|
|
575
609
|
"```json",
|
|
576
610
|
JSON.stringify({ round_contract: example }, null, 1),
|
|
577
611
|
"```",
|
|
@@ -637,7 +671,7 @@ function renderCompactTriggers(ctx) {
|
|
|
637
671
|
if (!guide?.decision)
|
|
638
672
|
continue;
|
|
639
673
|
lines.push(`- ${guide.decision} → \`${path}\` → ${guide.downstream}`);
|
|
640
|
-
if (path === "execution_report.
|
|
674
|
+
if (path === "execution_report.claims") {
|
|
641
675
|
lines.push(...criteriaDetailLines(ctx.criteria ?? []));
|
|
642
676
|
}
|
|
643
677
|
}
|
|
@@ -648,9 +682,9 @@ function renderCompactTriggers(ctx) {
|
|
|
648
682
|
* the guidance lookup so the prompt always names the real field. */
|
|
649
683
|
const FLAG_FIELD_PATHS = {
|
|
650
684
|
files_changed: "execution_report.files_changed",
|
|
651
|
-
|
|
652
|
-
criterion_claims: "execution_report.
|
|
653
|
-
contract_item_claims: "execution_report.
|
|
685
|
+
claims: "execution_report.claims",
|
|
686
|
+
criterion_claims: "execution_report.claims",
|
|
687
|
+
contract_item_claims: "execution_report.claims",
|
|
654
688
|
};
|
|
655
689
|
function flagFieldPath(field) {
|
|
656
690
|
return FLAG_FIELD_PATHS[field] ?? field;
|
|
@@ -688,7 +722,7 @@ function renderFlagGuidance(flags, criteria = [], level = "l1") {
|
|
|
688
722
|
lines.push(` → ${entry.label}: ${entry.action} [${check}]`);
|
|
689
723
|
}
|
|
690
724
|
}
|
|
691
|
-
const criterionFinding = flags.some((flag) => flag.field === "execution_report.
|
|
725
|
+
const criterionFinding = flags.some((flag) => flag.field === "execution_report.claims" ||
|
|
692
726
|
flag.field === "criterion_claims" ||
|
|
693
727
|
flag.check === "criteria_claims_unverified" ||
|
|
694
728
|
flag.check === "success_with_remaining_criteria");
|
|
@@ -701,7 +735,7 @@ function renderFlagGuidance(flags, criteria = [], level = "l1") {
|
|
|
701
735
|
/** Render the evaluation block appended to every prompt. */
|
|
702
736
|
export function renderSelfEvalBlock(ctx) {
|
|
703
737
|
const base = {
|
|
704
|
-
|
|
738
|
+
outcome: "partial",
|
|
705
739
|
output_summary: "<what was done and how it was verified>",
|
|
706
740
|
constraint_violations: [],
|
|
707
741
|
should_continue: true,
|
|
@@ -712,7 +746,6 @@ export function renderSelfEvalBlock(ctx) {
|
|
|
712
746
|
commands: ctx.commands,
|
|
713
747
|
contractVerificationAvailable: ctx.contractVerificationAvailable,
|
|
714
748
|
criteria: ctx.criteria ?? [],
|
|
715
|
-
currentRequirement: ctx.currentRequirement,
|
|
716
749
|
};
|
|
717
750
|
const lines = [
|
|
718
751
|
"### LoopForge Evaluation (Required)",
|
|
@@ -724,18 +757,17 @@ export function renderSelfEvalBlock(ctx) {
|
|
|
724
757
|
"```json",
|
|
725
758
|
JSON.stringify(base, null, 2),
|
|
726
759
|
"```",
|
|
727
|
-
"Add the execution report when
|
|
760
|
+
"Add the execution report when files changed or you claim items:",
|
|
728
761
|
"```json",
|
|
729
762
|
JSON.stringify({
|
|
730
763
|
execution_report: {
|
|
731
764
|
files_changed: fieldExample("execution_report.files_changed", reportCtx),
|
|
732
|
-
|
|
765
|
+
claims: fieldExample("execution_report.claims", reportCtx) ?? [],
|
|
733
766
|
},
|
|
734
767
|
}, null, 1),
|
|
735
768
|
"```",
|
|
736
|
-
"`files_changed` is the net
|
|
737
|
-
"
|
|
738
|
-
"is unchanged. Do not list gitignored paths merely to look complete.",
|
|
769
|
+
"`files_changed` is the net change from round start, including deletions.",
|
|
770
|
+
"A commit alone adds nothing; gitignored paths are outside the machine boundary.",
|
|
739
771
|
];
|
|
740
772
|
lines.push(...renderCompactTriggers(ctx));
|
|
741
773
|
lines.push(...renderContractGuidance(ctx));
|
|
@@ -743,7 +775,7 @@ export function renderSelfEvalBlock(ctx) {
|
|
|
743
775
|
if (ctx.recovery || ctx.verificationFlags.length > 0) {
|
|
744
776
|
lines.push(...renderFlagGuidance(ctx.verificationFlags, ctx.criteria ?? [], ctx.level));
|
|
745
777
|
}
|
|
746
|
-
lines.push("Never invent an id
|
|
778
|
+
lines.push("Never invent an id; use only ids rendered here or in `submission_guidance`", "and omit the field when an id is absent.");
|
|
747
779
|
return lines.join("\n");
|
|
748
780
|
}
|
|
749
781
|
function activeSubGoals(subGoals) {
|
|
@@ -758,27 +790,30 @@ export function deriveSubmissionGuidance(session, options) {
|
|
|
758
790
|
const commandNames = capability.commands
|
|
759
791
|
.filter((command) => command.enabled)
|
|
760
792
|
.map((command) => command.commandId);
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
currentRound: session.currentRound,
|
|
770
|
-
rounds: options.rounds,
|
|
771
|
-
});
|
|
793
|
+
// Never invent a prompt level. If no held artifact is observable, the
|
|
794
|
+
// level is unknown; the prompt itself is derived from current facts.
|
|
795
|
+
const level = session.roundSnapshot?.promptArtifact?.level ?? null;
|
|
796
|
+
const subGoals = deriveSubGoals({
|
|
797
|
+
loopId: session.loopId,
|
|
798
|
+
currentRound: session.currentRound,
|
|
799
|
+
rounds: options.rounds,
|
|
800
|
+
});
|
|
772
801
|
const facts = deriveRoundFacts({
|
|
773
802
|
rounds: options.rounds,
|
|
774
803
|
currentRound: session.currentRound,
|
|
775
804
|
inFlight: NO_IN_FLIGHT_ROUND,
|
|
776
|
-
subGoals,
|
|
777
805
|
commands: commandsPolicy,
|
|
778
806
|
});
|
|
779
807
|
const activeContract = facts.activeContract;
|
|
780
808
|
const itemStatuses = facts.itemStatuses;
|
|
781
|
-
const criteria =
|
|
809
|
+
const criteria = options.objective
|
|
810
|
+
? deriveCriterionStatuses({
|
|
811
|
+
rounds: options.rounds,
|
|
812
|
+
currentRound: session.currentRound,
|
|
813
|
+
objective: options.objective,
|
|
814
|
+
criterionFacts: facts.criterionFacts,
|
|
815
|
+
})
|
|
816
|
+
: [];
|
|
782
817
|
const guidanceFacts = {
|
|
783
818
|
activeContract,
|
|
784
819
|
itemStatuses,
|
|
@@ -794,18 +829,37 @@ export function deriveSubmissionGuidance(session, options) {
|
|
|
794
829
|
commands: commandNames,
|
|
795
830
|
contractVerificationAvailable: capability.contractVerificationAvailable,
|
|
796
831
|
criteria,
|
|
797
|
-
currentRequirement: session.task?.trim() || activeContract?.work_item || "",
|
|
798
832
|
};
|
|
799
|
-
const artifact = session.roundSnapshot?.promptArtifact
|
|
800
|
-
session.lastCompileResponse?.prompt_artifact;
|
|
801
|
-
const roundId = session.roundSnapshot?.roundId ??
|
|
802
|
-
`loop:${session.loopId}:round:${session.currentRound}`;
|
|
833
|
+
const artifact = session.roundSnapshot?.promptArtifact;
|
|
803
834
|
return {
|
|
804
|
-
|
|
835
|
+
contract_requirement: (() => {
|
|
836
|
+
const requirement = deriveContractRequirement({
|
|
837
|
+
shouldContinue: true,
|
|
838
|
+
blocked: false,
|
|
839
|
+
proposalPresent: false,
|
|
840
|
+
activeContract,
|
|
841
|
+
closure: itemStatuses.closure,
|
|
842
|
+
contractCapability: capability.contractVerificationAvailable,
|
|
843
|
+
successorRoundAvailable: session.maxRounds === undefined || session.currentRound < session.maxRounds,
|
|
844
|
+
});
|
|
845
|
+
return {
|
|
846
|
+
required_on_continue: requirement.required,
|
|
847
|
+
successor_required_if_closed: activeContract !== null && capability.contractVerificationAvailable &&
|
|
848
|
+
session.currentRound < (session.maxRounds ?? Number.POSITIVE_INFINITY),
|
|
849
|
+
reason: requirement.reason === "active_contract_closed" ||
|
|
850
|
+
requirement.reason === "active_contract_continues" ||
|
|
851
|
+
requirement.reason === "no_contract_capability" ||
|
|
852
|
+
requirement.reason === "no_successor_round"
|
|
853
|
+
? requirement.reason
|
|
854
|
+
: "no_active_contract",
|
|
855
|
+
active_contract_id: activeContract?.id ?? null,
|
|
856
|
+
};
|
|
857
|
+
})(),
|
|
805
858
|
active_contract: activeContract
|
|
806
859
|
? {
|
|
807
860
|
id: activeContract.id,
|
|
808
861
|
...(activeContract.work_item ? { work_item: activeContract.work_item } : {}),
|
|
862
|
+
scope: [...activeContract.scope],
|
|
809
863
|
declared_at_round: activeContract.declared_at_round,
|
|
810
864
|
items: activeContract.items.map((item) => ({
|
|
811
865
|
id: item.id,
|
|
@@ -827,13 +881,7 @@ export function deriveSubmissionGuidance(session, options) {
|
|
|
827
881
|
text: criterion.text,
|
|
828
882
|
status: criterion.status,
|
|
829
883
|
})),
|
|
830
|
-
recovery: options.recovery ??
|
|
831
|
-
? {
|
|
832
|
-
required: true,
|
|
833
|
-
restore_point: Math.max(1, session.currentRound - 1),
|
|
834
|
-
target_head: session.backtrackTargetGitHead,
|
|
835
|
-
}
|
|
836
|
-
: null),
|
|
884
|
+
recovery: options.recovery ?? null,
|
|
837
885
|
prompt: {
|
|
838
886
|
level,
|
|
839
887
|
dropped_sections: [...(artifact?.droppedSections ?? [])],
|