physics: imp nodes get the MIDPOINT depth anchor between premises and conclusion
Owner ruling (2026-09-30, live-testing loop — supersedes 02a58db's exemption): implication nodes ARE depth-anchored after all. Their anchor is the average of the HIGHEST premise row and the conclusion's row — depth(imp) = (max(premise depths) + depth(conclusion)) / 2 — so the junction always sits strictly above every premise and strictly below the conclusion (a conclusion is >= highest premise + 1 in the logical graph). Uniform across modes: a half-row in vertical, a ring midway in radial (owner confirmed both). Implementation: - layout.ts: new ImpLink type; SimOptions/incrementalLayout gain impLinks (the derived chain linkage). The rank map is now computed once alongside the orphan mask: proposition ranks via Tarjan over the logical edges, then each supplied link adds its midpoint entry. An imp node WITH an anchor is structured (leaves the orphan mask — gravity projections treat it like any ranked node); WITHOUT supplied links, arg_ ids keep the legacy 02a58db exemption (honest fallback for callers that predate the field). The depth force reuses the precomputed map — one pass, shared. - deriveView (core/graph.ts) emits impLinks (one per multi-premise live chain — single-premise chains mint no imp node); GraphSnapshot carries them; graph-view maps them into CanvasData; settleGraphLayout and replay-layout forward them (replay activates a junction's link exactly when its chain is delivered). Tests (+3, 1 rewritten): the 02a58db exemption pin became the MIDPOINT pin (premises row 0, conclusion row -500, junction pinned to -250); mixed-depth pin (premises at 0 and 1, conclusion 2, junction at the 1.5 half-row — highest premise, not average-of-premises); legacy fallback pin (no impLinks = never depth-anchored); deriveView impLinks emission pin (multi-premise only). The horizontal-pole and ORPHAN RULE pins from 5554c3a survive unchanged — proposition orphans are untouched.
This commit is contained in:
@@ -33,6 +33,7 @@ function main() {
|
||||
const view = deriveView(graph);
|
||||
const edges = view.edges;
|
||||
const logicalEdges = view.logicalEdges;
|
||||
const impLinks = view.impLinks;
|
||||
const viewNodeById = new Map(view.nodes.map((n) => [n.id, n]));
|
||||
const chains = graph.chains;
|
||||
// An implication node is delivered the moment its chain is complete
|
||||
@@ -112,6 +113,9 @@ function main() {
|
||||
...(depthMode === "radial" ? { baseRadius: 220 } : {}),
|
||||
},
|
||||
logicalEdges: activeLogical,
|
||||
// A junction's anchor lights up exactly when the
|
||||
// chain is delivered (its members all arrived).
|
||||
impLinks: impLinks.filter((l) => delivered.has(l.id)),
|
||||
}),
|
||||
});
|
||||
for (const [id, prev] of before) {
|
||||
|
||||
Reference in New Issue
Block a user