FileSearchLedger (src/campaign/search-ledger.ts:870) implements a canonical hash-chained fsynced JSONL with idempotent append, a trusted-head pin, multi-parent SearchCandidateLineage (:83-90), and a hard generation invariant (:1055-1079). git grep openSearchLedger( origin/main -- src/ returns only search-ledger.test.ts. runOptimization emits no ledger events, so the search loop and the lineage recorder in the same package never meet. The only lineage a caller can obtain is the GEPA candidate-graph artifact, which exists only when GEPA ran and never covers a non-GEPA proposer.
A downstream consumer then tried to adopt the ledger directly for a rolling search (director rounds authoring candidate slots round by round, parents from previous rounds, selection decided by evidence outside the file) and hit four hard refusals on installed 0.145.22, pinned in a sentinel test (tangle-network/discovery-lab tools/search-ledger-planless.test.mjs):
- a planless ledger raises
SearchLedgerIntegrityError: event ... appears before the required search plan
- a parent registered in another ledger file is refused
- a
selected decision without an in-ledger measured task outcome is refused
- a registration before its generation operation is refused
Proposed fix: accept an optional searchLedger: SearchLedger on RunOptimizationOptions and emit search-planned, candidate-registered, task-attempted, candidate-decided, search-completed from the existing loop points, which already hold every field those events require. Second half: relax search-planned to permit an appended plan extension (a rolling-search mode), or support cross-file parent references — otherwise document that an open-ended search must open one ledger per round and forfeit the generation invariant across rounds.
FileSearchLedger(src/campaign/search-ledger.ts:870) implements a canonical hash-chained fsynced JSONL with idempotent append, a trusted-head pin, multi-parentSearchCandidateLineage(:83-90), and a hard generation invariant (:1055-1079).git grep openSearchLedger( origin/main -- src/returns onlysearch-ledger.test.ts.runOptimizationemits no ledger events, so the search loop and the lineage recorder in the same package never meet. The only lineage a caller can obtain is the GEPA candidate-graph artifact, which exists only when GEPA ran and never covers a non-GEPA proposer.A downstream consumer then tried to adopt the ledger directly for a rolling search (director rounds authoring candidate slots round by round, parents from previous rounds, selection decided by evidence outside the file) and hit four hard refusals on installed 0.145.22, pinned in a sentinel test (
tangle-network/discovery-lab tools/search-ledger-planless.test.mjs):SearchLedgerIntegrityError: event ... appears before the required search planselecteddecision without an in-ledger measured task outcome is refusedProposed fix: accept an optional
searchLedger: SearchLedgeronRunOptimizationOptionsand emitsearch-planned,candidate-registered,task-attempted,candidate-decided,search-completedfrom the existing loop points, which already hold every field those events require. Second half: relaxsearch-plannedto permit an appended plan extension (a rolling-search mode), or support cross-file parent references — otherwise document that an open-ended search must open one ledger per round and forfeit the generation invariant across rounds.