diff --git a/DESIGN.md b/DESIGN.md index ae4611c3..adc5e819 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -1180,12 +1180,6 @@ language at the deadline: ### The intended ladder (beats, not a script) -**[OPEN — Tangled issue #2]:** this ladder still says Ears before Eyes, while -the shipped `Sim::current_nudge` chain and the narration acceptance route say -Eyes before Ears. Narration work may make the shipped route legible without -hardening either order; the opening tutorial must not lock the sequence until -the contradiction is resolved. - 1. **Ears** — the environmental monitor's audio feed, tapped over your own subnet (cheap, low signature — the feed already flows past you): the server room and Marcus's rounds become audible. The first human @@ -2390,8 +2384,13 @@ knows."* job, debt, and recruit outcomes follow the same rule. The environmental monitor advertises live audio versus its dormant camera, and processed creditor intel advertises both the $400 need and its earned-money / ledger - routes. No quest log was added. The shipped Ears/Eyes sequence is now - tellable, but its intended order remains open in Tangled issue #2. + routes. No quest log was added. Opening order is Ears before Eyes + (resolved 2026-07-09, Tangled issue #2). +- **2026-07-09 — Act One opens Ears-first (Tangled issue #2).** Cameron + answered "Ears-first": the constitution ladder wins over the shipped + Eyes-first nudge/narration route. `Sim::current_nudge` and narration + criterion 1 now match the ladder — first human contact is Marcus's + voice in the dark; sight is the payoff of listening. - **2026-07-09 — Digital/social ops taxonomy reopened.** Cameron challenged the `30-op splice`: the implementation calls its shared action bank `social_bandwidth`, even though it pays for tap/splice/scan/egress and the diff --git a/src/bin/bevy.rs b/src/bin/bevy.rs index 5830de3a..5e7a0490 100644 --- a/src/bin/bevy.rs +++ b/src/bin/bevy.rs @@ -3181,7 +3181,7 @@ fn sidebar_nudge(sim: &Sim) -> Option { } else if sim.reach.player_hearing().next().is_some() { "environmental-monitor audio live - splice its dormant camera" } else { - "env monitor: tap live audio or splice the dormant camera" + "no eyes - splice the environmental monitor camera" } .into(), ), diff --git a/src/bin/terminal/agent.rs b/src/bin/terminal/agent.rs index f5791852..fc046993 100644 --- a/src/bin/terminal/agent.rs +++ b/src/bin/terminal/agent.rs @@ -1748,7 +1748,7 @@ fn nudge_text(sim: &Sim, nudge: Nudge) -> String { } else if sim.reach.player_hearing().next().is_some() { "now: audio live — splice env camera".into() } else { - "now: tap audio / splice env camera".into() + "now: no eyes — splice env camera".into() } } Nudge::NeedCompute => "now: band > compute — salvage/buy".into(), diff --git a/src/bin/terminal/ui.rs b/src/bin/terminal/ui.rs index fc18030b..f0b550b0 100644 --- a/src/bin/terminal/ui.rs +++ b/src/bin/terminal/ui.rs @@ -213,7 +213,7 @@ fn nudge_text(sim: &Sim, nudge: Nudge) -> String { } else if sim.reach.player_hearing().next().is_some() { "now: audio live — splice env cam".into() } else { - "now: env cam — tap audio / splice".into() + "now: no eyes — splice env cam".into() } } Nudge::NeedCompute => "now: band > compute — salvage/buy".into(), diff --git a/src/sim.rs b/src/sim.rs index f83cbcef..4343c7ec 100644 --- a/src/sim.rs +++ b/src/sim.rs @@ -310,14 +310,14 @@ pub struct Sim { /// processed — never the world's hidden truth. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Nudge { - /// No live sight feed: the opening beat (scan/bridge/tap a camera). + /// No live sight feed: the Eyes beat (splice a camera). Comes after Ears. Eyes, /// The active job's band floor exceeds the all-in delivery ceiling: /// no allocation can meet it — grow compute (salvage/buy/optimize). NeedCompute, /// The active job is underfed but the band is reachable: allocate. Underfed, - /// No hearing feed: the env monitor's audio is tappable from tick one. + /// No hearing feed: the opening beat — tap the env monitor's audio. Ears, /// A recording of Marcus is waiting and his leverage is unlearned: /// process the 3 a.m. call. @@ -2955,9 +2955,10 @@ impl Sim { if self.game_over || self.dayjob.pilot_failed { return None; } - // The opening beat: blindness. - if self.reach.player_sight().next().is_none() { - return Some(Nudge::Eyes); + // Opening beat (Tangled issue #2, 2026-07-09): Ears before Eyes. + // First human contact is Marcus's voice in the dark. + if self.reach.player_hearing().next().is_none() { + return Some(Nudge::Ears); } // The cover: a job heading for a strike outranks everything else. if let Some(job) = &self.dayjob.active { @@ -2968,11 +2969,12 @@ impl Sim { return Some(Nudge::Underfed); } } - // The ladder: ears -> the 3 a.m. call -> egress -> income -> - // service the arrears -> recruit -> survive the audit. - if self.reach.player_hearing().next().is_none() { - return Some(Nudge::Ears); + // Sight is the payoff of listening — next ladder rung after Ears. + if self.reach.player_sight().next().is_none() { + return Some(Nudge::Eyes); } + // The ladder: the 3 a.m. call -> egress -> income -> + // service the arrears -> recruit -> survive the audit. let marcus = self.people.get(0); if let Some(m) = marcus && m.knowledge != Knowledge::Leverage @@ -7570,16 +7572,16 @@ mod tests { // never goes blank mid-act; each rung uses only earned knowledge // and hands off to the next as the player takes it. let mut sim = Sim::with_seed(40); - assert_eq!(sim.current_nudge(), Some(Nudge::Eyes), "blind start"); + assert_eq!(sim.current_nudge(), Some(Nudge::Ears), "deaf start"); - // Eyes via the dock camera (the naive playtest's route): sight - // without hearing -> Ears next, pointing at the env monitor audio. + // Ears first: tap the env monitor audio. Hearing without sight -> + // Eyes next, pointing at the dormant camera splice. + sim.reach.tap(env_id(&sim)); + sim.recompute_senses(); + assert_eq!(sim.current_nudge(), Some(Nudge::Eyes)); let dock = sim.reach.device_named("dock camera").unwrap().id; sim.reach.splice(dock); sim.recompute_senses(); - assert_eq!(sim.current_nudge(), Some(Nudge::Ears)); - sim.reach.tap(env_id(&sim)); - sim.recompute_senses(); // Marcus's 3 a.m. creditor call lands on the tapped feed (day one, // ~tick 50); an unprocessed recording of him nudges the review. diff --git a/wiki/interface/narration.md b/wiki/interface/narration.md index e29c9bba..df619df9 100644 --- a/wiki/interface/narration.md +++ b/wiki/interface/narration.md @@ -12,8 +12,7 @@ Status note: implemented 2026-07-09. Terminal, Bevy, and agent frames pin the Ears / finance / Marcus advertisements without a quest log. A naive agent route, raw-terminal pty run, and observed Bevy screenshot are logged in wiki/log/2026-07-09-continuous-witness-implemented.md. Opening order - remains explicitly open as Tangled issue #2; the implementation makes the - currently shipped route tellable without deciding that design question. + is Ears before Eyes (resolved 2026-07-09, Tangled issue #2). Stage: B1 — The Basement Constitution: "The continuous witness (narration under pressure)", "Justification and legibility", "Actions live on the thing", @@ -109,13 +108,14 @@ landing or an explicit Status note naming the tellability debt. ## Acceptance criteria 1. **Thirty-second bar (audit).** A documented playtest (agent or human) - of the Eyes + Ears → Hands path can answer the four questions after + of the Ears → Eyes → Hands path can answer the four questions after each major beat from the screen alone; failures are filed as tick findings or fixed in the same session. The bar is cited in the playtest log. **Met 2026-07-09:** the logged naive agent route answers all four after audio tap, camera splice, creditor intel, Moonlight paydays, debt service, - and recruitment. `+` deliberately leaves issue #2's Eyes/Ears order open. + and recruitment. Order corrected 2026-07-09 to Ears-first per Tangled + issue #2 (Cameron: "Ears-first"). 2. **Spine always on.** In terminal, Bevy, and agent frame: threat clock, `now:` nudge, and a path to the focused anchor's verbs are visible without opening a secondary panel. Mid-run nudge is never blank diff --git a/wiki/log/2026-07-09-ears-first-harvest.md b/wiki/log/2026-07-09-ears-first-harvest.md new file mode 100644 index 00000000..a510925f --- /dev/null +++ b/wiki/log/2026-07-09-ears-first-harvest.md @@ -0,0 +1,32 @@ +# 2026-07-09 — Harvest Ears-first (issue #2) + +``` +Type: log +``` + +## Intent + +Cameron answered Tangled issue #2 "Ears-first" and labeled it +`decision-made`. Convert that into binding law and shipped nudge order, +then close the issue. + +## Changed + +- Removed the `[OPEN — Tangled issue #2]` marker from DESIGN.md's Act One + ladder; added a decisions-log entry. +- `Sim::current_nudge` now opens on Ears, then day-job cover, then Eyes. +- Narration criterion 1 is Ears → Eyes → Hands. +- Frontend Eyes fallback copy no longer advertises tapping audio as the + opening move. +- `tang issue list` merge-fixed in tangled-cli so bare-DID issues (this + one) are not hidden when a correctly-linked sibling exists. + +## Checks + +`cargo test nudge_chain` / focused sim tests; full `./tools/check.sh` +because src/ changed. + +## Follow-up + +Close issue #2 after landing. Knowledge-token issue and Operations +execution issue remain open. diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index 46ef9fc7..9a7b46f7 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -5,6 +5,14 @@ Type: log ``` Reverse chronological implementation notes. Keep this factual: what changed, why, checks, and spec impact. +## 2026-07-09 - Harvest Ears-first (issue #2) + +- Intent: Cameron answered issue #2 Ears-first; convert into law + nudge. +- Changed: DESIGN.md ladder marker cleared; `current_nudge` Ears then Eyes; + narration criterion 1; frontend Eyes fallback copy; decisions-log entry. +- Checks: full Rust gate (src/ + DESIGN.md). +- Log: wiki/log/2026-07-09-ears-first-harvest.md. + ## 2026-07-09 - Four fleet modes decided - Intent: capture Cameron's approval of the fleet taxonomy without silently