Skip to content

Scenario listings group chains over the graph - #47

Merged
sajonaro merged 1 commit into
mainfrom
graph-classes
Oct 7, 2026
Merged

sajonaro merged 1 commit into
mainfrom
graph-classes

Conversation

@sajonaro

@sajonaro sajonaro commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

A follow-up to T2 (#44) and #46: the last place that lists chains during an incident.

Why

scenarios_list, scenarios_alive and incident_snapshot built their replies in three passes:

  1. list every chain the model allows;
  2. filter them against the facts;
  3. group them into classes (same root, root state and terminal).

On a deep model the snapshot, the agent's "everything in one call" tool, never returned.

What changes

  • scenarios.Classes(g, live) returns the representatives, with counts, for both the live and the eliminated chains, without listing any. Per root it walks the graph in topological order, carrying each node twice: once for paths with nothing contradicted on them and once for paths with something contradicted. It keeps how many paths reach the node and the least of them in scenario order. A chain's prefix is the least path to where it stops, so the least path per node is enough.
  • strategy.Liveness(m, reg, store) exposes the per-node, per-edge form of FilterLive's test, which occam over the graph already uses.
  • What still lists: a cyclic graph falls back to listing, as before. all: true asks for every chain and still lists them.

Same replies

  • Property test: over 400 random graphs × 3 liveness patterns, Classes equals Representatives over Expand, split by liveness. It compares classes, order, counts, IDs and representative chains, including edge labels and observes. It fails with the edge check removed and with the tie-break reversed (both tried).
  • Differential test: on the layered model under 200 random fact stores, the live and eliminated classes deep-equal those from FilterLive's split.
  • Harness: the storefront still lists 14,429 chains in 305 classes, and the first page is byte-identical (24,280 bytes).

Speed (BenchmarkScale, new classes case)

Tiers Chains Classes Before Graph
6 273,511 1,261 3.2 s just to list 37 ms
8 9,853,471 2,881 does not finish 0.14 s
10 354,734,551 5,501 — 0.46 s

Verified

go test ./... passes, and the downstream harness passes 18/18.

scenarios_list, scenarios_alive and incident_snapshot listed every chain
the model allows, filtered it against the incident's facts, and only then
grouped it into classes of the same root, root state and terminal. On a
deep model the incident's one-call summary never returned.

scenarios.Classes gives the classes from the graph: per root, a walk in
topological order carries each node twice, with and without something
dead on the way, with how many paths reach it and the least of them in
scenario order, so every class gets its count and its shortest chain for
the live and the eliminated chains alike. strategy.Liveness is FilterLive's
test per node and per edge, which occam over the graph already uses. A
cyclic graph lists, as before.

Six tiers group in 37 ms (listing alone took 3.2 s) and ten, 354 million
chains in 5,501 classes, in 0.46 s. The replies are unchanged: a property
test over random graphs and liveness, and a differential test over random
facts on a real model, compare them with Representatives over Expand split
by FilterLive, and fail when the edge check or the tie-break is broken.
all: true asks for every chain and still lists them.
@sajonaro
sajonaro merged commit 12f6bac into main Oct 7, 2026
3 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 7, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant