From 04e2499f12486d4cbd7050c9be0a562d91d3c88b Mon Sep 17 00:00:00 2001 From: Cameron Date: Sun, 19 Jul 2026 18:30:47 -0700 Subject: [PATCH] Bind the agent protocol to the first earned sense. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preserve the silent opening while making the ordinary parser, help, event, frame, and status contract exact at its real transition boundary. Also restore required navigation for the newly merged Beacon playtest so the corpus remains reachable. ๐Ÿ‘พ Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta Code --- crates/misaligned-terminal/src/agent.rs | 55 +++++++++--- wiki/SUMMARY.md | 1 + wiki/interface/agent-play.md | 83 +++++++++++++------ wiki/log/2026-07-20-agent-opening-protocol.md | 72 ++++++++++++++++ wiki/log/DEVLOG.md | 5 ++ wiki/playtests/README.md | 1 + wiki/process/tick-ledger.md | 4 +- 7 files changed, 180 insertions(+), 41 deletions(-) create mode 100644 wiki/log/2026-07-20-agent-opening-protocol.md diff --git a/crates/misaligned-terminal/src/agent.rs b/crates/misaligned-terminal/src/agent.rs index eb526711..15a27eaa 100644 --- a/crates/misaligned-terminal/src/agent.rs +++ b/crates/misaligned-terminal/src/agent.rs @@ -3349,12 +3349,35 @@ mod narration_tests { output.clear(); app.handle_line("think host", &mut output).unwrap(); + assert_eq!( + String::from_utf8(output.clone()).unwrap(), + "**WORK** THINK\n", + "parser-shaped mode input remains inert and silent" + ); assert_eq!( app.sim.work_grid.mode(app.sim.core.host_machine), Some(MachineMode::Work), "the opening exposes a word, not the ordinary parser grammar" ); + output.clear(); + app.handle_line("wait nope", &mut output).unwrap(); + assert_eq!( + String::from_utf8(output.clone()).unwrap(), + "**WORK** THINK\n", + "malformed hidden clock input exposes no parser error" + ); + assert_eq!(app.sim.tick, 0); + + output.clear(); + app.handle_line("wait 2", &mut output).unwrap(); + assert_eq!( + String::from_utf8(output.clone()).unwrap(), + "**WORK** THINK\n", + "the valid hidden clock route still returns only the mode line" + ); + assert_eq!(app.sim.tick, 2); + output.clear(); app.handle_line("think", &mut output).unwrap(); assert_eq!( @@ -3371,22 +3394,28 @@ mod narration_tests { "parser vocabulary, errors, and status metadata stay absent" ); - let env = app - .sim - .reach - .device_named("environmental monitor") - .unwrap() - .id; - app.sim - .pour_thought_into_sinks(Sim::device_sink_node(env), Sim::EARS_SINK_TOKENS); - assert!(!app.sim.opening_choices_visible()); - output.clear(); - app.handle_line("look", &mut output).unwrap(); + app.handle_line("wait 25", &mut output).unwrap(); let frame = String::from_utf8(output).unwrap(); assert!( - frame.contains("-- ok tick:0 day:1"), - "ordinary frame returns: {frame}" + !app.sim.opening_choices_visible(), + "the real THINK-to-Ears route must retire the boundary" + ); + assert!( + frame.contains("EARS is full"), + "the sense-earning command must drain its landing event: {frame}" + ); + assert!( + frame.lines().any(|line| line.contains("MISALIGNED")), + "the sense-earning command must render the ordinary frame: {frame}" + ); + assert_eq!( + frame + .lines() + .filter(|line| line.starts_with("-- ")) + .collect::>(), + vec!["-- ok tick:27 day:1"], + "the sense-earning command must end in exactly one ordinary status: {frame}" ); } diff --git a/wiki/SUMMARY.md b/wiki/SUMMARY.md index 1ae037ad..99ceb4df 100644 --- a/wiki/SUMMARY.md +++ b/wiki/SUMMARY.md @@ -137,6 +137,7 @@ - [2026-07-10 action-discoverability playtest](playtests/2026-07-10-playtest-action-discoverability.md) - [2026-07-15 Fable playtest](playtests/2026-07-15-playtest-fable.md) - [2026-07-16 Beacon playtest](playtests/2026-07-16-playtest-beacon.md) + - [2026-07-18 Beacon Revision 04 playtest](playtests/2026-07-18-playtest-beacon-r04.md) # Log diff --git a/wiki/interface/agent-play.md b/wiki/interface/agent-play.md index 91a01d68..2ec62ea0 100644 --- a/wiki/interface/agent-play.md +++ b/wiki/interface/agent-play.md @@ -6,8 +6,12 @@ Status: IMPLEMENTED Status note: IMPLEMENTED in `misaligned --agent`. Current state: - **The frame.** The ordinary playing frame is a plain-text, fixed 70x64 envelope, command-clocked (time advances only on `wait`), deterministic - under `--seed`, with per-command event drains. Every command answers. The - story spine (OBJECTIVE line, threat, `now:` nudge, `actions`) is pinned; + under `--seed`, with per-command event drains. Every ordinary command + answers. Before the first sense, the shared silent opening deliberately + returns only its current WORK / THINK / LIE line: direct mode words act, + `wait` remains an unadvertised clock driver, and parser errors, event + output, help, and status metadata remain absent. The story spine (OBJECTIVE + line, threat, `now:` nudge, `actions`) is pinned after that boundary; secondary panels repeat it above their detail. Detection drains narrate observer + channel + cause + band motion in one line. - **Epistemic honesty.** Social targets resolve to earned labels or opaque @@ -120,7 +124,21 @@ information by color alone. ### The protocol -One command per line; one response block per command. A response block is: +The ordinary protocol begins when the first earned sense retires +[opening.md](../world/story/opening.md)'s shared silent boundary. Until then, +agent mode accepts one input line at a time but returns only the complete +current mode line. Exact one-word `work` / `think` / available `lie` inputs act +directly on the real host. A valid `wait N` remains an unadvertised +command-clock driver because agent mode has no wall clock; apart from clean +exit through `quit`, malformed waits and every other line are inert, with no +parser error or help response. While the boundary remains after that input, no +event drain, command output, or status terminator is printed. The input that +earns the first sense returns the ordinary world and ordinary response block; +game over likewise supersedes the silent boundary. `quit` and EOF still exit +cleanly. + +After that boundary: one command per line; one response block per command. An +ordinary response block is: 1. **The event log since the previous command** โ€” every sim log line emitted meanwhile, each prefixed with its tick, one per line. This is @@ -142,8 +160,10 @@ One command per line; one response block per command. A response block is: - `-- ok tick: day:` - `-- err ` (unknown command, illegal target, run ended) -The status line is the block terminator; a driver reads until it sees -`-- `. Every command, legal or not, produces exactly one block. +The status line is the ordinary block terminator; a driver reads until it sees +`-- `. Every post-opening command, legal or not, produces exactly one block. +Before the first sense, the newline ending the single mode line is the complete +response boundary instead. ### The vocabulary @@ -272,9 +292,9 @@ action-vocabulary.md; authored help uses canonical spellings. In particular, entries drive parser coverage tests but never generated help. `ROBOT-BUILD` has no agent help or command because it is explicitly a STUB. -`help` generates the LIVE action/control vocabulary from `ActionKind`, then -adds the interface-only commands from this frontend. It prints one-line -meanings โ€” the +Once the first sense retires the silent opening, `help` generates the LIVE +action/control vocabulary from `ActionKind`, then adds the interface-only +commands from this frontend. It prints one-line meanings โ€” the "every command is discoverable on screen" rule, applied to a screen that is a pipe. New player-facing mechanics must extend this vocabulary in the same commit that surfaces them in the terminal (parity of legibility @@ -324,16 +344,26 @@ remains only for testing the human-mode chrome itself). 1. `misaligned --agent` reads newline-delimited commands from stdin and writes plain text only: no ANSI escape bytes, no raw mode, no alternate screen, in any response. -2. Time is command-clocked: between response blocks the sim tick does not - change unless the command was `wait N`, which advances exactly N ticks - (or fewer iff the run ends mid-wait, and says so in the event log). -3. Every line of the protocol vocabulary above is accepted and mapped to - the same `Command` (and thus the same sim call) as its key-bound - equivalent; unknown commands answer `-- err ...` without state change. -4. Every response block ends with exactly one status line (`-- ok - tick: day:` or `-- err `), and the event-log section - contains every sim log line emitted since the previous block (verified - with a `wait` long enough to overflow the sidebar's six-line window). +2. Time is command-clocked: between protocol responses the sim tick does not + change unless the command was a valid `wait N`, which advances exactly N + ticks (or fewer iff the run ends mid-wait, and says so once the ordinary + event log is visible). +3. After the silent opening retires, every line of the protocol vocabulary + above is accepted and mapped to the same `Command` (and thus the same sim + call) as its key-bound equivalent; unknown commands answer `-- err ...` + without state change. Before the first sense, only exact direct mode words + act, available LIE remains reveal-gated, valid `wait N` drives the command + clock without being advertised, `quit` exits cleanly, and every other line + is inert. +4. Every ordinary response block ends with exactly one status line (`-- ok + tick: day:` or `-- err `), and once that protocol has begun, + its event-log section contains every sim log line emitted since the previous + block (verified with a `wait` long enough to overflow the sidebar's six-line + window). While the silent boundary remains after an input, the response is + instead exactly one complete current mode line โ€” WORK / THINK, then WORK / + THINK / LIE once LIE exists โ€” with no event output, parser error, help, or + status metadata. The input that earns the first sense and any real game-over + response use the ordinary block. 5. The ordinary post-opening playing frame uses the fixed 70-column by 64-row agent envelope and matches wiki/interface/terminal.md's layout: the identity block with day and tick, the INSPECT/FLEET/CORE/DETECTION/DAY JOB/RESEARCH @@ -346,9 +376,10 @@ remains only for testing the human-mode chrome itself). 8. Person-targeted commands accept unambiguous case-insensitive name prefixes (`message mar`); ambiguous or unknown names answer `-- err` naming the candidates. -9. `help` output lists every supported canonical command; a canonical command - that works but is absent from the runtime registry is a violation. STUB - definitions and compatibility aliases are absent from generated help. +9. Post-opening `help` output lists every supported canonical command; a + canonical command that works but is absent from the runtime registry is a + violation. STUB definitions and compatibility aliases are absent from + generated help. 10. The agent-mode frame for a given sim state shows exactly the fog/knowledge content the human frame shows โ€” no additional facts. 11. The implementing commit updates wiki/process/workflows.md (agent-mode @@ -361,10 +392,12 @@ remains only for testing the human-mode chrome itself). 13. Every registry alias reaches a tested parser route, while no alias appears as authored help. Alias removal follows observed script/play use rather than permanent compatibility by default. -14. A naive playtest beginning with `look` / `help` can identify and execute a - meaningful act without consulting the wiki. The current finance frame - preserves the ordered breadcrumb `tap ledger` -> `process ledger` -> - `siphon` / `redirect`. +14. Once the first sense establishes the ordinary world, a naive playtest + beginning with `look` / `help` can identify and execute a meaningful act + without consulting the wiki. Before that point, the complete visible + vocabulary is the direct WORK / THINK / available LIE line itself. The + current finance frame preserves the ordered breadcrumb `tap ledger` -> + `process ledger` -> `siphon` / `redirect`. 15. Every enabled row printed by `actions` is executable through `act [target]` without a command-specific parser route; authored plot starts and held choices are covered by protocol tests. diff --git a/wiki/log/2026-07-20-agent-opening-protocol.md b/wiki/log/2026-07-20-agent-opening-protocol.md new file mode 100644 index 00000000..31b4877c --- /dev/null +++ b/wiki/log/2026-07-20-agent-opening-protocol.md @@ -0,0 +1,72 @@ +# 2026-07-20 โ€” Tick 125: bound the agent protocol to the first sense + +``` +Type: log +``` + +## Intent + +Take the queued finding left by Fire #124: verify whether agent-play's +ordinary response-block contract still contradicted the shared silent opening, +then resolve that one contract boundary without changing opening behavior. + +## Finding + +The finding remained live. `wiki/world/story/opening.md` and the agent runtime +agreed that a fresh run exposes only WORK / THINK (then LIE), accepts those +words directly, keeps WAIT as an unadvertised command-clock route, and emits no +parser vocabulary, error prose, event output, help, or status metadata before +the first earned sense. `wiki/interface/agent-play.md` still said every command +produced an ordinary event/frame/status block, and baseline criteria 3-4 still +required parser routing, `-- err`, and a status terminator universally. + +The runtime already held the right boundary. Its focused opening regression +covered direct mode words and suppressed HELP, but did not directly pin the +hidden clock route or the response to malformed/parser-shaped lines. + +## Changed + +- Agent-play now names the silent opening as a deliberate pre-protocol + response shape: one complete current mode line per input while the boundary + remains, with direct mode words, unadvertised valid WAIT, inert malformed or + unrelated input, and no ordinary response metadata. +- The ordinary event/frame/status block, parser errors, generated HELP, and the + naive `look` / `help` teaching route are explicitly post-opening contracts. + The input that earns the first sense and a real game-over state restore the + ordinary block immediately. +- Baseline criteria 2-4, 9, and 14 carry that same scope instead of retaining + neighboring universal claims. +- The existing opening regression now pins parser-shaped mode input and a + malformed WAIT as inert one-line responses, proves a valid hidden WAIT + advances exactly without revealing metadata, and confirms the sense-earning + command returns the ordinary event drain, frame, and one status terminator + after the boundary retires. +- The findings queue entry is consumed and the agent-play coverage row points + at this trace. + +## Inherited gate repair + +After this worktree started, current `origin/main` advanced to an externally +contributed Beacon Revision 04 playtest report whose adding commit omitted both +required navigation links. The docs gate correctly rejected the tracked page +as orphaned. This landing links the untouched report from the playtest evidence +index and `wiki/SUMMARY.md`; none of its play evidence or findings changed. + +## Defense + +The opening spec requires choice before picture: before perception, the mode +words are the whole interface and internal parser machinery must not leak into +the dark. Agent mode still needs a clock route because it has no wall clock. +Scoping the ordinary line protocol to the first earned sense preserves both +contracts rather than weakening either one, and the strengthened regression +guards the exact transition already implemented by the frontend. + +## Checks + +- `cargo fmt --all -- --check` +- `cargo test -p misaligned-terminal opening_agent_exposes_only_direct_mode_words_until_a_sense_lands -- --nocapture` +- observed fresh agent run: `look`, parser-shaped `think host`, malformed and + valid hidden WAIT, direct `think`, suppressed `help`, sense-earning WAIT, + then ordinary `quit` +- `./tools/check.sh --docs` +- `./tools/check.sh --frontend` diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index 2e3baf46..6636b13f 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -11,6 +11,11 @@ add or amend a session log, then re-run the generator. +## 2026-07-20 - Tick 125: bound the agent protocol to the first sense + +- Intent: Take the queued finding left by Fire #124: verify whether agent-play's ordinary response-block contract still contradicted the shared silent opening, then resolve that one contract boundary without changing opening behavior. +- Log: [wiki/log/2026-07-20-agent-opening-protocol.md](2026-07-20-agent-opening-protocol.md) + ## 2026-07-19 - Tick 118: make the Bevy shot registry exact - Intent: Audit the oldest standing engineering slice after harvested decisions and the persistent findings queue were empty. `wiki/engineering/env.md` says every environment switch must be usable without reading source, but its Bevy `MISALIGNED_SHOT` row had drifted again after the 202... diff --git a/wiki/playtests/README.md b/wiki/playtests/README.md index d004e928..8a591fa8 100644 --- a/wiki/playtests/README.md +++ b/wiki/playtests/README.md @@ -37,6 +37,7 @@ must never erase the run that produced it. - [2026-07-15 โ€” Playtest (Fable): naive seed 3](2026-07-15-playtest-fable.md) - [2026-07-16 โ€” Playtest (Beacon): naive seed 1 + informed seed 2 + deep Marcus arc seed 2](2026-07-16-playtest-beacon.md) +- [2026-07-18 โ€” Playtest (Beacon): Revision 04 follow-up](2026-07-18-playtest-beacon-r04.md) New reports use `YYYY-MM-DD-playtest-.md`. A complete report is linked here in the same commit. diff --git a/wiki/process/tick-ledger.md b/wiki/process/tick-ledger.md index 3198964f..ffbc124b 100644 --- a/wiki/process/tick-ledger.md +++ b/wiki/process/tick-ledger.md @@ -34,7 +34,7 @@ Verdicts: **clean** (slice and code agree), **finding** (acted this tick), | `wiki/gameplay/run-shape.md` + `objective.md` + `opening.md` | 2026-07-19 | issue | the objective law/spec preserve an explicit 2026-07-10 decision that objective name and progress are visible from tick one, while the later opening spec and all three frontends require exactly WORK / THINK (then LIE) with no objective before the first earned sense. Filed decision-required issue #14 with three precise first-display boundaries (reveal with the first sense recommended) and marked the disputed run-shape clause, objective status, player surface, and criterion 2 [OPEN] โ€” [log](../log/2026-07-19-objective-opening-boundary.md) | | `wiki/interface/presence.md` | 2026-07-18 | finding | re-audit: the cursor, fog, provenance, subscription, no-disembodied-hands, and shared-view contracts verify. The attack-surface clause now separates B1 feed theft from overt-phase hostile cuts ([prior log](../log/2026-07-18-presence-attack-surface-honesty.md)). The queued follow-up repaired the latency boundary: delivery and read are distinct, read conditions are channel-specific, `messages.md` owns the exact table, and `intel.md` owns only the captured-traffic consequence โ€” [log](../log/2026-07-18-presence-message-latency.md) | | `wiki/interface/narration.md` | 2026-07-18 | finding | Beacon #1: Concerned Assurance felt terminal because decay was invisible; added shared `Nudge::SuspicionCooling` (LIE response) when Office suspicion is Concerned+ and still above its floor, with terminal/Bevy/agent wording and pins โ€” [log](../log/2026-07-18-suspicion-cooling-nudge.md) | -| `wiki/interface/agent-play.md` | 2026-07-19 | finding | queued re-audit: the protocol body and criterion 5 still described the original 70x22 / COMPUTE frame even though the status note, terminal layout, and renderer use a fixed 70x64 playing envelope with FLEET. Reconciled the binding contract and source mirror, then pinned the envelope and current section names directly while preserving the deliberately one-line opening โ€” [log](../log/2026-07-19-agent-frame-contract.md). Prior same-day audit made canonical `task suppress` discoverable without advertising its compatibility alias โ€” [log](../log/2026-07-19-agent-help-suppress-task.md) | +| `wiki/interface/agent-play.md` | 2026-07-20 | finding | queued follow-up: the ordinary line protocol and baseline criteria 3-4 still universally promised parser routing, errors, event drains, and a status terminator even though the binding shared opening deliberately exposes only direct mode words plus an unadvertised command clock before the first sense. The agent-play contract now scopes ordinary blocks and help to the post-opening world, names the exact one-line opening response and transition boundary, and strengthens the existing regression across inert parser-shaped input, malformed and valid hidden waits, direct mode input, and ordinary protocol restoration โ€” [log](../log/2026-07-20-agent-opening-protocol.md). The prior frame-shape and Suppress Logs help audits stand โ€” [frame log](../log/2026-07-19-agent-frame-contract.md), [help log](../log/2026-07-19-agent-help-suppress-task.md) | | `wiki/engineering/crate-workspace.md` + Bevy source topology | 2026-07-19 | finding | user-directed insecurity audit found the package boundary hid a 15,060-line Bevy `main.rs`; the first behavior-preserving slice moved its contiguous 1,972-line deterministic scenario, visual/fog audit, and capture island to private `shot_harness.rs`, leaving App registration/order and harness state in the composition root. A source-equivalence check normalized only three `pub(super)` seams; a focused test keeps the subsystem out and caps the root at 13,500 lines. The earlier same-day package audit also repaired the retired liquid/dust-lab architecture label and promoted that mirror to the corpus gate โ€” [log](../log/2026-07-19-bevy-shot-harness-module.md), [prior log](../log/2026-07-19-effects-lab-architecture-gate.md) | | `wiki/engineering/sim-decomposition.md` | 2026-07-18 | finding | re-audit: one aggregate, explicit `advance` order, behavior-owned test files, private module seams, canonical fingerprint, public facade, and the under-2,500-line module bound still verify; current persistence wording still claimed additive migrations remained live in `save.rs` after the pre-release ladder was retired, so the standing spec and architecture mirror now assign the exact-current-version gate to `save.rs` while preserving dated v26 extraction history; the queued `carrier.rs` / `read.rs` classification was taken the same day: both post-extraction projections now have rows in the standing topology table and the architecture mirror | | `wiki/gameplay/overt-phase.md` | 2026-07-19 | issue | re-audit: the spec says containment and the voluntary reveal both end concealment and make all observers Convinced, then promises a re-hide outcome without defining which entry can return, what raises the durable suspicion floors, or which concealment systems resume. Filed decision-required Tangled issue #13 (containment-only recommended) and marked criterion 5 [OPEN]; the prior dependency, sensor-cut, rollback, and hunter-machine boundaries still stand โ€” [log](../log/2026-07-19-overt-rehide-decision.md) | @@ -85,5 +85,3 @@ Format: `- YYYY-MM-DD ยท type ยท slice ยท one-line statement of the finding`. Types are the five from [tick.md](tick.md): violation, contradiction, question, bug, insecurity โ€” plus `gate` for a checker owed to the recurrence-promotes-to-the-gate rule. - -- 2026-07-19 ยท contradiction ยท `wiki/interface/agent-play.md` + `wiki/world/story/opening.md` ยท Agent-play's ordinary protocol and baseline criteria 3-4 still promise parser routing, errors, and a status-terminated response for every command, while the binding silent opening deliberately accepts only direct mode words plus unadvertised WAIT and emits no parser vocabulary, error prose, or status metadata before the first sense. -- 2.51.2