chains-primary: stored chains replace typed edges; edges become a derived view
Owner rulings 2026-09-30: reasoning chains are the stored truth; the graph canvas renders a lossy derived image. No migration, no backcompat — old graph data was wiped. - contracts: GraphChain (arg_-minted id, premises, conclusion) replaces typed edges; GraphEdge survives only as the untyped derived arrow; GraphSnapshot carries stored chains; supports edges retired entirely - store: chains.jsonl ledger (edges.jsonl purged at load alongside legacy events.jsonl); readChains/appendChain seam; merge dedupes by (sorted premises, conclusion), re-assertions append under the same arg_ id - core: deriveView mints implication nodes (name ⟹, statement via formatChainLine) plus premise→imp→conclusion arrows; clusters stay proposition-only (birthSessionPartition); chainsForSelection now groups STORED chains (chain rides iff every member selected) — independent arguments for one conclusion never union; chainsToGraph/chainsToEdges die - extraction: extractor submits chains natively (expandFindings deleted); auditor receives propositions only; supports fan-out gone - deletion: full death of a proposition kills every referencing chain; arg_-prefixed node deletes kill that chain; chainsRemoved stats - UI: every arrow renders the ⟹ double shaft; supports toggle + thickness slider and detail-card edge sections deleted (card keeps name + proposition); chain table + practice pipeline read stored chains - tests: 1188 green across the new seams
This commit is contained in:
@@ -65,7 +65,6 @@ import {
|
||||
sanitizeRegionTuning,
|
||||
type PhysicsTuning,
|
||||
type RegionTuning,
|
||||
type EdgeType,
|
||||
INCREMENTAL_GRAVITY,
|
||||
LINK_DISTANCE,
|
||||
type DepthAnchorMode,
|
||||
@@ -86,14 +85,13 @@ export interface CanvasNode {
|
||||
label: string;
|
||||
}
|
||||
|
||||
/** One directed edge (follows | supports); arrow points prerequisite → dependent. */
|
||||
/** One directed edge of the DERIVED view (chains-primary, 2026-09-30):
|
||||
* premise → implication node → conclusion, UNTYPED — every arrow is an
|
||||
* implication, so every arrow renders the double-shaft glyph (⟹) +
|
||||
* arrowhead (DECIDED 2026-09-14, docs/vision-edge-glyph.md). */
|
||||
export interface CanvasEdge {
|
||||
from: string;
|
||||
to: string;
|
||||
/** Relation type: `follows` renders the double-shaft glyph (⟹),
|
||||
* `supports` the plain single line (DECIDED 2026-09-14,
|
||||
* docs/vision-edge-glyph.md). */
|
||||
type: EdgeType;
|
||||
}
|
||||
|
||||
/** One cluster region: member node ids + the LLM-coined label (or null). */
|
||||
@@ -623,10 +621,6 @@ export class GraphCanvasRenderer {
|
||||
private builtVersion = -1; // version the cache was built at
|
||||
private nodesPath: Path2D | null = null;
|
||||
private shaftsPath: Path2D = new Path2D();
|
||||
/** Supports shafts draw THINNER (owner, 2026-09-29): their own path +
|
||||
* stroke pass at edgeWidth × supportsWidth. Arrowheads share the one
|
||||
* heads path at full geometry (owner pick: shaft only). */
|
||||
private supportsShaftsPath: Path2D = new Path2D();
|
||||
private headsPath: Path2D = new Path2D();
|
||||
private regionCanvas: HTMLCanvasElement | null = null;
|
||||
/** World rect the bitmap covers (drawImage target coords). */
|
||||
@@ -1237,32 +1231,26 @@ export class GraphCanvasRenderer {
|
||||
// relation types draw the same arrow for now — the double-shaft
|
||||
// glyph was rejected (2026-09-15); differentiation is pending a new
|
||||
// approach. Two owner rulings 2026-09-29: the supports draw toggle
|
||||
// (off skips the paths entirely — a draw-only hide; the sim still
|
||||
// feels them) and the supports SHAFT thickness split (supports get
|
||||
// their own path stroked at edgeWidth × supportsWidth; heads stay
|
||||
// full-geometry in the one shared path).
|
||||
// CHAINS-PRIMARY (2026-09-30): one path family — every derived arrow
|
||||
// is an implication, double-shafted + arrowheaded uniformly.
|
||||
const arrowLen = settings.arrowLength;
|
||||
const shafts = new Path2D();
|
||||
const supportsShafts = new Path2D();
|
||||
const heads = new Path2D();
|
||||
for (const e of data.edges) {
|
||||
if (!settings.showSupports && e.type === "supports") continue;
|
||||
if (!isVisible(e.from) || !isVisible(e.to)) continue;
|
||||
const a = this.nodeById.get(e.from);
|
||||
const b = this.nodeById.get(e.to);
|
||||
if (!a || !b) continue;
|
||||
const g = arrowGeometry(a, b, nodeR, nodeR, arrowLen);
|
||||
if (!g) continue;
|
||||
const path = e.type === "supports" ? supportsShafts : shafts;
|
||||
path.moveTo(g.shaftFrom.x, g.shaftFrom.y);
|
||||
path.lineTo(g.shaftTo.x, g.shaftTo.y);
|
||||
shafts.moveTo(g.shaftFrom.x, g.shaftFrom.y);
|
||||
shafts.lineTo(g.shaftTo.x, g.shaftTo.y);
|
||||
heads.moveTo(g.tip.x, g.tip.y);
|
||||
heads.lineTo(g.left.x, g.left.y);
|
||||
heads.lineTo(g.right.x, g.right.y);
|
||||
heads.closePath();
|
||||
}
|
||||
this.shaftsPath = shafts;
|
||||
this.supportsShaftsPath = supportsShafts;
|
||||
this.headsPath = heads;
|
||||
|
||||
// Cluster regions are NOT built here: they rasterize into their own
|
||||
@@ -1639,10 +1627,6 @@ export class GraphCanvasRenderer {
|
||||
ctx.lineWidth = settings.edgeWidth / k;
|
||||
ctx.lineCap = "round";
|
||||
ctx.stroke(this.shaftsPath);
|
||||
if (settings.showSupports) {
|
||||
ctx.lineWidth = Math.max(settings.edgeWidth * settings.supportsWidth, 0.5) / k;
|
||||
ctx.stroke(this.supportsShaftsPath);
|
||||
}
|
||||
ctx.fill(this.headsPath);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user