loopforge 3.0.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +126 -143
- package/dist/audit.d.ts +50 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +131 -0
- package/dist/audit.js.map +1 -0
- package/dist/canonical-state.d.ts +98 -23
- package/dist/canonical-state.d.ts.map +1 -1
- package/dist/canonical-state.js +257 -181
- package/dist/canonical-state.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +40 -33
- package/dist/cli.js.map +1 -1
- package/dist/cognitive-facts.d.ts +17 -0
- package/dist/cognitive-facts.d.ts.map +1 -0
- package/dist/cognitive-facts.js +99 -0
- package/dist/cognitive-facts.js.map +1 -0
- package/dist/cognitive-governance.d.ts +25 -33
- package/dist/cognitive-governance.d.ts.map +1 -1
- package/dist/cognitive-governance.js +38 -138
- package/dist/cognitive-governance.js.map +1 -1
- package/dist/committed-round.d.ts +59 -0
- package/dist/committed-round.d.ts.map +1 -0
- package/dist/committed-round.js +222 -0
- package/dist/committed-round.js.map +1 -0
- package/dist/enforcement-gate.d.ts +78 -0
- package/dist/enforcement-gate.d.ts.map +1 -0
- package/dist/enforcement-gate.js +1109 -0
- package/dist/enforcement-gate.js.map +1 -0
- package/dist/engine.d.ts +111 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +887 -0
- package/dist/engine.js.map +1 -0
- package/dist/evidence-claims.d.ts +50 -0
- package/dist/evidence-claims.d.ts.map +1 -0
- package/dist/evidence-claims.js +116 -0
- package/dist/evidence-claims.js.map +1 -0
- package/dist/evidence-provider.d.ts +50 -23
- package/dist/evidence-provider.d.ts.map +1 -1
- package/dist/evidence-provider.js +167 -50
- package/dist/evidence-provider.js.map +1 -1
- package/dist/generate-schema.js +1 -84
- package/dist/generate-schema.js.map +1 -1
- package/dist/index.d.ts +19 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -15
- package/dist/index.js.map +1 -1
- package/dist/loop-compiler.d.ts +58 -3
- package/dist/loop-compiler.d.ts.map +1 -1
- package/dist/loop-compiler.js +841 -304
- package/dist/loop-compiler.js.map +1 -1
- package/dist/loop-extras-parser.d.ts +2 -2
- package/dist/loop-extras-parser.d.ts.map +1 -1
- package/dist/loop-extras-parser.js +2 -2
- package/dist/loop-extras-parser.js.map +1 -1
- package/dist/loop-projection.d.ts +6 -0
- package/dist/loop-projection.d.ts.map +1 -0
- package/dist/loop-projection.js +26 -0
- package/dist/loop-projection.js.map +1 -0
- package/dist/loop-store.d.ts +115 -24
- package/dist/loop-store.d.ts.map +1 -1
- package/dist/loop-store.js +365 -218
- package/dist/loop-store.js.map +1 -1
- package/dist/mcp/round-lifecycle.d.ts +214 -0
- package/dist/mcp/round-lifecycle.d.ts.map +1 -0
- package/dist/mcp/round-lifecycle.js +935 -0
- package/dist/mcp/round-lifecycle.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +29 -43
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/session.d.ts +64 -101
- package/dist/mcp/session.d.ts.map +1 -1
- package/dist/mcp/session.js +433 -1110
- package/dist/mcp/session.js.map +1 -1
- package/dist/mcp/tools.d.ts +20 -11
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +587 -413
- package/dist/mcp/tools.js.map +1 -1
- package/dist/policy-metrics.d.ts +12 -24
- package/dist/policy-metrics.d.ts.map +1 -1
- package/dist/policy-metrics.js +78 -184
- package/dist/policy-metrics.js.map +1 -1
- package/dist/policy.d.ts +61 -50
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +48 -146
- package/dist/policy.js.map +1 -1
- package/dist/prompt-assembler.d.ts +37 -6
- package/dist/prompt-assembler.d.ts.map +1 -1
- package/dist/prompt-assembler.js +487 -278
- package/dist/prompt-assembler.js.map +1 -1
- package/dist/prompt-policy.d.ts +1 -8
- package/dist/prompt-policy.d.ts.map +1 -1
- package/dist/prompt-policy.js +8 -26
- package/dist/prompt-policy.js.map +1 -1
- package/dist/protocol.d.ts +398 -236
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +147 -17
- package/dist/protocol.js.map +1 -1
- package/dist/replay.d.ts +5 -13
- package/dist/replay.d.ts.map +1 -1
- package/dist/replay.js +32 -69
- package/dist/replay.js.map +1 -1
- package/dist/round-contract.d.ts +64 -0
- package/dist/round-contract.d.ts.map +1 -0
- package/dist/round-contract.js +80 -0
- package/dist/round-contract.js.map +1 -0
- package/dist/round-coordinator.d.ts +23 -25
- package/dist/round-coordinator.d.ts.map +1 -1
- package/dist/round-coordinator.js +103 -92
- package/dist/round-coordinator.js.map +1 -1
- package/dist/round-driver.d.ts +13 -13
- package/dist/round-driver.d.ts.map +1 -1
- package/dist/round-driver.js +25 -14
- package/dist/round-driver.js.map +1 -1
- package/dist/round-transaction.d.ts +14 -18
- package/dist/round-transaction.d.ts.map +1 -1
- package/dist/round-transaction.js +37 -47
- package/dist/round-transaction.js.map +1 -1
- package/dist/self-eval.d.ts +48 -0
- package/dist/self-eval.d.ts.map +1 -0
- package/dist/self-eval.js +248 -0
- package/dist/self-eval.js.map +1 -0
- package/dist/storage.d.ts +9 -4
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +18 -6
- package/dist/storage.js.map +1 -1
- package/dist/token-utils.d.ts +15 -3
- package/dist/token-utils.d.ts.map +1 -1
- package/dist/token-utils.js +24 -5
- package/dist/token-utils.js.map +1 -1
- package/dist/verification-gate.d.ts +149 -0
- package/dist/verification-gate.d.ts.map +1 -0
- package/dist/verification-gate.js +1343 -0
- package/dist/verification-gate.js.map +1 -0
- package/dist/workspace.d.ts +29 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +61 -0
- package/dist/workspace.js.map +1 -0
- package/loop_policy.json +37 -16
- package/package.json +5 -10
- package/skills/perception/SKILL.md +184 -202
- package/dist/canonical-event-writer.d.ts +0 -20
- package/dist/canonical-event-writer.d.ts.map +0 -1
- package/dist/canonical-event-writer.js +0 -131
- package/dist/canonical-event-writer.js.map +0 -1
- package/dist/compiler-subgoals.d.ts +0 -7
- package/dist/compiler-subgoals.d.ts.map +0 -1
- package/dist/compiler-subgoals.js +0 -93
- package/dist/compiler-subgoals.js.map +0 -1
- package/dist/derive-id.d.ts +0 -12
- package/dist/derive-id.d.ts.map +0 -1
- package/dist/derive-id.js +0 -31
- package/dist/derive-id.js.map +0 -1
- package/dist/mcp/session-projection.d.ts +0 -5
- package/dist/mcp/session-projection.d.ts.map +0 -1
- package/dist/mcp/session-projection.js +0 -18
- package/dist/mcp/session-projection.js.map +0 -1
- package/dist/mcp/session-queue.d.ts +0 -3
- package/dist/mcp/session-queue.d.ts.map +0 -1
- package/dist/mcp/session-queue.js +0 -18
- package/dist/mcp/session-queue.js.map +0 -1
- package/dist/mcp/session-types.d.ts +0 -72
- package/dist/mcp/session-types.d.ts.map +0 -1
- package/dist/mcp/session-types.js +0 -2
- package/dist/mcp/session-types.js.map +0 -1
- package/dist/round-commit-store.d.ts +0 -12
- package/dist/round-commit-store.d.ts.map +0 -1
- package/dist/round-commit-store.js +0 -13
- package/dist/round-commit-store.js.map +0 -1
- package/dist/round-gate.d.ts +0 -31
- package/dist/round-gate.d.ts.map +0 -1
- package/dist/round-gate.js +0 -259
- package/dist/round-gate.js.map +0 -1
- package/dist/round-recovery.d.ts +0 -17
- package/dist/round-recovery.d.ts.map +0 -1
- package/dist/round-recovery.js +0 -117
- package/dist/round-recovery.js.map +0 -1
- package/dist/round-report.d.ts +0 -16
- package/dist/round-report.d.ts.map +0 -1
- package/dist/round-report.js +0 -401
- package/dist/round-report.js.map +0 -1
- package/dist/runtime-services.d.ts +0 -59
- package/dist/runtime-services.d.ts.map +0 -1
- package/dist/runtime-services.js +0 -460
- package/dist/runtime-services.js.map +0 -1
- package/dist/vault-format.d.ts +0 -4
- package/dist/vault-format.d.ts.map +0 -1
- package/dist/vault-format.js +0 -4
- package/dist/vault-format.js.map +0 -1
- package/dist/vault-types.d.ts +0 -24
- package/dist/vault-types.d.ts.map +0 -1
- package/dist/vault-types.js +0 -2
- package/dist/vault-types.js.map +0 -1
- package/loopforge-policy.json +0 -340
package/README.md
CHANGED
|
@@ -1,13 +1,81 @@
|
|
|
1
|
-
# LoopForge
|
|
1
|
+
# LoopForge
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
task's objective, constraints, evidence, decisions and recovery state stable
|
|
5
|
-
across many Agent-driven rounds.
|
|
3
|
+
**A context window is not memory. Memory needs a runtime.**
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
> **v3.6.0** — `npm install -g loopforge`. Node.js ≥ 18. Zero runtime dependencies.
|
|
6
|
+
> [中文文档](../README.zh-CN.md)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## The real problems with long-horizon tasks
|
|
11
|
+
|
|
12
|
+
Any AI coding agent, given a long enough task, hits three walls. Not because the model isn't smart enough. Not because the context window isn't large enough. These are **architectural** problems.
|
|
13
|
+
|
|
14
|
+
### Problem 1: The summary cascade
|
|
15
|
+
|
|
16
|
+
Context fills up → compress. Fills up again → compress again. The third compression is a summary of a summary of a summary. Every cycle evaporates information — critical constraints get silently deleted because the summarizer judged them "no longer relevant." Researchers found that after 3–4 summary cycles, constraint violation rates spike from 0% to 59%. The agent doesn't know what it forgot, because the forgetting itself was compressed away.
|
|
17
|
+
|
|
18
|
+
### Problem 2: Self-correction doesn't work
|
|
19
|
+
|
|
20
|
+
Models cannot reliably improve themselves through introspection — they talk themselves out of correct answers. Effective recovery requires an **external verifier** — an independent observer that doesn't share the agent's context, doesn't participate in its reasoning, and only looks at inputs and outputs.
|
|
21
|
+
|
|
22
|
+
### Problem 3: Compound error (p^N)
|
|
23
|
+
|
|
24
|
+
If each step succeeds with probability p, N sequential steps succeed with probability p^N. Frontier agents nail nearly 100% of tasks under 4 minutes but crater to under 10% on tasks over 4 hours. Small errors at each step become the correct input for the next step.
|
|
25
|
+
|
|
26
|
+
**These three problems amplify each other. The summary cascade loses information → lost information becomes errors → the agent can't self-correct because those errors look reasonable within its own context.**
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## What LoopForge does about it
|
|
31
|
+
|
|
32
|
+
LoopForge runs outside the agent and owns the boundary between rounds. Its
|
|
33
|
+
design has two explicit sources:
|
|
34
|
+
|
|
35
|
+
- **One factual source:** committed typed round documents in the Vault.
|
|
36
|
+
- **One cognitive source:** Canonical State compiled from those facts.
|
|
37
|
+
|
|
38
|
+
`loopforge_next` accepts a structured evaluation. The core fields `success`,
|
|
39
|
+
`output_summary`, `constraint_violations`, and `should_continue` are strict;
|
|
40
|
+
optional fields are normalized. Invalid input returns `evaluation_invalid` and
|
|
41
|
+
can be corrected with the same `roundId` without saving session state, writing
|
|
42
|
+
a round, entering either gate, or changing metrics.
|
|
43
|
+
|
|
44
|
+
Valid submissions pass through evidence collection, 27 verification checks,
|
|
45
|
+
and 14 enforcement rules. Only an allowed round joins committed history. The
|
|
46
|
+
shared internal `CommittedRoundView` gives Replay, Audit, Metrics, contracts,
|
|
47
|
+
the compiler, and gate history one decoder and one filtering policy. It does
|
|
48
|
+
not create another storage format.
|
|
49
|
+
|
|
50
|
+
The compiler evolves Canonical State from committed history, then derives
|
|
51
|
+
focus, todo, phase, delegation, and handoff for prompts and status views. The
|
|
52
|
+
next prompt therefore comes from typed cognitive state, not from a summary of
|
|
53
|
+
the previous prompt.
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
Traditional: prompt -> summary -> next prompt -> another summary
|
|
57
|
+
LoopForge: committed rounds -> Canonical State -> next prompt
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The verification gate compares claims with Git snapshots, test output, and
|
|
61
|
+
configured command evidence. The enforcement gate can accept, reject,
|
|
62
|
+
backtrack, or terminate. A rejected submission commits nothing. R4 and R5 can
|
|
63
|
+
restore the last clean round, inject a diagnosis, and verify workspace
|
|
64
|
+
restoration before work continues.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## What LoopForge is not
|
|
69
|
+
|
|
70
|
+
- **Not a memory database.** The optional state file is derived. Committed
|
|
71
|
+
rounds hold facts, and Canonical State supplies runtime cognition.
|
|
72
|
+
- **Not a context compressor.** It recompiles prompts from typed state instead
|
|
73
|
+
of compressing the prior prompt.
|
|
74
|
+
- **Not a constraint tracker.** Constraints are one input to external judgment.
|
|
75
|
+
- **Not an agent or unattended executor.** The external agent owns planning,
|
|
76
|
+
code changes, and tool use. LoopForge governs round transitions.
|
|
77
|
+
|
|
78
|
+
---
|
|
11
79
|
|
|
12
80
|
## Install
|
|
13
81
|
|
|
@@ -17,154 +85,69 @@ loopforge init --client claude
|
|
|
17
85
|
claude mcp add loopforge -- npx loopforge mcp
|
|
18
86
|
```
|
|
19
87
|
|
|
20
|
-
|
|
21
|
-
The generic initializer prints an MCP configuration fragment. The package
|
|
22
|
-
requires Node.js 18 or newer and has zero runtime dependencies.
|
|
23
|
-
|
|
24
|
-
## How a loop works
|
|
25
|
-
|
|
26
|
-
1. The Agent calls `loopforge_start` with one objective and its hard constraints.
|
|
27
|
-
2. LoopForge compiles a prompt from canonical state.
|
|
28
|
-
3. The Agent executes that prompt and submits a structured `RoundReport`.
|
|
29
|
-
4. Runtime evidence is checked, the round boundary is enforced, and the result is accepted, rejected, backtracked or stopped.
|
|
30
|
-
5. If work remains, the next prompt is compiled again from committed facts.
|
|
31
|
-
|
|
32
|
-
The report deliberately separates `outcome` (`success`, `partial`, `failed` or
|
|
33
|
-
`blocked`) from `continuation` (`continue` or `stop`). This prevents a local
|
|
34
|
-
round result from being mistaken for completion of the whole objective. The old
|
|
35
|
-
`status` report and free-form evaluation text are not accepted at the public
|
|
36
|
-
boundary.
|
|
37
|
-
|
|
38
|
-
```json
|
|
39
|
-
{
|
|
40
|
-
"format": "loopforge.round-report",
|
|
41
|
-
"outcome": "partial",
|
|
42
|
-
"continuation": "continue",
|
|
43
|
-
"summary": "Implemented the parser and ran focused tests.",
|
|
44
|
-
"violations": [],
|
|
45
|
-
"agentIntent": "Add parser regression coverage next",
|
|
46
|
-
"evidence": {"files": ["src/parser.ts"], "checks": [], "claims": [], "provenance": {}},
|
|
47
|
-
"discoveries": {"wrongAssumptions": [], "emergedWork": [], "facts": [], "newConstraints": []},
|
|
48
|
-
"subGoalEvents": {"completed": [], "blocked": [], "canceled": []}
|
|
49
|
-
}
|
|
50
|
-
```
|
|
88
|
+
Works with Claude Code, Codex CLI, or any MCP-compatible client.
|
|
51
89
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
Focus, Todo, Handoff, progress, failed patterns and prompt diagnostics are
|
|
61
|
-
rebuildable projections, never a competing plan or persistence layer. Compiler
|
|
62
|
-
responses keep those derived views in one `projection` object. The full model,
|
|
63
|
-
the L0/L1/L2 prompt levels and the immutable prompt artifact are described in
|
|
64
|
-
the [project README](https://github.com/kyrielrving11/LoopForge/blob/main/README.md)
|
|
65
|
-
under “Canonical cognitive state” and “One prompt artifact per attempt”.
|
|
66
|
-
|
|
67
|
-
The default store is `.loopforge`. Events are written through the canonical
|
|
68
|
-
writer and receive a monotonic `event_sequence` within each loop. Prompt and
|
|
69
|
-
state hashes make a restart or replay auditable. Markdown state is only a
|
|
70
|
-
replaceable view, not the recovery truth.
|
|
71
|
-
|
|
72
|
-
Evidence collection and recovery are asynchronous. A malformed report is an
|
|
73
|
-
input error; corrupt JSON, an invalid event format, or a sequence gap is a
|
|
74
|
-
`storage_corruption` error and is never auto-repaired. The configured
|
|
75
|
-
`maxRounds` must be a positive integer no greater than the policy limit.
|
|
76
|
-
|
|
77
|
-
## Verification, enforcement and gates
|
|
78
|
-
|
|
79
|
-
Git evidence is enabled by default. Explicit command providers run with an
|
|
80
|
-
executable and argument array (`shell: false`), bounded output, a timeout and a
|
|
81
|
-
workspace path check; required command failures contradict an unsupported
|
|
82
|
-
success claim. Agent claims remain `claimed` until a provider observes them —
|
|
83
|
-
provenance is owned by the runtime, and criteria coverage comes from verified
|
|
84
|
-
claims, never from a progress estimate. A successful report that requests a
|
|
85
|
-
stop is accepted as completion only when a live evidence provider produced
|
|
86
|
-
verifiable evidence; with no provider, completion stays unresolved.
|
|
87
|
-
|
|
88
|
-
Gate checks use `GateActionDescriptor` to make risk explicit: production,
|
|
89
|
-
credentials, data migration, publishing, payment, external communication,
|
|
90
|
-
public API changes, irreversible actions and unknown authorization are User
|
|
91
|
-
Gates; bounded, reversible, explicitly agent-allowed workspace work is an
|
|
92
|
-
Agent Gate. Decisions bind to an `actionHash`, so changing an action
|
|
93
|
-
invalidates an earlier approval.
|
|
94
|
-
|
|
95
|
-
For the full decision semantics — what the gate detects, how enforcement
|
|
96
|
-
decides accept, reject, backtrack and stop — see the corresponding sections in
|
|
97
|
-
the [project README](https://github.com/kyrielrving11/LoopForge/blob/main/README.md).
|
|
98
|
-
|
|
99
|
-
## Recovery semantics
|
|
100
|
-
|
|
101
|
-
A rejected attempt is zero-commit: its report does not enter canonical state.
|
|
102
|
-
`loopforge_retry` keeps the same logical round ID and increments the attempt;
|
|
103
|
-
`loopforge_next` cannot bypass a rejection. `loopforge_backtrack` returns a
|
|
104
|
-
bounded restore point and verification requirements but never changes workspace
|
|
105
|
-
files. Pause and resume preserve the transaction across client or process
|
|
106
|
-
boundaries. Stop records termination without deleting the vault.
|
|
107
|
-
|
|
108
|
-
`agentIntent` is an optional, non-authoritative suggestion retained inside the
|
|
109
|
-
report for audit and drift comparison. It never overwrites Current Focus, Todo,
|
|
110
|
-
runtime progress, completion, or the compiler's Suggested Next Action.
|
|
111
|
-
|
|
112
|
-
Terminal enforcement escalation is tracked per rule. A rule can issue one
|
|
113
|
-
guided retry before a repeated hit terminates it; accepting progress or
|
|
114
|
-
backtracking clears the active rejection episode.
|
|
115
|
-
|
|
116
|
-
## MCP surface
|
|
117
|
-
|
|
118
|
-
The server exposes exactly twelve Agent-driven tools:
|
|
90
|
+
The MCP server path (`loopforge mcp`) is the primary integration. It provides
|
|
91
|
+
the full cognitive infrastructure: verification gate, enforcement gate,
|
|
92
|
+
backtrack, evidence collection, and crash recovery. The engine is also
|
|
93
|
+
available as a library for custom integrations.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Architecture
|
|
119
98
|
|
|
120
99
|
```text
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
100
|
+
External agent
|
|
101
|
+
-> structured evaluation
|
|
102
|
+
-> evidence / verification / enforcement
|
|
103
|
+
-> accept, reject, backtrack, or terminate
|
|
104
|
+
reject / terminate: no round commit
|
|
105
|
+
accept / stop / backtrack: commit transaction decision
|
|
106
|
+
-> committed round documents [factual source]
|
|
107
|
+
-> CommittedRoundView [shared read model]
|
|
108
|
+
-> Replay [what happened]
|
|
109
|
+
-> Audit / Metrics [evidence and diagnostics]
|
|
110
|
+
-> Canonical State [cognitive source]
|
|
111
|
+
-> DerivedCognitiveFacts
|
|
112
|
+
-> prompt / state file / status
|
|
113
|
+
-> external agent, next round
|
|
125
114
|
```
|
|
126
115
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
are asynchronous; corrupt JSON, invalid event formats and sequence gaps return
|
|
151
|
-
`storage_corruption` instead of a partial status. `maxRounds` must be a positive
|
|
152
|
-
integer within the configured policy limit.
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Key capabilities
|
|
119
|
+
|
|
120
|
+
- Structured evaluation with strict core fields, lenient optional normalization,
|
|
121
|
+
and retryable `evaluation_invalid` responses.
|
|
122
|
+
- One committed-round history for the compiler, contracts, gates, Replay,
|
|
123
|
+
Audit, and Metrics.
|
|
124
|
+
- One Canonical State for prompts, the optional state file, and current-status
|
|
125
|
+
cognition.
|
|
126
|
+
- Evidence-backed accept, reject, backtrack, and terminate decisions, including
|
|
127
|
+
Round Contract and workspace-restore checks.
|
|
128
|
+
- L0, L1, and L2 prompt density, five-state sub-goals, constraint lifecycle,
|
|
129
|
+
milestones, and agent-requested emphasis or confusion points.
|
|
130
|
+
- Separate Replay and Audit views. Replay answers what happened; Audit checks
|
|
131
|
+
evidence and completeness.
|
|
132
|
+
- Durable sessions with atomic round documents, sequence checks, owned locks,
|
|
133
|
+
renewable leases, pause, resume, and idempotent recovery.
|
|
134
|
+
- Nine MCP tools: `start`, `next`, `status`, `stop`, `pause`, `resume`, `replay`,
|
|
135
|
+
`gate_check`, and `gate_resolve`.
|
|
136
|
+
- Zero runtime dependencies. Policy controls thresholds, budgets, and intervals.
|
|
137
|
+
|
|
138
|
+
---
|
|
153
139
|
|
|
154
140
|
## Development
|
|
155
141
|
|
|
156
142
|
```bash
|
|
157
143
|
npm run check
|
|
158
144
|
npm test
|
|
159
|
-
npm run
|
|
160
|
-
npm run verify:artifacts
|
|
161
|
-
npm pack --dry-run --json --ignore-scripts
|
|
145
|
+
npm pack --dry-run --json
|
|
162
146
|
```
|
|
163
147
|
|
|
164
|
-
The schema in
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
selected client and prints its MCP registration command.
|
|
148
|
+
The protocol schema in `../loopforge-protocol.json` is generated from `src/protocol.ts`. Do not edit it by hand.
|
|
149
|
+
|
|
150
|
+
---
|
|
168
151
|
|
|
169
152
|
## License
|
|
170
153
|
|
package/dist/audit.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** v2.12: Read-only, replayable end-of-loop audit — the verification view.
|
|
2
|
+
*
|
|
3
|
+
* Positioning vs loopforge_replay: replay is the factual timeline (what
|
|
4
|
+
* happened per round); audit is the assessment layer (which claims are
|
|
5
|
+
* machine-verified, which gates were decided, is the sequence intact).
|
|
6
|
+
* Everything is derived from committed vault entries — audit never writes.
|
|
7
|
+
*/
|
|
8
|
+
import type { LoopStore } from "./loop-store.js";
|
|
9
|
+
import type { VaultEntry } from "./loop-store.js";
|
|
10
|
+
export interface AuditRound {
|
|
11
|
+
round: number;
|
|
12
|
+
outcome: string;
|
|
13
|
+
claims: Array<{
|
|
14
|
+
text: string;
|
|
15
|
+
status: "verified" | "unverified" | "no_evidence";
|
|
16
|
+
}>;
|
|
17
|
+
checks: Array<{
|
|
18
|
+
check: string;
|
|
19
|
+
severity: string;
|
|
20
|
+
verdict: "failed" | "warn" | "info";
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
export interface AuditGate {
|
|
24
|
+
gateId: string;
|
|
25
|
+
kind: "user" | "agent";
|
|
26
|
+
actionHash: string;
|
|
27
|
+
approved: boolean;
|
|
28
|
+
decidedAt: string;
|
|
29
|
+
round: number;
|
|
30
|
+
}
|
|
31
|
+
export interface AuditResult {
|
|
32
|
+
loopId: string;
|
|
33
|
+
verdict: "passed" | "incomplete" | "contradicted";
|
|
34
|
+
rounds: AuditRound[];
|
|
35
|
+
gates: AuditGate[];
|
|
36
|
+
unresolvedUserGates: string[];
|
|
37
|
+
criteria: {
|
|
38
|
+
declared: number;
|
|
39
|
+
evidenced: number;
|
|
40
|
+
missing: number;
|
|
41
|
+
};
|
|
42
|
+
sequenceComplete: boolean;
|
|
43
|
+
/** False when no LoopStore was provided (sequence/provenance degraded). */
|
|
44
|
+
provenanceAvailable: boolean;
|
|
45
|
+
}
|
|
46
|
+
/** Build the audit from committed vault entries. Pure, read-only.
|
|
47
|
+
* @param store Optional LoopStore — when provided, sequence integrity is
|
|
48
|
+
* checked and provenanceAvailable becomes true. */
|
|
49
|
+
export declare function buildAudit(loopId: string, entries: VaultEntry[], store?: LoopStore): AuditResult;
|
|
50
|
+
//# sourceMappingURL=audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAIjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAIlD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,GAAG,YAAY,GAAG,aAAa,CAAA;KAAE,CAAC,CAAC;IACnF,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC,CAAC;CACzF;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,QAAQ,GAAG,YAAY,GAAG,cAAc,CAAC;IAClD,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,QAAQ,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,gBAAgB,EAAE,OAAO,CAAC;IAC1B,2EAA2E;IAC3E,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAMD;;oDAEoD;AACpD,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,UAAU,EAAE,EACrB,KAAK,CAAC,EAAE,SAAS,GAChB,WAAW,CAgHb"}
|
package/dist/audit.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/** v2.12: Read-only, replayable end-of-loop audit — the verification view.
|
|
2
|
+
*
|
|
3
|
+
* Positioning vs loopforge_replay: replay is the factual timeline (what
|
|
4
|
+
* happened per round); audit is the assessment layer (which claims are
|
|
5
|
+
* machine-verified, which gates were decided, is the sequence intact).
|
|
6
|
+
* Everything is derived from committed vault entries — audit never writes.
|
|
7
|
+
*/
|
|
8
|
+
import { eventSequence, StorageCorruptionError } from "./loop-store.js";
|
|
9
|
+
import { auditOrder, deriveGate } from "./cognitive-governance.js";
|
|
10
|
+
import { rederiveClaimViewWithFlags, listVerifiedClaims } from "./evidence-claims.js";
|
|
11
|
+
import { isRecord, entryRound as sharedEntryRound } from "./token-utils.js";
|
|
12
|
+
import { decodeCommittedRound } from "./committed-round.js";
|
|
13
|
+
function entryRound(entry) {
|
|
14
|
+
return sharedEntryRound(entry);
|
|
15
|
+
}
|
|
16
|
+
/** Build the audit from committed vault entries. Pure, read-only.
|
|
17
|
+
* @param store Optional LoopStore — when provided, sequence integrity is
|
|
18
|
+
* checked and provenanceAvailable becomes true. */
|
|
19
|
+
export function buildAudit(loopId, entries, store) {
|
|
20
|
+
const ordered = auditOrder(entries);
|
|
21
|
+
// ── Rounds: per-round claims + checks from committed snapshots ─────────
|
|
22
|
+
const rounds = [];
|
|
23
|
+
for (const entry of ordered) {
|
|
24
|
+
const taskId = String(entry.task_id ?? "");
|
|
25
|
+
if (!taskId.startsWith(`loop:${loopId}:r`) || !taskId.endsWith(":feedback"))
|
|
26
|
+
continue;
|
|
27
|
+
const committed = decodeCommittedRound(entry);
|
|
28
|
+
if (!committed)
|
|
29
|
+
continue;
|
|
30
|
+
// v2.14: rounds committed with action="backtrack" were rolled back —
|
|
31
|
+
// they are not part of the loop's final history. Counting them would
|
|
32
|
+
// inflate the round list and let their error flags flip the verdict.
|
|
33
|
+
if (committed.action === "backtrack")
|
|
34
|
+
continue;
|
|
35
|
+
const round = entryRound(entry);
|
|
36
|
+
const outcome = committed.outcome ?? "unknown";
|
|
37
|
+
const claimView = committed.evaluation
|
|
38
|
+
? rederiveClaimViewWithFlags(committed.evaluation, (committed.afterEvidence.length > 0
|
|
39
|
+
? committed.afterEvidence
|
|
40
|
+
: committed.roundEvidence), committed.verificationFlags)
|
|
41
|
+
: null;
|
|
42
|
+
rounds.push({
|
|
43
|
+
round,
|
|
44
|
+
outcome,
|
|
45
|
+
claims: claimView
|
|
46
|
+
? claimView.claims.map((claim) => ({
|
|
47
|
+
text: claim.targetId,
|
|
48
|
+
status: claim.status === "verified" ? "verified" : "unverified",
|
|
49
|
+
}))
|
|
50
|
+
: [],
|
|
51
|
+
checks: committed.verificationFlags.map((flag) => ({
|
|
52
|
+
check: flag.check,
|
|
53
|
+
severity: flag.severity,
|
|
54
|
+
verdict: flag.severity === "error" ? "failed" : flag.severity,
|
|
55
|
+
})),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// ── Gates: latest decision wins; opened-without-decision stays open ────
|
|
59
|
+
const decisionsByGate = new Map();
|
|
60
|
+
const openedGates = new Map();
|
|
61
|
+
for (const entry of ordered) {
|
|
62
|
+
const gateId = String(entry.gate_id ?? "");
|
|
63
|
+
if (!gateId)
|
|
64
|
+
continue;
|
|
65
|
+
if (entry.task_type === "gate_decision" && isRecord(entry.gate_decision)) {
|
|
66
|
+
const decision = entry.gate_decision;
|
|
67
|
+
decisionsByGate.set(gateId, {
|
|
68
|
+
gateId,
|
|
69
|
+
kind: decision.kind === "agent" ? "agent" : "user",
|
|
70
|
+
actionHash: typeof decision.actionHash === "string" ? decision.actionHash : "",
|
|
71
|
+
approved: decision.approved === true,
|
|
72
|
+
decidedAt: typeof decision.decidedAt === "string" ? decision.decidedAt : "",
|
|
73
|
+
round: entryRound(entry),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else if (entry.task_type === "gate_opened") {
|
|
77
|
+
openedGates.set(gateId, {
|
|
78
|
+
description: typeof entry.gate_action === "string" ? entry.gate_action : gateId,
|
|
79
|
+
round: entryRound(entry),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const gates = [...decisionsByGate.values()];
|
|
84
|
+
const unresolvedUserGates = [];
|
|
85
|
+
for (const [gateId, opened] of openedGates) {
|
|
86
|
+
if (decisionsByGate.has(gateId))
|
|
87
|
+
continue;
|
|
88
|
+
// Re-derive the classification from the recorded action text.
|
|
89
|
+
const { gate } = deriveGate(opened.description);
|
|
90
|
+
if (gate.kind === "user") {
|
|
91
|
+
unresolvedUserGates.push(`${gateId} (round ${opened.round}): ${opened.description}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// ── Sequence integrity (P0) ────────────────────────────────────────────
|
|
95
|
+
let sequenceComplete = true;
|
|
96
|
+
let provenanceAvailable = store !== undefined;
|
|
97
|
+
if (store) {
|
|
98
|
+
try {
|
|
99
|
+
const sequences = eventSequence(store, loopId);
|
|
100
|
+
const max = sequences.length > 0 ? Math.max(...sequences) : 0;
|
|
101
|
+
sequenceComplete = sequences.length === max;
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
sequenceComplete = false;
|
|
105
|
+
if (!(error instanceof StorageCorruptionError))
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// ── Criteria accounting + verdict ──────────────────────────────────────
|
|
110
|
+
const verified = listVerifiedClaims(entries, loopId);
|
|
111
|
+
const declared = rounds.reduce((sum, round) => sum + round.claims.length, 0);
|
|
112
|
+
const evidenced = verified.length;
|
|
113
|
+
let verdict = "passed";
|
|
114
|
+
if (rounds.some((round) => round.checks.some((check) => check.verdict === "failed"))) {
|
|
115
|
+
verdict = "contradicted";
|
|
116
|
+
}
|
|
117
|
+
else if (unresolvedUserGates.length > 0 || (declared > 0 && evidenced === 0)) {
|
|
118
|
+
verdict = "incomplete";
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
loopId,
|
|
122
|
+
verdict,
|
|
123
|
+
rounds,
|
|
124
|
+
gates,
|
|
125
|
+
unresolvedUserGates,
|
|
126
|
+
criteria: { declared, evidenced, missing: Math.max(0, declared - evidenced) },
|
|
127
|
+
sequenceComplete,
|
|
128
|
+
provenanceAvailable,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,16 +3,52 @@
|
|
|
3
3
|
* The canonical state is data, not Markdown. Prompt and state-file renderers
|
|
4
4
|
* consume the same value so they cannot silently drift apart.
|
|
5
5
|
*/
|
|
6
|
-
import type { ConstraintMeta,
|
|
7
|
-
export declare const
|
|
6
|
+
import type { ConstraintMeta, CriterionStatus, Lesson, LoopCompileRequest, LoopCompileResponse, MilestoneSummary, RoundContract, SubGoal, VerificationFlag } from "./protocol.js";
|
|
7
|
+
export declare const CANONICAL_STATE_SCHEMA_VERSION: 1;
|
|
8
|
+
/** v3.2: Durable snapshot of what an L1 prompt actually presented last round.
|
|
9
|
+
* Used as the diff baseline for L1 collapse. Persisted inside the lineage
|
|
10
|
+
* entry's loop_lineage (field extension — no new persistence format) and
|
|
11
|
+
* carried on PromptArtifact for the compile-to-persist round-trip. */
|
|
12
|
+
export interface PresentedStateSnapshot {
|
|
13
|
+
/** Round whose presentation this snapshot describes (the baseline round). */
|
|
14
|
+
round: number;
|
|
15
|
+
/** Stable IDs (c-XXXXXXXX) of constraints rendered in the L1 Active
|
|
16
|
+
* Constraints section (post-emphasize, non-hard). */
|
|
17
|
+
constraintIds: string[];
|
|
18
|
+
/** [sub-goal id, status] pairs rendered in the L1 Active Sub-Goals section
|
|
19
|
+
* (in_progress + pending only). Statuses enable transition detection. */
|
|
20
|
+
subGoals: Array<[string, string]>;
|
|
21
|
+
/** [start, end] round ranges of all milestones at presentation time. */
|
|
22
|
+
milestoneRanges: Array<[number, number]>;
|
|
23
|
+
}
|
|
24
|
+
/** v3.3: Per-round statistics for the display (files changed, rejected
|
|
25
|
+
* attempts, self-reported progress delta). Compiler-derived from committed
|
|
26
|
+
* entries — zero persistence. Optional: absent when no committed rounds. */
|
|
27
|
+
export interface RoundStat {
|
|
28
|
+
round: number;
|
|
29
|
+
filesChangedCount: number | null;
|
|
30
|
+
rejectedAttempts: number | null;
|
|
31
|
+
progressDelta: number | null;
|
|
32
|
+
}
|
|
33
|
+
/** v3.3: Machine git-motion cross-check over the last committed rounds.
|
|
34
|
+
* Display-only companion to the R4/R5 exculpatory signal. Optional:
|
|
35
|
+
* absent when no committed rounds carry git snapshots — the object, when
|
|
36
|
+
* present, always carries definite values (v3.6: the null arms were dead —
|
|
37
|
+
* the derive path returns undefined wholesale instead of null fields). */
|
|
38
|
+
export interface MachineStatus {
|
|
39
|
+
windowRounds: number;
|
|
40
|
+
gitMotion: boolean;
|
|
41
|
+
motionRounds: number;
|
|
42
|
+
}
|
|
8
43
|
export interface CanonicalLoopState {
|
|
9
|
-
|
|
44
|
+
schemaVersion: typeof CANONICAL_STATE_SCHEMA_VERSION;
|
|
10
45
|
loopId: string;
|
|
11
46
|
round: number;
|
|
12
47
|
maxRounds: number;
|
|
13
48
|
goalId: string;
|
|
14
49
|
objective: string;
|
|
15
50
|
objectiveVersion: number;
|
|
51
|
+
currentTask: string;
|
|
16
52
|
successCriteria: string[];
|
|
17
53
|
hardConstraints: string[];
|
|
18
54
|
activeConstraints: string[];
|
|
@@ -26,17 +62,23 @@ export interface CanonicalLoopState {
|
|
|
26
62
|
blockers: string[];
|
|
27
63
|
verificationFlags: VerificationFlag[];
|
|
28
64
|
discoveries: string[];
|
|
65
|
+
nextAction: string;
|
|
29
66
|
rollingOutcomes: string[];
|
|
30
67
|
recurringIssues: string[];
|
|
31
68
|
failedPatterns: string[];
|
|
32
|
-
/** v2.1:
|
|
33
|
-
|
|
69
|
+
/** v2.1: Phase-boundary milestone summaries that survive window eviction. */
|
|
70
|
+
milestones: MilestoneSummary[];
|
|
34
71
|
/** v2.2: Structured sub-goals with compiler-managed lifecycle. */
|
|
35
72
|
subGoals: SubGoal[];
|
|
73
|
+
/** v3.2: Derived per-criterion status (goal → criteria → evidence view). */
|
|
74
|
+
criterionStatuses: CriterionStatus[];
|
|
75
|
+
/** v3.2: Deterministic lessons learned (repeated violations / failures). */
|
|
76
|
+
lessons: Lesson[];
|
|
36
77
|
/** v2.5: Agent trust score [0, 1] from verification flags. */
|
|
37
78
|
agentTrustScore: number | undefined;
|
|
38
79
|
/** v2.5: Trust trend over last 10 rounds. */
|
|
39
80
|
agentTrustTrend: number[];
|
|
81
|
+
suggestedNextTask: string;
|
|
40
82
|
externalContext: string;
|
|
41
83
|
stateFilePath: string;
|
|
42
84
|
progress: {
|
|
@@ -50,29 +92,62 @@ export interface CanonicalLoopState {
|
|
|
50
92
|
skipped: number;
|
|
51
93
|
} | null;
|
|
52
94
|
};
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
*
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
todoProjection: TodoProjection | null;
|
|
66
|
-
suggestedNextAction: string;
|
|
67
|
-
activeGate: DerivedGate | null;
|
|
68
|
-
stateFreshness: "fresh" | "stale" | "missing";
|
|
69
|
-
handoff: HandoffProjection;
|
|
95
|
+
/** v3.3: Display-only round stats over the last committed rounds.
|
|
96
|
+
* Conditional presence: absent when there are no committed rounds. */
|
|
97
|
+
roundStats?: RoundStat[];
|
|
98
|
+
/** v3.3: Machine git-motion cross-check for the progress dashboard.
|
|
99
|
+
* Conditional presence: absent when no committed git snapshots exist. */
|
|
100
|
+
machineStatus?: MachineStatus;
|
|
101
|
+
/** v3.4: The ACTIVE Round Contract this round executes under —
|
|
102
|
+
* compile-derived from committed rounds (never the submission's own
|
|
103
|
+
* round_contract, which is a proposal for the NEXT round). Conditional
|
|
104
|
+
* presence: absent without an active contract — keeps state hashes
|
|
105
|
+
* byte-identical for contract-less rounds. */
|
|
106
|
+
roundContract?: RoundContract;
|
|
70
107
|
}
|
|
71
108
|
/** Deterministic JSON serialization used by state and prompt hashes. */
|
|
72
109
|
export declare function stableStringify(value: unknown): string;
|
|
73
110
|
export declare function hashCanonicalState(state: CanonicalLoopState): string;
|
|
74
111
|
/** Human/Agent-readable materialized view. It is always reproducible from the
|
|
75
112
|
* canonical state and is never consulted as transaction truth. */
|
|
113
|
+
/** v3.3: Forward-looking "roadmap" view derived from existing state — loop
|
|
114
|
+
* position, met/remaining criteria (with IDs), and sub-goal activity.
|
|
115
|
+
*
|
|
116
|
+
* Deliberately label-free: milestone labels/ranges are collapsed content in
|
|
117
|
+
* L1 (the diff-collapse invariant) and are rendered in full by Phase
|
|
118
|
+
* History everywhere else — the roadmap only reports "N rounds since the
|
|
119
|
+
* last milestone boundary", never the boundary's identity. Next action is
|
|
120
|
+
* likewise excluded: every level renders its own Next Action section.
|
|
121
|
+
* Shared by the state-file and prompt renderers so they cannot silently
|
|
122
|
+
* drift apart (module contract above). Returns [] — renders nothing —
|
|
123
|
+
* when the state carries none of these. Presentation only; never feeds
|
|
124
|
+
* enforcement. */
|
|
125
|
+
export declare function buildRoadmap(state: CanonicalLoopState): string[];
|
|
126
|
+
/** v3.3/v3.4: Render the ACTIVE Round Contract as the Current Task section
|
|
127
|
+
* body — the single formatting source shared by prompts and the state
|
|
128
|
+
* file (module contract above). The original objective is NOT here: it
|
|
129
|
+
* lives in the Objective section. Empty arrays render no line. */
|
|
130
|
+
export declare function formatRoundContract(contract: RoundContract): string;
|
|
131
|
+
/** The trust bar line ("██████░░░░ 60%"). The L2 Agent Trust section and the
|
|
132
|
+
* detailed L1 renderer used to carry private copies of this formula — shared
|
|
133
|
+
* here so a formatting change is made once (module contract: renderers must
|
|
134
|
+
* not silently drift apart). */
|
|
135
|
+
export declare function trustBarLine(score: number): string;
|
|
136
|
+
/** Milestone heading line ("**🏁 Round 7** (Rounds 3–7, 60%)"). Shared by the
|
|
137
|
+
* L2 Phase History and the detailed L1 renderer; the L1 copy previously
|
|
138
|
+
* rendered the range as "R3–R7", a format only this heading used. */
|
|
139
|
+
export declare function milestoneHeading(milestone: MilestoneSummary): string;
|
|
76
140
|
export declare function renderCanonicalStateMarkdown(state: CanonicalLoopState): string;
|
|
77
|
-
export declare function createCanonicalLoopState(request: LoopCompileRequest, response: LoopCompileResponse, stateFilePath: string
|
|
141
|
+
export declare function createCanonicalLoopState(request: LoopCompileRequest, response: LoopCompileResponse, stateFilePath: string,
|
|
142
|
+
/** v3.3: Display-only derived data (round stats, machine git-motion).
|
|
143
|
+
* Optional 4th param — callers that predate v3.3 stay on 3-arg calls. */
|
|
144
|
+
derived?: {
|
|
145
|
+
roundStats?: RoundStat[];
|
|
146
|
+
machineStatus?: MachineStatus;
|
|
147
|
+
/** v3.4: ACTIVE Round Contract for this round (compile-derived from the
|
|
148
|
+
* committed evals of earlier rounds — see loop-compiler). Drives the
|
|
149
|
+
* Current Task. Never the submission's own round_contract field, which
|
|
150
|
+
* is a proposal for the NEXT round. */
|
|
151
|
+
roundContract?: RoundContract | null;
|
|
152
|
+
}): CanonicalLoopState;
|
|
78
153
|
//# sourceMappingURL=canonical-state.d.ts.map
|