geneseed 3.19.0 → 3.20.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/CHANGELOG.md CHANGED
@@ -8,6 +8,12 @@ label. For the capability ↔ spec map, see [SHIPPED.md](SHIPPED.md).
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [3.20.0] — 2026-10-09
12
+
13
+ ### Changed
14
+ - Loops repair twice before giving up: the test repair rings (`apply-test`, `fix-test`, `write-run`, `stabilise`) now allow two repairs instead of one, then the attempt is discarded for one fresh try, then the loop stops for you. The first revision carries most of the gain, but a second still lands fixes the first missed. Bound the Loop, the `apply` and `test` bricks and the loops concept page say two. Review rings are unchanged.
15
+ - The fallback to the old wiki manifest name (`wiki.jsonc`) stays for now, against the 3.18.0 note that it would go in the next release: nothing yet reports an install that missed the rename, so removing it could drop a wiki in silence.
16
+
11
17
  ## [3.19.0] — 2026-10-09
12
18
 
13
19
  ### Added
package/SHIPPED.md CHANGED
@@ -20,7 +20,7 @@ historical references, not files distributed with the repo.
20
20
  > **On version numbers.** [`harness.config.json`](harness.config.json)'s `version` is a
21
21
  > human-readable label only. The canonical identity of an installed harness is the
22
22
  > **source fingerprint** stamped in `.geneseed-version` (see `geneseed version`), not the
23
- > string. Current label: **3.19.0**.
23
+ > string. Current label: **3.20.0**.
24
24
 
25
25
  ## Capabilities
26
26
 
@@ -50,9 +50,10 @@ check) refuses a graph with an undeclared cycle inside an iteration, before a si
50
50
  **A ring's `max` is also its own repair budget.** The edge that returns to a ring's first node
51
51
  from inside it — `test` → `apply` — is charged to the smallest ring holding both ends, and that
52
52
  ring stops at its `max` even when a wider ring raises the node's shared budget. The shipped test
53
- rings (`apply-test`, `fix-test`, `write-run`, `stabilise`) are `max: 1`: one repair, then the
54
- attempt is discarded for one fresh try, then the loop stops for you. A second revision makes the
55
- result worse, not better — 0.82 correct after one, 0.673 after two (arXiv 2607.24604).
53
+ rings (`apply-test`, `fix-test`, `write-run`, `stabilise`) are `max: 2`: two repairs, then the
54
+ attempt is discarded for one fresh try, then the loop stops for you. Most of the gain is in the
55
+ first revision — 0.82 correct after one, 0.673 after two (arXiv 2607.24604) — but a second still
56
+ lands fixes the first missed, so it is kept as the last chance, and nothing past it.
56
57
 
57
58
  **`error` always stops.** A brick may declare the outcome `error` without an edge for it; the
58
59
  engine sends it to `$stop`. The shipped `test` brick reports it when a check crashed or its
@@ -2,5 +2,5 @@
2
2
  "_comment": "version is a human-readable release label only; the canonical identity of an installed harness is the source fingerprint stamped in .geneseed-version (see `harness version`), not this string.",
3
3
  "theme": "neutral",
4
4
  "product": "Geneseed",
5
- "version": "3.19.0"
5
+ "version": "3.20.0"
6
6
  }
@@ -223,7 +223,8 @@ export function ensureContextStub(out) {
223
223
 
224
224
  /** The wiki manifest's name. `geneseed-` says who owns it in a shared `.claude/`/`.opencode/`. */
225
225
  export const WIKI_FILE = 'geneseed-wiki.jsonc';
226
- /** Its earlier names, newest first. Readers still fall back to them for one release. */
226
+ /** Its earlier names, newest first. Readers still fall back to them, with no end date:
227
+ * nothing yet tells a user an install missed the rename, so dropping the fallback would lose a wiki in silence. */
227
228
  const LEGACY_WIKI_FILES = ['wiki.jsonc', 'wiki.json'];
228
229
 
229
230
  /**
@@ -128,7 +128,8 @@ const cost = (s) => s.length + (s.match(/\n/g) || []).length + 2;
128
128
  const SESSION_FILES = ['user-rules.md', 'PROFILE.md', 'memory/MEMORY.md', 'anamnesis/MEMORY.md',
129
129
  'notebook/NOTEBOOK.md', 'geneseed-wiki.jsonc'];
130
130
  // The wiki manifest's earlier name, read when the new one is absent (an install not yet re-emitted,
131
- // or a rename that failed). One release; `wiki.json`, older still, is the build's to rename.
131
+ // or a rename that failed). Kept until a missed rename is reported somewhere (status), since
132
+ // without it such an install loses its wiki in silence; `wiki.json`, older still, is the build's to rename.
132
133
  const LEGACY_WIKI = 'wiki.jsonc';
133
134
  // SHA-256 of each seed body in `js/build/stubs.mjs` (`SESSION_SEEDS`), CRLF folded. A file still
134
135
  // byte-identical to its seed says nothing, so it is skipped rather than injected as noise.
package/js/loop/state.mjs CHANGED
@@ -291,8 +291,8 @@ function allowedEntries(graph, v) {
291
291
  // The repair ring an edge closes: the smallest non-iteration loop whose FIRST node is the edge's
292
292
  // target and which also holds its source (test -> apply is apply-test's repair, review -> apply
293
293
  // review-fix's). Its own counter makes `max` the number of repairs that ring may spend, even when
294
- // a wider ring sharing the node raises the node budget above it — `max: 1` is one repair, then
295
- // `exhaust`'s fresh attempt, then a stop (arXiv 2607.24604: a second revision lowers accuracy).
294
+ // a wider ring sharing the node raises the node budget above it — `max: 2` is two repairs, then
295
+ // `exhaust`'s fresh attempt, then a stop (arXiv 2607.24604: revisions past the first lower accuracy).
296
296
  // Its key lives in `counters`, so every reset of a unit resets it too.
297
297
  function repairRing(graph, from, to) {
298
298
  const iteration = iterationLoop(graph);
@@ -185,7 +185,7 @@ export function notebookItems(state) {
185
185
 
186
186
  /**
187
187
  * The wiki manifest's names, current first. `wiki.jsonc` is the name before the `geneseed-`
188
- * prefix: the build renames it on the next emit, and until then it is still read — one release.
188
+ * prefix: the build renames it on the next emit, and until then it is still read (no end date; see `LEGACY_WIKI_FILES`).
189
189
  */
190
190
  const WIKI_NAMES = ['geneseed-wiki.jsonc', 'wiki.jsonc'];
191
191
  const WIKI_META = ['Wiki manifest', 'your machine-wide knowledge base(s)'];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "//": "Every field here is argued and gated in tests/unit/package_manifest.test.mjs. `files`, `bin` and `engines` each have a test that fails when reality drifts from this file; `version` mirrors harness.config.json and is gated too. Read that docblock before editing this one.",
3
3
  "name": "geneseed",
4
- "version": "3.19.0",
4
+ "version": "3.20.0",
5
5
  "description": "A portable, theme-able harness you implant once and use everywhere to grow a disciplined AI coding agent.",
6
6
  "keywords": [
7
7
  "ai",
@@ -10,7 +10,7 @@ carries an `amend`, that supersedes the original intent — follow the amendment
10
10
  replaced.
11
11
 
12
12
  When this is a repair after `test`, act on the latest `test` note only — it is the verdict on
13
- the code as it stands. Fix every finding it lists in this one pass: there is no second repair.
13
+ the code as it stands. Fix every finding it lists in this one pass: repairs are capped at two.
14
14
 
15
15
  Make no unrelated edits: no drive-by rename, no incidental cleanup, no touching a file the card
16
16
  did not declare. If the change genuinely needs a file outside the write set, stop and report that
@@ -11,7 +11,7 @@ brick only observes; a fix belongs in `apply`, not here.
11
11
  1. **Gate** — the build or compile step. If it fails, mark every check below `SKIPPED (gate
12
12
  failed)` and report.
13
13
  2. **Focused checks** — the linter and the tests the change can reach. Run every one even after a
14
- failure: they check independent properties, and the one repair must see every finding at once.
14
+ failure: they check independent properties, and each repair must see every finding at once.
15
15
  3. **Full suite** — only when everything above passed; otherwise `SKIPPED (an earlier check failed)`.
16
16
 
17
17
  List every check with `PASS`, `FAIL`, `ERROR` or `SKIPPED (reason)` — one that did not run is
@@ -114,8 +114,8 @@ legitimate rewrite). The host gates both at the tool boundary.
114
114
  Every autonomous loop needs an exit you set before you enter it. Before iterating —
115
115
  retrying, searching, generating-and-checking — fix the bounds: a cap on attempts, a
116
116
  budget of time or tokens, and an explicit definition of success *and* of failure.
117
- A check-and-repair loop gets one repair, then a fresh attempt or a hand-back — a second
118
- revision lowers accuracy. Only a verdict on the final artifact counts: a pass from before
117
+ A check-and-repair loop gets two repairs, then a fresh attempt or a hand-back — more
118
+ revisions cost accuracy. Only a verdict on the final artifact counts: a pass from before
119
119
  an edit is void, and old check output is never fed back. Then watch for the loop that has stopped progressing:
120
120
  if you are issuing the same call, hitting the same error, or trying variations of one
121
121
  approach with no new information, that is not persistence, it is thrashing — break out, change strategy,
@@ -127,7 +127,7 @@ stop itself is a cost without a limit.
127
127
  <!-- LEAN:else -->
128
128
  Fix an autonomous loop's bounds before you enter it: an attempt cap, a time or token
129
129
  budget, an explicit definition of success *and* failure. A check-and-repair loop spends
130
- one repair, then a fresh attempt or a hand-back; accept only a verdict on the final
130
+ two repairs at most, then a fresh attempt or a hand-back; accept only a verdict on the final
131
131
  artifact — a pass from before an edit is void, old check output is never fed back.
132
132
  Watch for the loop that has stopped progressing: the same call, the same error, variations with no new information are
133
133
  thrashing; break out, change strategy, or stop. When a bound is reached or progress
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "loops": [
26
26
  { "name": "iterations", "nodes": ["identify", "apply", "test", "bruno-test", "security-scan", "review"], "max": 20, "iteration": true },
27
- { "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
27
+ { "name": "apply-test", "nodes": ["apply", "test"], "max": 2 },
28
28
  { "name": "review-fix", "nodes": ["apply", "test", "bruno-test", "security-scan", "review"], "max": 3 }
29
29
  ],
30
30
  "contracts": ["**/openapi*.yaml", "**/openapi*.yml", "**/openapi*.json", "**/swagger*.yaml", "**/swagger*.yml", "**/swagger*.json"]
@@ -17,7 +17,7 @@
17
17
  ],
18
18
  "loops": [
19
19
  { "name": "iterations", "nodes": ["identify", "apply", "test", "review"], "max": 20, "iteration": true },
20
- { "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
20
+ { "name": "apply-test", "nodes": ["apply", "test"], "max": 2 },
21
21
  { "name": "review-fix", "nodes": ["apply", "test", "review"], "max": 3 }
22
22
  ]
23
23
  }
@@ -14,6 +14,6 @@
14
14
  ],
15
15
  "loops": [
16
16
  { "name": "iterations", "nodes": ["ci-triage", "ci-fix", "test"], "max": 10, "iteration": true },
17
- { "name": "fix-test", "nodes": ["ci-fix", "test"], "max": 1 }
17
+ { "name": "fix-test", "nodes": ["ci-fix", "test"], "max": 2 }
18
18
  ]
19
19
  }
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "loops": [
24
24
  { "name": "iterations", "nodes": ["upgrade-scout", "apply", "test", "deps-audit", "review"], "max": 20, "iteration": true },
25
- { "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
25
+ { "name": "apply-test", "nodes": ["apply", "test"], "max": 2 },
26
26
  { "name": "review-fix", "nodes": ["apply", "test", "deps-audit", "review"], "max": 3 }
27
27
  ],
28
28
  "ignoreDeletions": ["**/package-lock.json", "**/yarn.lock", "**/pnpm-lock.yaml", "**/*.lock", "**/gradle.lockfile"]
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "loops": [
24
24
  { "name": "iterations", "nodes": ["identify", "apply", "test", "review"], "max": 20, "iteration": true },
25
- { "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
25
+ { "name": "apply-test", "nodes": ["apply", "test"], "max": 2 },
26
26
  { "name": "review-fix", "nodes": ["apply", "test", "review"], "max": 3 }
27
27
  ]
28
28
  }
@@ -18,7 +18,7 @@
18
18
  ],
19
19
  "loops": [
20
20
  { "name": "iterations", "nodes": ["identify", "apply", "test", "review", "done-check"], "max": 20, "iteration": true },
21
- { "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
21
+ { "name": "apply-test", "nodes": ["apply", "test"], "max": 2 },
22
22
  { "name": "review-fix", "nodes": ["apply", "test", "review"], "max": 3 }
23
23
  ]
24
24
  }
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "loops": [
26
26
  { "name": "iterations", "nodes": ["identify", "apply", "flake-check", "test", "review"], "max": 10, "iteration": true },
27
- { "name": "stabilise", "nodes": ["apply", "flake-check"], "max": 1 },
27
+ { "name": "stabilise", "nodes": ["apply", "flake-check"], "max": 2 },
28
28
  { "name": "review-fix", "nodes": ["apply", "flake-check", "test", "review"], "max": 3 }
29
29
  ]
30
30
  }
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "loops": [
21
21
  { "name": "iterations", "nodes": ["identify", "apply", "test", "review"], "max": 20, "iteration": true },
22
- { "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
22
+ { "name": "apply-test", "nodes": ["apply", "test"], "max": 2 },
23
23
  { "name": "review-fix", "nodes": ["apply", "test", "review"], "max": 3 }
24
24
  ],
25
25
  "weights": { "logic": 0.6 }
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "loops": [
24
24
  { "name": "iterations", "nodes": ["identify", "characterize", "test", "mutation-check"], "max": 20, "iteration": true },
25
- { "name": "write-run", "nodes": ["characterize", "test"], "max": 1 },
25
+ { "name": "write-run", "nodes": ["characterize", "test"], "max": 2 },
26
26
  { "name": "kill-mutants", "nodes": ["characterize", "test", "mutation-check"], "max": 3 }
27
27
  ],
28
28
  "weights": { "new-file": 0.2 }
@@ -18,7 +18,7 @@
18
18
  ],
19
19
  "loops": [
20
20
  { "name": "iterations", "nodes": ["identify", "apply", "test"], "max": 20, "iteration": true },
21
- { "name": "apply-test", "nodes": ["apply", "test"], "max": 1 }
21
+ { "name": "apply-test", "nodes": ["apply", "test"], "max": 2 }
22
22
  ],
23
23
  "weights": { "logic": 0.6 }
24
24
  }
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "loops": [
24
24
  { "name": "iterations", "nodes": ["identify", "apply", "test", "review"], "max": 20, "iteration": true },
25
- { "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
25
+ { "name": "apply-test", "nodes": ["apply", "test"], "max": 2 },
26
26
  { "name": "review-fix", "nodes": ["apply", "test", "review"], "max": 3 }
27
27
  ],
28
28
  "weights": { "delete": 0.5 },
@@ -23,7 +23,7 @@
23
23
  ],
24
24
  "loops": [
25
25
  { "name": "iterations", "nodes": ["identify", "apply", "test", "review", "done-check"], "max": 20, "iteration": true },
26
- { "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
26
+ { "name": "apply-test", "nodes": ["apply", "test"], "max": 2 },
27
27
  { "name": "review-fix", "nodes": ["apply", "test", "review"], "max": 3 }
28
28
  ]
29
29
  }
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "loops": [
21
21
  { "name": "iterations", "nodes": ["identify", "red-test", "apply", "test", "review"], "max": 20, "iteration": true },
22
- { "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
22
+ { "name": "apply-test", "nodes": ["apply", "test"], "max": 2 },
23
23
  { "name": "review-fix", "nodes": ["apply", "test", "review"], "max": 3 }
24
24
  ]
25
25
  }
@@ -23,7 +23,7 @@
23
23
  ],
24
24
  "loops": [
25
25
  { "name": "iterations", "nodes": ["identify", "apply", "test", "compat-check", "review"], "max": 20, "iteration": true },
26
- { "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
26
+ { "name": "apply-test", "nodes": ["apply", "test"], "max": 2 },
27
27
  { "name": "review-fix", "nodes": ["apply", "test", "compat-check", "review"], "max": 3 }
28
28
  ],
29
29
  "contracts": [