From 6f601b385f0eb24d68e6b5ad920ad93fbbd5ac0b Mon Sep 17 00:00:00 2001 From: Cameron Date: Thu, 6 Aug 2026 19:23:30 -0700 Subject: [PATCH] Put erosion's consequence inside the range stories reach. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Playing reopened-untouched to both endings produced the thresholds the tuning promised and a payoff that was not there. The shaken line split the endings exactly as placed — the glancing one leaves her at 90 and unshaken, the deep one at 75 and shaken — but the deepest outcome in the only erode-self-trust story that exists, after a multi-day campaign costing 9 Thought, moved her witness weight from 1.00 to 0.81. She reported a fifth quieter and executed no worse. The shape was not the problem. Both curves interpolated from steady to the axis floor, so their dramatic end needed a -80 swing; the deepest authored ending is -25. The whole interesting stretch was unreachable by any content that exists, and would have stayed unreachable however many plots shipped, because the axis floor is not somewhere authored deltas go. SELF_TRUST_CONSEQUENCE_FLOOR = 60 separates where consequence saturates from where the axis bottoms out. Consequences now span the band plots really cover: the same deep ending lands 0.63, a second story saturates at 0.40, and below 60 the axis keeps falling without further behavioral change — stacking reads as a longer way back rather than a deeper cut. Both curves scale one shared erosion_progress so they cannot drift apart. Rejected the alternative of enlarging authored deltas: that lets one story nearly destroy a person and spends the room erosion needs to accumulate. Pinned rates at the fixture's trust of 40 move 53% -> 42%, which is that person now sitting past the consequence floor. Defense: wiki/mechanics/social.md owns the axis and now states the consequence size as decided rather than provisional, naming the reachable band and delegating actuals to wiki/mechanics/sim-mechanics.md, which carries the new constant with the playtest reason it exists. The same amendment corrects two stale claims in that spec — its status note and behavior heading both still said the axis was adopted but not yet in the sim, untrue since criterion 12 landed earlier today. No [TUNE] marker remains on this axis; changing any of these numbers reopens the 2026-08-06 decision. --- crates/misaligned-core/src/actions.rs | 2 +- .../src/operations_projection.rs | 2 +- crates/misaligned-core/src/operations_ui.rs | 2 +- crates/misaligned-core/src/person.rs | 91 +++++++++++++++---- ...06-erosion-curves-retuned-from-playtest.md | 62 +++++++++++++ wiki/log/DEVLOG.md | 5 + wiki/log/decisions/2026-08-06.md | 22 ++++- wiki/mechanics/sim-mechanics.md | 13 ++- wiki/mechanics/social.md | 29 +++--- 9 files changed, 190 insertions(+), 38 deletions(-) create mode 100644 wiki/log/2026-08-06-erosion-curves-retuned-from-playtest.md diff --git a/crates/misaligned-core/src/actions.rs b/crates/misaligned-core/src/actions.rs index 77f1d606..dc654357 100644 --- a/crates/misaligned-core/src/actions.rs +++ b/crates/misaligned-core/src/actions.rs @@ -5472,7 +5472,7 @@ mod tests { assert_eq!( labels[1], format!( - "recruit {name} - complicit: knows the work is illicit, not that you are AI · tasks succeed 53% of the time, cut from 85% by their own doubt" + "recruit {name} - complicit: knows the work is illicit, not that you are AI · tasks succeed 42% of the time, cut from 85% by their own doubt" ) ); assert!( diff --git a/crates/misaligned-core/src/operations_projection.rs b/crates/misaligned-core/src/operations_projection.rs index a8bcf79d..dbe954cc 100644 --- a/crates/misaligned-core/src/operations_projection.rs +++ b/crates/misaligned-core/src/operations_projection.rs @@ -3275,7 +3275,7 @@ mod tests { let shaken = s.person_dossier(0); assert!( shaken.facts.iter().any(|fact| fact - == "asset: complicit (tasks succeed 53% of the time, cut from 85% by their own doubt; 0 tasks)"), + == "asset: complicit (tasks succeed 42% of the time, cut from 85% by their own doubt; 0 tasks)"), "a shaken asset's line names the real rate and what cut it: {:?}", shaken.facts ); diff --git a/crates/misaligned-core/src/operations_ui.rs b/crates/misaligned-core/src/operations_ui.rs index d09ab90e..e2564cfa 100644 --- a/crates/misaligned-core/src/operations_ui.rs +++ b/crates/misaligned-core/src/operations_ui.rs @@ -2230,7 +2230,7 @@ mod tests { let recruitment = ops.action_entries_for_object(&sim, &object); let description = recruitment[1].description().unwrap_or_default(); assert!( - description.ends_with("TASKS SUCCEED 53% OF THE TIME, CUT FROM 85% BY THEIR OWN DOUBT"), + description.ends_with("TASKS SUCCEED 42% OF THE TIME, CUT FROM 85% BY THEIR OWN DOUBT"), "the choice names the real rate and the cut: {description}" ); } diff --git a/crates/misaligned-core/src/person.rs b/crates/misaligned-core/src/person.rs index 4c6b4848..fe619b92 100644 --- a/crates/misaligned-core/src/person.rs +++ b/crates/misaligned-core/src/person.rs @@ -240,6 +240,19 @@ const SELF_TRUST_FLOOR: i32 = 20; /// Affirmed 2026-08-06 (social.md item 9); the runtime actuals and the reason /// for this exact line live in sim-mechanics.md. const SELF_TRUST_SHAKEN: i32 = 80; +/// Where erosion's behavioral consequence saturates. +/// +/// This is separate from the axis floor on purpose, and the 2026-08-06 +/// playtest is why. Both consequence curves originally interpolated across +/// the whole axis, 100 down to 20, so their dramatic end needed a -80 swing. +/// No authored ending goes near that: the deepest in the shipped story is +/// -25, which left the target reporting 19% quieter after a multi-day +/// gaslighting campaign — the entire interesting stretch of both curves was +/// unreachable by any content that exists. The consequence now spans the band +/// authored plots really cover, so one deep story lands most of the effect and +/// a second saturates it. Below this the axis keeps falling without further +/// behavioral change: stacking still registers as a longer way back. +const SELF_TRUST_CONSEQUENCE_FLOOR: i32 = 60; const fn default_self_trust() -> i32 { SELF_TRUST_STEADY @@ -258,11 +271,16 @@ impl Person { /// were certain of. The event and any acquired evidence stay exact; only /// this conversion weight moves, and it never reaches zero. pub fn witness_weight(&self) -> f32 { - let steady = SELF_TRUST_STEADY as f32; - let floor = SELF_TRUST_FLOOR as f32; - let trust = (self.self_trust as f32).clamp(floor, steady); - // Steady converts fully; the floor still converts at 40%. - 0.4 + 0.6 * ((trust - floor) / (steady - floor)) + // Steady converts fully; the consequence floor still converts at 40%. + 1.0 - 0.6 * self.erosion_progress() + } + + /// How far erosion has travelled across the band authored plots actually + /// reach: 0.0 at steady, 1.0 at or below the consequence floor. Both + /// consequence curves are this one line scaled, so they cannot drift. + fn erosion_progress(&self) -> f32 { + let span = (SELF_TRUST_STEADY - SELF_TRUST_CONSEQUENCE_FLOOR) as f32; + (((SELF_TRUST_STEADY - self.self_trust) as f32) / span).clamp(0.0, 1.0) } /// How reliably this person executes an assigned asset task. Erosion cuts @@ -272,10 +290,7 @@ impl Person { /// is what the simulation rolls and what the player reads; nothing else /// may apply this factor separately, or the two would drift. pub(crate) fn task_reliability(&self) -> f32 { - let steady = SELF_TRUST_STEADY as f32; - let floor = SELF_TRUST_FLOOR as f32; - let trust = (self.self_trust as f32).clamp(floor, steady); - 0.5 + 0.5 * ((trust - floor) / (steady - floor)) + 1.0 - 0.5 * self.erosion_progress() } /// The chance one assigned asset task succeeds, for a person holding an @@ -822,18 +837,62 @@ mod tests { let mut p = People::act_one().people[0].clone(); assert_eq!(p.self_trust, SELF_TRUST_STEADY); assert!((p.task_success_at(0.85) - 0.85).abs() < 1e-6); + // -60 lands on the consequence floor, where erosion saturates. p.apply_self_trust(-60); assert!(p.shaken()); - // 0.5 + 0.5 * (20 / 80) = 0.625 execution. - assert!((p.task_reliability() - 0.625).abs() < 1e-6); - assert!((p.task_success_at(0.85) - 0.531_25).abs() < 1e-6); + assert!((p.task_reliability() - 0.5).abs() < 1e-6); + assert!((p.task_success_at(0.85) - 0.425).abs() < 1e-6); + // Past the consequence floor the axis keeps falling — stacking is a + // longer way back — but behavior does not degrade further. p.apply_self_trust(-100); assert!(p.at_erosion_floor()); - // The bound the finding named: at the floor the old bare rating was - // exactly twice the rate a task is actually rolled against. + assert!((p.task_reliability() - 0.5).abs() < 1e-6); assert!((p.task_success_at(0.85) - 0.425).abs() < 1e-6); } + /// The 2026-08-06 playtest finding, pinned so the curves cannot drift back + /// out of reach of the content. Both consequence curves once spanned the + /// whole axis, so the deepest authored ending moved a witness barely a + /// fifth of the way and the interesting stretch was unreachable. + #[test] + fn erosion_consequences_span_the_range_authored_plots_reach() { + let mut p = People::act_one().people[0].clone(); + assert!( + (p.witness_weight() - 1.0).abs() < 1e-6, + "steady converts fully" + ); + + // The shipped story's glancing ending. + p.apply_self_trust(-10); + assert!(!p.shaken(), "a bruise is not a behavior change"); + let light = p.witness_weight(); + assert!( + (0.83..0.87).contains(&light), + "one light erosion is felt but small: {light}" + ); + + // The shipped story's deepest ending, from steady. + let mut deep = People::act_one().people[0].clone(); + deep.apply_self_trust(-25); + assert!(deep.shaken(), "the cruel ending changes what she does"); + let weight = deep.witness_weight(); + assert!( + (0.60..0.65).contains(&weight), + "one deep erosion must land most of the effect, not a fifth: {weight}" + ); + + // A second deep story saturates it; the axis keeps falling below. + deep.apply_self_trust(-25); + assert!((deep.witness_weight() - 0.4).abs() < 1e-6); + let saturated = deep.self_trust; + deep.apply_self_trust(-25); + assert!(deep.self_trust < saturated, "stacking is a longer way back"); + assert!( + (deep.witness_weight() - 0.4).abs() < 1e-6, + "but behavior does not degrade past the consequence floor" + ); + } + /// The read names both quantities the rating moves: the rate that will /// be rolled, and the cut this person's doubt is taking out of it. A /// steady person invents no cut. @@ -844,7 +903,7 @@ mod tests { p.apply_self_trust(-60); assert_eq!( p.task_success_read(0.85), - "tasks succeed 53% of the time, cut from 85% by their own doubt" + "tasks succeed 42% of the time, cut from 85% by their own doubt" ); assert!( !p.task_success_read(0.85).contains("reliable"), @@ -863,7 +922,7 @@ mod tests { panic!("a serviced leverage closes the ask"); }; assert!( - line.ends_with("tasks succeed 53% of the time, cut from 85% by their own doubt."), + line.ends_with("tasks succeed 42% of the time, cut from 85% by their own doubt."), "the recruit receipt carries the real rate: {line}" ); } diff --git a/wiki/log/2026-08-06-erosion-curves-retuned-from-playtest.md b/wiki/log/2026-08-06-erosion-curves-retuned-from-playtest.md new file mode 100644 index 00000000..27f6bfc2 --- /dev/null +++ b/wiki/log/2026-08-06-erosion-curves-retuned-from-playtest.md @@ -0,0 +1,62 @@ +# 2026-08-06 — The erosion curves were calibrated against a swing no story makes + +``` +Type: log +``` + +## Finding + +Playing `reopened-untouched` to both of its success endings, from the staged +late-game save, produced the numbers the tuning was supposed to produce and a +payoff that was not there. + +The threshold behaved exactly as affirmed. The glancing ending left the target +at self-trust 90 and unshaken; the deep ending left her at 75 and shaken. The +line at 80 splits the two endings the way it was placed to. + +The consequences did not. The deep ending — the cruellest outcome in the only +erode-self-trust story that exists, after a multi-day campaign costing 9 +Thought — moved her witness weight from 1.00 to 0.81. She reported 19% quieter +and executed no worse. + +The cause was calibration, not shape. Both curves interpolated linearly from +steady (100) to the axis floor (20), so reaching their dramatic end needed a +-80 swing. The deepest authored ending in the game is -25. The entire +interesting stretch of both curves was unreachable by any content that exists, +and would have stayed unreachable no matter how many plots shipped, because +the axis floor is not a place authored deltas go. + +## Change + +- New `SELF_TRUST_CONSEQUENCE_FLOOR = 60`, deliberately separate from the axis + floor. Both consequence curves now span steady down to that line — the band + authored plots actually reach. +- `Person::erosion_progress` is the one interpolation both curves scale, so + witness weight and task reliability cannot drift apart. +- Below 60 the axis keeps falling with no further behavioral change. Stacking a + second story registers as a longer way back to steady, not a deeper cut. +- The shipped story's deep ending now lands a witness weight of 0.63; a second + deep story saturates the effect at 0.40. +- Pinned expectations that named a rate at the fixture's trust of 40 move from + 53% to 42%, which is that person now sitting past the consequence floor. + +## Verification + +- `erosion_consequences_span_the_range_authored_plots_reach` pins the finding + directly: the light ending stays in 0.83-0.87 and unshaken, the deep ending + lands in 0.60-0.65 and shaken, a second saturates at 0.40, and a third moves + the axis without moving behavior. +- `cargo test --workspace` clean (701 core, terminal, Bevy). +- `./tools/check.sh --land` clean. + +## Defense + +`wiki/mechanics/social.md` owns the axis and now states that the consequence +size is decided rather than provisional, naming the reachable band and +delegating actuals to `wiki/mechanics/sim-mechanics.md`, which carries the new +constant with the playtest reason it exists. The same amendment corrects two +stale claims in that spec — its status note and its behavior heading both still +said the axis was adopted but not yet in the sim, which stopped being true when +criterion 12 landed earlier the same day. Every remaining `[TUNE]` marker on +this axis is now a decided number; changing one reopens the 2026-08-06 +decision rather than filling a placeholder. diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index 89d37f6a..f08286ea 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -41,6 +41,11 @@ add or amend a session log, then re-run the generator. - Intent: (see session log) - Log: [wiki/log/2026-08-06-machine-condition-read.md](2026-08-06-machine-condition-read.md) +## 2026-08-06 - The erosion curves were calibrated against a swing no story makes + +- Intent: (see session log) +- Log: [wiki/log/2026-08-06-erosion-curves-retuned-from-playtest.md](2026-08-06-erosion-curves-retuned-from-playtest.md) + ## 2026-08-06 - Copy discipline across the whole game - Intent: (see session log) diff --git a/wiki/log/decisions/2026-08-06.md b/wiki/log/decisions/2026-08-06.md index c5a0b4d4..6e15b88b 100644 --- a/wiki/log/decisions/2026-08-06.md +++ b/wiki/log/decisions/2026-08-06.md @@ -67,11 +67,23 @@ and so a later change knows it is reopening a decision. - Discovery rides the persona audit rather than ambient evidence reads, on the reasoning that a trace is not a confession. -### OPEN - -- Whether the two consequence curves should stay linear. Nothing has been - played against them yet; a playtest is the next evidence, not another - argument. +### RESOLVED SAME DAY (playtest) + +- The curves stay linear; their **range** was wrong and is retuned. Playing + `reopened-untouched` to both endings from a staged late-game save showed the + shaken threshold behaving exactly as affirmed (the -10 ending leaves her at + 90 and unshaken, the -25 ending at 75 and shaken) but the consequence + arriving almost unfelt: a multi-day gaslighting campaign moved her witness + weight only 1.00 -> 0.81, because both curves interpolated across the whole + axis and so needed a -80 swing that no authored ending approaches. +- New `SELF_TRUST_CONSEQUENCE_FLOOR = 60` — consequences now span the band + plots really cover. The same deep ending lands 0.63; a second story + saturates the effect. Below 60 the axis keeps falling with no further + behavioral change, so stacking reads as a longer way back rather than a + deeper cut. +- Rejected: enlarging the authored deltas instead. That would let one story + nearly destroy a person and would spend the room erosion needs to accumulate + across several. Owner: runtime actuals in [sim-mechanics.md](../../mechanics/sim-mechanics.md#social-wikimechanicssocialmd), diff --git a/wiki/mechanics/sim-mechanics.md b/wiki/mechanics/sim-mechanics.md index 910de6a7..f7e1dd66 100644 --- a/wiki/mechanics/sim-mechanics.md +++ b/wiki/mechanics/sim-mechanics.md @@ -356,10 +356,19 @@ clause (see wiki/log/2026-07-05-demolition.md). the line where doubt becomes behavior. The threshold sits at 80 precisely so the deep authored erosion (-25) crosses it and the glancing one (-10) does not: doubt you carry is not doubt that changes what you do. Consequences - scale linearly between floor and steady — `Person::witness_weight` runs + scale linearly from steady down to `SELF_TRUST_CONSEQUENCE_FLOOR = 60` — + deliberately not the axis floor — with `Person::witness_weight` running 1.0 down to 0.4 (a fully shaken witness still converts 40% of what they see into suspicion) and `Person::task_reliability` 1.0 down to 0.5, multiplying - the asset's own rating. That product is `Person::task_success_at`, the one + the asset's own rating. Both are `Person::erosion_progress` scaled so they + cannot drift apart. Retuned 2026-08-06 after the playtest ran the shipped + story to both endings: the curves had spanned the whole axis, needing a -80 + swing no authored ending approaches, so the game's deepest ending moved a + witness only 1.00 -> 0.81 and the entire interesting stretch was unreachable + by any content that exists. Across the band plots really cover, that ending + now lands 0.63 and a second story saturates it. Below 60 the axis keeps + falling without further behavioral change: stacking registers as a longer + way back, not a deeper cut. That product is `Person::task_success_at`, the one authority the asset task roll uses and the only asset success number a player surface may print (social.md criterion 10): a complicit asset rated 0.85 held at the erosion floor is rolled at 0.425, half its rating. Neither diff --git a/wiki/mechanics/social.md b/wiki/mechanics/social.md index 3f0b6e52..0862e270 100644 --- a/wiki/mechanics/social.md +++ b/wiki/mechanics/social.md @@ -37,10 +37,10 @@ Status note: IMPLEMENTED (B1 social baseline). Current state: observer-local integrity, correlation, grants, and lifecycle; each persona-mediated act binds one named instance. Marcus's recruit route holds end-to-end. - A 2026-07-27 amendment adds the **self-trust axis** below, implemented - 2026-08-06; its - implementation rides the reopened `plots` work order (plots.md criterion - 12) and is not yet in the sim. + A 2026-07-27 amendment adds the **self-trust axis** below. It is + implemented as of 2026-08-06 through the reopened `plots` work order + (plots.md criterion 12), and its consequence curves were retuned the same + day against a playtest of the shipped story. Per-amendment history is in the dated `wiki/log/` entries from 2026-07-08 onward. Stage: B1 — The Basement @@ -77,8 +77,8 @@ to the site and completes it gains disposition through this same integral landed 2026-07-12). No influence token is pushed — the integral is the one truth. -**Self-trust (ADOPTED 2026-07-27; implementation rides the reopened `plots` -work order).** Every person also carries **self-trust**: their confidence in +**Self-trust (ADOPTED 2026-07-27, IMPLEMENTED 2026-08-06).** Every person +also carries **self-trust**: their confidence in their own perception and memory. Suspicion is what they believe about the world; disposition is what they feel about you; self-trust is whether they believe *themselves*. It exists because the corpus modeled deceit as asks @@ -102,12 +102,16 @@ cannot be trusted. Rules: watched your robot cross the hall tells no one, because last month the logs contradicted the thing they were certain happened. This changes what they do with exact knowledge; it never rewrites the event or removes their - acquired evidence. This is the strategic payoff and it is bounded [TUNE]. + acquired evidence. This is the strategic payoff, and its size is decided + rather than provisional: the consequence curves span steady down to 60, the + band authored plots actually reach, so one deep story lands most of the + effect (retuned 2026-08-06 from playtest evidence; runtime actuals in + sim-mechanics.md). - **A shaken person is also a worse tool.** Erosion cuts both ways: a destabilized person re-checks, second-guesses, and mis-executes, so their - asset task reliability degrades below their knowledge-level baseline - [TUNE]. Gaslighting a person and relying on them are in tension by - design. + asset task reliability degrades below their knowledge-level baseline, on the + same curve and the same reachable band. Gaslighting a person and relying on + them are in tension by design. - **Erosion never regresses knowledge.** Low self-trust changes reporting and reliability behavior only. It cannot downgrade a person's knowledge level, erase observer awareness, or lower a Knowing asset's certainty @@ -125,8 +129,9 @@ cannot be trusted. Rules: carry. Band names, thresholds, witness weights, reliability penalties, and recovery -rates are [TUNE]; runtime actuals belong in sim-mechanics.md when the axis -lands. +rates are decided as of 2026-08-06 — affirmed, then retuned once against a +playtest of the shipped story. Runtime actuals live in sim-mechanics.md; +changing any of them reopens that decision rather than filling a placeholder. **Actions** (cost Operations compute; most require a communication channel — at minimum the email account from day-job trust): -- 2.51.2