cyber: draw the breach path in the dashboard's Evolution view#356
Open
larstalian wants to merge 5 commits into
Open
cyber: draw the breach path in the dashboard's Evolution view#356larstalian wants to merge 5 commits into
larstalian wants to merge 5 commits into
Conversation
The Evolution graph laid nodes out by kind, so a cyber world read as a kind-sorted graph, not a breachable network -- the one thing a reader wants (how is the flag won) was invisible. This draws the reference solver's public-entry -> flag chain. - breach_path(graph) (cyber pack) returns the winning path as ordered on-path node ids + a summary (entry, flag, hops, exploit classes), reusing the same spine the difficulty metric reads. The credential chain follows the real enables walk, not an id-suffix sort, so the kill-chain order is true; _credential_walk now shares that one ordered traversal (_credential_chain_vulns). - It rides on lineage like world_difficulty: the builder stamps seeds, and the pool's optional path_fn re-stamps evolved children (core stays pack-agnostic -- the path is computed pack-side and surfaced opaquely). _lineage_node passes it through. - The Evolution view glows the on-path nodes and the edges between them, dims the decoys, marks the flag with a star, and shows a per-step badge (hops, entry class, difficulty). New legend entry. Verified by a real headless render. A 4-dimension adversarial review (correctness, cross-layer wiring, .rules, render) came back with 0 blockers/majors; its minor (chain ordered by id-suffix) and nits (loose PathFn type, docstring WHAT-narration) are fixed here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
An adversarial audit (reader + skeptic per file) checked every comment and docstring this PR added against .rules. Verdict applied: - breach_path: drop the docstring's second paragraph; the contract paragraph is the irreducible public-API WHY, the "stays in sync / off-path is decoy" note restated the module docstring and asserted no actionable invariant. - _restamp_lineage: keep only the non-obvious invariant (snapshot_id is the graph hash, not derived from lineage, so stamping leaves a world's identity stable); the rest narrated WHAT the name + module docstring already say. - two test comments deleted: one narrated the _spine_reaches assert and referenced the dashboard feature; the other restated the < comparison. - the dashboard.css block comment deleted: it restated what an opacity drop obviously does and carried provenance owned by the JS class assignment. Comment-only; breach_path tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Evolution view unions every step's nodes into one layout, keeping each node's FIRST appearance. A chain hop's terminal flag-read becomes a relay when the chain deepens (the harden mutation changes its kind), but the union froze the original "credential_gated_flag" label -- so a 4-hop chain rendered as four flag-reads, reading like multiple breaches instead of one chain to a single flag. Capture the per-step label (the projection already sends the correct kind for each step) and refresh each node's label on scrub. Now every step shows exactly one credential_gated_flag -- the real terminal -- and the earlier hops read as relays. Verified live: one flag-read per step (the correct terminal for that step), across the full evolved lineage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Office (3D office sim) reads as an empty room for cyber/network worlds -- no NPCs, no department geography -- so landing there hid all the world structure behind a tab click. Default to the Evolution graph instead (the node-link view of the world + its breach path); Office stays one click away for packs where it fits. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The graph columned nodes by KIND (services | endpoints | vulns | data), so a breach hop -- service -> endpoint -> vuln -> next service -- ran right then snapped back to the far-left service column for every hop. A 4-hop chain made three full-width backward jumps, so the path rendered as a scribble of crossing diagonals. Column by position in the breach instead: each hop is one column, the loot sits past the last hop, and off-path decoys hang off their nearest on-path column. The path now flows strictly left->right. Measured on the seed chain world: backward jumps 3 -> 0, on-path edge crossings 2 -> 0. Worlds with no recorded breach path keep the kind bands. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
You asked me to make the dashboard's world scene really good — and to focus on the Evolution view rather than the Office (the office metaphor doesn't fit network/graph worlds).
I dug into the Evolution view and found it's well-built (stable layout, a strong add/remove/modify scrubber) but it laid nodes out by kind — so a cyber world read as a kind-sorted graph, not a breachable network. The one thing a reader actually wants from a cyber world — how is the flag won? — was invisible.
This draws the breach path: the reference solver's public-entry → flag chain, glowing end-to-end over dimmed decoys.
What
breach_path(graph)(cyber pack) returns the winning path as ordered on-path node ids + a summary (entry,flag,hops, exploitclasses), reusing the same spine the difficulty metric reads — so the drawn path and the measured difficulty can't disagree. The credential chain follows the realenableswalk (true kill-chain order), and_credential_walknow shares that one traversal.world_difficulty: the builder stamps seeds; the pool's optionalpath_fnre-stamps evolved children. Core stays domain-agnostic — the path is computed pack-side and surfaced opaquely;_lineage_nodepasses it through.2-hop chain · ssrf → flag · diff 36.9). New legend entry.Verification
breach_pathon lineage): no glow, no badge, flag star intact, no crash — graceful fallback..rules· render): 0 blockers, 0 majors. Its minor (chain ordered by id-suffix, not the solve walk) and two nits (loosePathFntype, docstring narrating WHAT) are fixed in this PR. One flagged issue ("flag star on every secret") was verified false — a cyber world has exactly one secret, always the flag.Nonecase, and the evolved-child re-stamp. Impacted suites green (cyber + dashboard + curriculum, 117 tests).Follow-ups (deferred, not in this PR)
src/openrange/agent.pyedit (broadening shell-fence parsing for cold models) is in my working tree but deliberately excluded from this PR — flagging it so it isn't lost.🤖 Generated with Claude Code