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).
70 lines
1.9 KiB
TypeScript
70 lines
1.9 KiB
TypeScript
/**
|
|
* Legend/filters predicate tests — the pure half of the graph-view filters
|
|
* panel (isNodeVisible); the sigma reducers just consume its verdict.
|
|
*/
|
|
|
|
import assert from "node:assert/strict";
|
|
import { describe, it } from "node:test";
|
|
import { displayCostTotals, isNodeVisible } from "../components/graph-view.tsx";
|
|
|
|
const node = {
|
|
name: "Money multiplier",
|
|
statement: "The maximum ratio of broad money a bank can create from each unit of base money.",
|
|
};
|
|
|
|
describe("isNodeVisible (search predicate)", () => {
|
|
it("is visible with an empty query", () => {
|
|
assert.equal(isNodeVisible(node, ""), true);
|
|
});
|
|
|
|
it("search matches the statement case-insensitively", () => {
|
|
assert.equal(isNodeVisible(node, "MONEY multiplier"), true);
|
|
});
|
|
|
|
it("search matches the statement when the name does not", () => {
|
|
assert.equal(isNodeVisible(node, "MAXIMUM ratio"), true);
|
|
assert.equal(isNodeVisible(node, " velocity"), false);
|
|
});
|
|
|
|
it("search matches the name when the statement does not", () => {
|
|
assert.equal(isNodeVisible(node, "money MULTIPLIER"), true);
|
|
assert.equal(isNodeVisible(node, " banking"), false);
|
|
});
|
|
|
|
it("whitespace-only query is no filter", () => {
|
|
assert.equal(isNodeVisible(node, " "), true);
|
|
});
|
|
|
|
|
|
});
|
|
|
|
describe("displayCostTotals (naming-free cost fold)", () => {
|
|
const stage = (dollars: number, unpricedRuns = 0) => ({
|
|
runs: dollars > 0 ? 1 : 0,
|
|
dollars,
|
|
unpricedRuns,
|
|
tokens: {
|
|
inputTokens: 0,
|
|
outputTokens: 0,
|
|
cacheReadTokens: 0,
|
|
cacheWriteTokens: 0,
|
|
reasoningTokens: 0,
|
|
},
|
|
});
|
|
const costs = {
|
|
stages: {
|
|
extraction: stage(1.25, 1),
|
|
audit: stage(0.75),
|
|
naming: stage(9.99, 2), // dead channel — must never reach the display
|
|
},
|
|
} as const;
|
|
|
|
it("sums the live stages only — the dead namer's spend is invisible", () => {
|
|
assert.equal(displayCostTotals(costs).totalDollars, 2);
|
|
});
|
|
|
|
it("unpriced counts fold the same two stages", () => {
|
|
assert.equal(displayCostTotals(costs).unpricedRuns, 1);
|
|
});
|
|
});
|