digest-aware serialized extraction + chain simplification replace the spine stage

Owner live-test verdict on the spine (2026-09-30): no perceptible gain —
the real problems (restatement nodes, shallow re-derivations, same
conclusion from many angles) are mint-time issues a post-hoc chain
minter cannot fix. This arc moves assembly INTO the extractor and adds
the deterministic dedupe the owner specified:

- Digest-aware extraction: each stretch's extractor prompt carries THE
  GRAPH SO FAR (its own source's merged propositions + chains, ids
  verbatim); build on existing ids instead of restating, lean on
  established conclusions as premises. Mixed-namespace chain endpoints
  (fresh p-ids OR existing n_-ids) validated at the submit seam.
- Serialized per source: a source's batches/chunks run strictly in
  order (each extract reads every earlier merge); cross-source runs
  stay parallel; source-wide abort stops the loop. The spine stage,
  role, phase, usage stage, cost row, and setup roster are gone.
- Core-ideas prompt: goal reframed as uncovering core ideas and showing
  how everything derives from the foundations; direction upward, prefer
  lean derivations, never re-derive what the graph already holds.
- Chain simplification (merger maintenance): simplifyChains drops
  provably redundant chains at every merge — prefer-fewest-premises +
  ancestry-cover ([A,B]⟹X with [X,C]⟹Y covers [A,B,C]⟹Y, transitive);
  same-key provenance lines drop together; rewriteLedgers under the
  audit lock; droppedChains counted separately in stats.

Chunk budget stays 8192 (owner: keep for now, maybe lower later).
This commit is contained in:
amosblomqvist
2026-09-30 17:44:37 +03:00
parent 52c02533d1
commit 91341a93da
18 changed files with 734 additions and 879 deletions
+2 -16
View File
@@ -61,7 +61,6 @@ export interface GraphCostSummary {
* historical spend on either is simply not displayed.) */
stages: {
extraction: StageCost;
spine: StageCost;
audit: StageCost;
};
/** Newest first, capped at `recentCap` (default 10). */
@@ -113,16 +112,11 @@ function mergeTokens(into: CallUsage, steps: readonly CallUsage[]): void {
* same output — no clock, no fs, no store reads. */
export function graphCostSummary(input: CostSummaryInput): GraphCostSummary {
const extraction = emptyStage();
const spine = emptyStage();
const audit = emptyStage();
const runs: RecentRun[] = [];
const foldExtractionRun = (run: ExtractionRunUsage, title: string) => {
const stages = run.stages ?? { extractor: { model: "unknown", steps: [] }, auditor: { model: "unknown", steps: [] } };
// The spine stage is OPTIONAL on the record (2026-09-30): records
// written before it existed (and runs whose digest was empty, so
// the call was skipped) carry no entry — default to empty steps.
const spineStage = stages.spine ?? { model: "unknown", steps: [] };
// Per-stage: tokens always count; dollars only when priced.
extraction.runs++;
mergeTokens(extraction.tokens, stages.extractor.steps);
@@ -130,14 +124,6 @@ export function graphCostSummary(input: CostSummaryInput): GraphCostSummary {
if (extDollars === null) extraction.unpricedRuns++;
else extraction.dollars += extDollars;
if (spineStage.steps.length > 0) {
spine.runs++;
mergeTokens(spine.tokens, spineStage.steps);
const spDollars = stageDollars(spineStage.model, spineStage.steps);
if (spDollars === null) spine.unpricedRuns++;
else spine.dollars += spDollars;
}
audit.runs++;
mergeTokens(audit.tokens, stages.auditor.steps);
const audDollars = stageDollars(stages.auditor.model, stages.auditor.steps);
@@ -149,7 +135,7 @@ export function graphCostSummary(input: CostSummaryInput): GraphCostSummary {
const runDollars = allStages.every((d) => d === null)
? null
: allStages.reduce<number>((a, d) => a + (d ?? 0), 0);
const allSteps = [...stages.extractor.steps, ...spineStage.steps, ...stages.auditor.steps];
const allSteps = [...stages.extractor.steps, ...stages.auditor.steps];
runs.push({
startedAt: run.startedAt,
at: run.at,
@@ -177,7 +163,7 @@ export function graphCostSummary(input: CostSummaryInput): GraphCostSummary {
return {
totalDollars: extraction.dollars + audit.dollars,
unpricedRuns,
stages: { extraction, spine, audit },
stages: { extraction, audit },
runs: capped,
};
}