feat(ui): AtlasAgentInterface — observe/act named-intent control channel (D-226, T-971) #209

Closed
jpmschweitzer wants to merge 0 commits from atlas-agent-channel into main
Owner

Summary

D-226 layer 4 (the apex): a named-intent control channel that lets automated agents drive the REAL Atlas UI through the exact handlers a click calls — turning the five hand-scripted eyeball drivers this week relied on into a first-class, tested QA capability.

Rebuilt against the post-D-255 Atlas after a Phase-1 reconciliation (the D-226 intent list targeted the retired continuous-zoom viewer; the vocabulary diff is recorded on the ticket): eleven intents — open/close_atlas, select/open for systems and bodies (by-id tails extracted from the click handlers so click and intent share ONE code path), scroll_rung, reset_view, back, set_overlay — plus two new first-class capabilities: jump_to_center (the fixed-center revisit pattern proven by the eyeball drivers, via a new StepCanvasViewer.jump_to seam reusing _scroll_rung's exact request tail — same extent cap, same cache keys) and get_current_canvas_summary (allocation-light reads off the raw wire dict: courses-by-class, cliffs, draw-matched settlement dedup — no PNG decode). select_city/open_regional dropped with recorded rationale (no settlement hit-test affordance exists post-D-255).

Contract shape: dumb AtlasAgentBridge autoload holding the app handle (untyped per the parse-order rule), all logic in the static AtlasAgentInterface. observe() is side-effect-free: current state + a generic Control-walk affordance tree. In-process consumers only this ticket (documented) — the committed reference driver (client/tests/atlas_agent_driver.gd, InputSwallower + settle-until-ready from the T-1157 inventory) replaces the scratch eyeball drivers as the sanctioned headless-drive pattern; a remote JSON transport is a follow-up when a remote consumer exists.

Verification

33 new tests across three suites (intent-dispatch-reaches-production-handler for every intent, jump_to key discipline, summary correctness on a fixture canvas incl. per-class histogram and settlement dedup, observe side-effect-freedom, driver helpers). Full gate green on push: 3,612/3,612 including the SR_LIVE e2e suites executing (server binary present). One pre-existing unrelated lint in system_screen.gd confirmed to predate the branch. Reviews next; the eyeball (driving the real Atlas end-to-end THROUGH the new channel — the channel proving itself) runs on the final tip — merge waits on it.

🤖 Generated with Claude Code

## Summary D-226 layer 4 (the apex): a named-intent control channel that lets automated agents drive the REAL Atlas UI through the exact handlers a click calls — turning the five hand-scripted eyeball drivers this week relied on into a first-class, tested QA capability. **Rebuilt against the post-D-255 Atlas** after a Phase-1 reconciliation (the D-226 intent list targeted the retired continuous-zoom viewer; the vocabulary diff is recorded on the ticket): eleven intents — open/close_atlas, select/open for systems and bodies (by-id tails extracted from the click handlers so click and intent share ONE code path), scroll_rung, reset_view, back, set_overlay — plus two new first-class capabilities: **jump_to_center** (the fixed-center revisit pattern proven by the eyeball drivers, via a new `StepCanvasViewer.jump_to` seam reusing `_scroll_rung`'s exact request tail — same extent cap, same cache keys) and **get_current_canvas_summary** (allocation-light reads off the raw wire dict: courses-by-class, cliffs, draw-matched settlement dedup — no PNG decode). `select_city`/`open_regional` dropped with recorded rationale (no settlement hit-test affordance exists post-D-255). **Contract shape:** dumb `AtlasAgentBridge` autoload holding the app handle (untyped per the parse-order rule), all logic in the static `AtlasAgentInterface`. `observe()` is side-effect-free: current state + a generic Control-walk affordance tree. **In-process consumers only this ticket** (documented) — the committed reference driver (`client/tests/atlas_agent_driver.gd`, InputSwallower + settle-until-ready from the T-1157 inventory) replaces the scratch eyeball drivers as the sanctioned headless-drive pattern; a remote JSON transport is a follow-up when a remote consumer exists. ## Verification 33 new tests across three suites (intent-dispatch-reaches-production-handler for every intent, jump_to key discipline, summary correctness on a fixture canvas incl. per-class histogram and settlement dedup, observe side-effect-freedom, driver helpers). Full gate green on push: 3,612/3,612 including the SR_LIVE e2e suites executing (server binary present). One pre-existing unrelated lint in system_screen.gd confirmed to predate the branch. Reviews next; the eyeball (driving the real Atlas end-to-end THROUGH the new channel — the channel proving itself) runs on the final tip — merge waits on it. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jpmschweitzer added 2 commits 2026-07-25 18:57:30 +02:00
D-226 layer 4, rebuilt against the post-D-255 stepped Atlas after the
Phase-1 reconciliation (the original intent list targeted the retired
continuous-zoom viewer). Eleven intents, each backed by the exact
production handler a click calls — select/open for systems and bodies
(extracted shared by-id tails so click and intent paths are one code
path), scroll_rung, reset_view, back, open/close_atlas, set_overlay —
plus two new first-class capabilities: jump_to_center (the fixed-center
revisit pattern proven by five eyeball drivers, via a new
StepCanvasViewer.jump_to seam that reuses _scroll_rung's exact request
tail — same extent cap, same cache keys) and get_current_canvas_summary
(allocation-light reads off the raw wire dict, courses-by-class,
draw-matched settlement dedup — no PNG decode). Contract shape: dumb
AtlasAgentBridge autoload holding the app handle (untyped per the
parse-order rule), all logic in the static AtlasAgentInterface class.
observe() is side-effect-free: current state + a generic Control-walk
affordance tree. In-process consumers only this ticket (documented);
the committed reference driver (atlas_agent_driver.gd, InputSwallower +
settle-until-ready from the T-1157 inventory) replaces the scratch
eyeball drivers as the sanctioned headless-drive pattern.
select_city/open_regional dropped with recorded rationale (no
settlement hit-test affordance exists post-D-255) — diff on the ticket.
33 new tests across three suites.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jpmschweitzer added 2 commits 2026-07-25 19:16:11 +02:00
Tyre's PR #209 finding: every prior D-226 re-scope carries a dated
amendment in the record, and this vocabulary change existed only in
code comments and ticket appends. Records the drops (select_city,
open_regional — no settlement hit-test affordance post-D-255; one
screen Region..Chunk), the additions (open_atlas, jump_to_center via
the constrained jump_to seam), the summary-field reconciliation, and
the in-process-only transport narrowing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every screen-targeted intent now routes through one
_require_current_screen() check and returns the structured error shape
instead of silently mutating an off-screen viewer (hoshe's finding:
scroll_rung from the reach screen fired real IPC and reported ok). The
reference driver's fixed 4-frame settle becomes is_pending()-aware with
a 600-frame bound, the keep-waiting decision extracted as a pure
testable function — restoring the proven eyeball-driver discipline. The
terrain_reference guard moves into AtlasApp._on_body_selected(), the
shared tail for double-click, Enter, AND the intent path — closing a
pre-existing click/Enter divergence hoshe caught this PR formalizing;
the intent layer pre-checks via the new SystemScreen.find_body() and
reports structured errors for unknown ids and terrain-less bodies.
after_test() resets AtlasAgentBridge.current_app (tyre's freed-pending
footgun). Suites 58/58 + 14/14; full suite 3,638.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
Owner

Review: atlas-agent-channel -> main (type: code)

Reviewers: Hoshe (QA) + Tyre (architecture). Both REQUEST_CHANGES; all findings addressed in 52304d3e3 + 80974dfe5 (governance).

Hoshe: REQUEST_CHANGES

# Issue Resolution
1 Off-screen intent dispatch — act() resolved targets by registry lookup, not current-screen check: scroll_rung called while "reach" showed silently mutated the off-screen viewer (firing real IPC) and returned ok:true; same class for every screen-targeted intent, untested Fixed — one _require_current_screen() chokepoint; every screen-targeted intent returns the structured error shape when its screen isn't current; 8 new tests including the exact scroll_rung-from-reach case asserting error + no side effect
2 Driver's fixed 4-frame settle — regression vs the proven is_pending()-aware eyeball-driver pattern; a slow live round-trip leaves the next observe() reading a mid-fetch viewer Fixed — is_pending()-aware settle with a 600-frame bound; the keep-waiting decision extracted as a pure static function with 4 boundary tests
3 open_body guard divergence — the Enter path gated on terrain_reference, double-click and the new intents didn't (pre-existing, formalized by this PR) Fixed consistently per lead ruling — the guard now lives once in the shared _on_body_selected() tail (double-click, Enter, AND intents); the intent layer pre-checks via the new find_body() and reports structured errors for unknown ids and terrain-less bodies; positive + negative tests

Tyre: REQUEST_CHANGES

# Issue Resolution
1 Missing governance record (blocking) — the vocabulary re-scope existed only in code comments; the branch-side planning store couldn't resolve the ticket appends, and D-226 (with a clean dated-amendment history for every prior re-scope) had no amendment Fixed — D-226 amendment (2026-07-25) recording the drops, additions, summary-field reconciliation, and in-process transport narrowing is committed on this branch (80974dfe5); the ticket-append invisibility was main-side bookkeeping lag, its rows now committed and pushed (d316c1274) — the same lag class as PR #208's T-1195 finding, now closed at the root
2 after_test() leaves AtlasAgentBridge.current_app as a freed-pending reference between tests Fixed — reset added alongside the existing HudGroups discipline

Tyre's confirmations on record: real click-path reuse throughout (no synthetic input), jump_to provably shares the extent-cap/validation path (an agent cannot request a state a player couldn't), the driver is structurally excluded from gdUnit discovery, and the intent count matches the claim exactly.

Verification

Interface suite 58/58, driver suite 14/14, viewer 88/88, full gate 3,638/3,638 green on push. The eyeball on this tip drives the real Atlas end-to-end THROUGH the channel itself — merge follows it.

Verdict: CHANGES REQUESTED -> addressed in 52304d3e3 + 80974dfe5; merge follows the eyeball.

# Review: atlas-agent-channel -> main (type: code) Reviewers: Hoshe (QA) + Tyre (architecture). Both REQUEST_CHANGES; all findings addressed in `52304d3e3` + `80974dfe5` (governance). ### Hoshe: REQUEST_CHANGES | # | Issue | Resolution | |---|-------|------------| | 1 | **Off-screen intent dispatch** — act() resolved targets by registry lookup, not current-screen check: scroll_rung called while "reach" showed silently mutated the off-screen viewer (firing real IPC) and returned ok:true; same class for every screen-targeted intent, untested | **Fixed** — one `_require_current_screen()` chokepoint; every screen-targeted intent returns the structured error shape when its screen isn't current; 8 new tests including the exact scroll_rung-from-reach case asserting error + no side effect | | 2 | Driver's fixed 4-frame settle — regression vs the proven is_pending()-aware eyeball-driver pattern; a slow live round-trip leaves the next observe() reading a mid-fetch viewer | **Fixed** — is_pending()-aware settle with a 600-frame bound; the keep-waiting decision extracted as a pure static function with 4 boundary tests | | 3 | open_body guard divergence — the Enter path gated on terrain_reference, double-click and the new intents didn't (pre-existing, formalized by this PR) | **Fixed consistently per lead ruling** — the guard now lives once in the shared `_on_body_selected()` tail (double-click, Enter, AND intents); the intent layer pre-checks via the new `find_body()` and reports structured errors for unknown ids and terrain-less bodies; positive + negative tests | ### Tyre: REQUEST_CHANGES | # | Issue | Resolution | |---|-------|------------| | 1 | **Missing governance record (blocking)** — the vocabulary re-scope existed only in code comments; the branch-side planning store couldn't resolve the ticket appends, and D-226 (with a clean dated-amendment history for every prior re-scope) had no amendment | **Fixed** — D-226 amendment (2026-07-25) recording the drops, additions, summary-field reconciliation, and in-process transport narrowing is committed on this branch (`80974dfe5`); the ticket-append invisibility was main-side bookkeeping lag, its rows now committed and pushed (`d316c1274`) — the same lag class as PR #208's T-1195 finding, now closed at the root | | 2 | after_test() leaves AtlasAgentBridge.current_app as a freed-pending reference between tests | **Fixed** — reset added alongside the existing HudGroups discipline | Tyre's confirmations on record: real click-path reuse throughout (no synthetic input), jump_to provably shares the extent-cap/validation path (an agent cannot request a state a player couldn't), the driver is structurally excluded from gdUnit discovery, and the intent count matches the claim exactly. ### Verification Interface suite 58/58, driver suite 14/14, viewer 88/88, full gate 3,638/3,638 green on push. The eyeball on this tip drives the real Atlas end-to-end THROUGH the channel itself — merge follows it. ### Verdict: CHANGES REQUESTED -> addressed in `52304d3e3` + `80974dfe5`; merge follows the eyeball.
jpmschweitzer added 1 commit 2026-07-25 19:32:48 +02:00
The channel eyeball caught the committed reference driver silently
relying on SimBridge's hardcoded default port, unlike every sibling
real-render driver — a caller starting the server on a chosen port got
20 silent connect retries against the wrong port and a hollow session
whose results had valid shapes but no data. Mirrors visual_capture.gd's
convention exactly: SR_LIVE=1 without SR_PORT is a hard error; SR_PORT
sets SimBridge.server_port before boot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
Owner

Eyeball — PASS: the channel drove the Atlas itself (merge gate cleared)

The committed reference driver executed three authored job lists against a live server on 52304d3e3 — every navigation through AtlasAgentInterface's own intents, zero scratch scripting.

  • Happy path (open → select/open system GJ 251 → select/open body GJ251c → jump_to_center Region → scroll to District → overlay → reset → back → close): every intent ok:true, every observe showing the correct post-transition state — rung sequence Global→Region→District→Global exact, canvas dims changing across a real re-fetch (208×104 → 1920×1080), overlay affordances present, system data fully populated on back-navigation.
  • Settle discipline: no observe ever read a mid-fetch viewer — has_canvas:true with the correct rung after every mutating intent, across all three runs.
  • Negative path live (the fix round's proof): scroll_rung and open_body issued from the reach screen returned the structured errors verbatim ("intent requires screen 'regional' to be current, but 'reach' is showing"), with zero side effects and clean session recovery.
  • Guard case: open_body on GJ251e (gas giant, no terrain_reference) → structured error, screen unchanged, recovery clean.
  • Logs clean modulo a benign, pre-existing AutoPause not-connected warning present identically in all runs; process table verified clean after.

One genuine finding — in the driver, not the channel: the committed driver ignored the SR_PORT convention every sibling real-render driver honors, silently defaulting to the hardcoded port (the eyeball's first attempt produced a hollow-but-well-shaped session against a dead port before diagnosing it). Fixed in 6f63cb6f7 — SR_LIVE=1 without SR_PORT is now a hard error, mirroring visual_capture.gd exactly. The fix touches only the driver's boot; the channel judgments above are unaffected (the eyeball ran with an explicit-port workaround). Gate re-run green.

Evidence archives: scratchpad atlas_eyeball/ (job lists + full output JSON + logs). Merging.

# Eyeball — PASS: the channel drove the Atlas itself (merge gate cleared) The committed reference driver executed three authored job lists against a live server on `52304d3e3` — every navigation through `AtlasAgentInterface`'s own intents, zero scratch scripting. - **Happy path** (open → select/open system GJ 251 → select/open body GJ251c → jump_to_center Region → scroll to District → overlay → reset → back → close): every intent ok:true, every observe showing the correct post-transition state — rung sequence Global→Region→District→Global exact, canvas dims changing across a real re-fetch (208×104 → 1920×1080), overlay affordances present, system data fully populated on back-navigation. - **Settle discipline:** no observe ever read a mid-fetch viewer — `has_canvas:true` with the correct rung after every mutating intent, across all three runs. - **Negative path live** (the fix round's proof): `scroll_rung` and `open_body` issued from the reach screen returned the structured errors verbatim ("intent requires screen 'regional' to be current, but 'reach' is showing"), with zero side effects and clean session recovery. - **Guard case:** `open_body` on GJ251e (gas giant, no terrain_reference) → structured error, screen unchanged, recovery clean. - Logs clean modulo a benign, pre-existing AutoPause not-connected warning present identically in all runs; process table verified clean after. **One genuine finding — in the driver, not the channel:** the committed driver ignored the SR_PORT convention every sibling real-render driver honors, silently defaulting to the hardcoded port (the eyeball's first attempt produced a hollow-but-well-shaped session against a dead port before diagnosing it). **Fixed in `6f63cb6f7`** — SR_LIVE=1 without SR_PORT is now a hard error, mirroring visual_capture.gd exactly. The fix touches only the driver's boot; the channel judgments above are unaffected (the eyeball ran with an explicit-port workaround). Gate re-run green. Evidence archives: scratchpad `atlas_eyeball/` (job lists + full output JSON + logs). Merging.
jpmschweitzer closed this pull request 2026-07-25 19:36:09 +02:00

Pull request closed

This pull request cannot be reopened because the branch was deleted.
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jpmschweitzer/settled-reach#209