You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
W105.1-5 — Contract amendments for four Stable Life gaps plus exists/count collections (#457)
* W105.1-5 — Contract amendments for four Stable Life gaps plus exists/count collections
Modifier.target grows player.reputation.* (travel-time deferred), ItemDefinition.weeklyCostCents
gains charge semantics, HousingDefinition gains utilitiesCents/transportCents folded into the
existing rent arrears pipeline, NPCDefinition gains startingMemories, and Condition.collection
resolves against a closed set of seven state arrays for exists/count (no new core operator --
04-core already ships the mechanism, this kind just never wired it). Decision log entries for
each in 90-decisions.md. GameOfLife issues #107-#110.
* W105.3 — Fold in the vehicle transport waiver from games/03-game-design.md sec16.4
The user supplied the companion game design doc directly, revealing "Transport ...
waived if the player owns a vehicle" -- an asymmetry the original W105.3 amendment
missed (transportCents was unconditional, same as utilitiesCents). Added a reserved
"vehicle" tag on ItemDefinition.tags that housing checks against player.inventory;
utilitiesCents keeps no such waiver, matching sec16.4's own asymmetry. Revised the
90-decisions.md entry in place rather than superseding it, since the PR hasn't merged.
* Regenerate docs/docs/guide.md to fix the staleness gate
Took PR #458's regenerated guide as the baseline (its own drift, unrelated to
this branch) and additively covered this branch's five W105 contract changes:
player.reputation.* as a writable modifier target, item weeklyCostCents charge
semantics, housing's three-component weekly charge plus the vehicle transport
waiver, NPC startingMemories, and the exists/count collection set. Stamped with
-StampGuide; ./build/Test-Documentation.ps1 passes clean.
The first row is this section's own motivating example: *a modifier that sets a need to a fixed
@@ -4660,6 +4674,8 @@ interface HousingState {
4660
4674
4661
4675
damage: number; // 0–100, mutable
4662
4676
weeklyCostCents: Cents;
4677
+
utilitiesCents: Cents; // §7.4 — W105.3, stamped from HousingDefinition at move-in; 0 if absent there
4678
+
transportCents: Cents; // §7.4 — W105.3, stamped from HousingDefinition at move-in; 0 if absent there
4663
4679
depositPaidCents: Cents;
4664
4680
4665
4681
rentDueWeek: number;
@@ -4832,6 +4848,21 @@ interface Modifier {
4832
4848
Application order, stacking and expiry are §6.1's — this is the content shape that produces the
4833
4849
`StatusEffect.modifiers` (§2.3) `resolve` reads.
4834
4850
4851
+
**The writable target set, stated exactly (W105.1).** Two different mechanisms make a
4852
+
`target` legal, and both are closed sets:
4853
+
4854
+
| Mechanism | Legal targets | How the value is produced |
4855
+
|---|---|---|
4856
+
| Read-time layering (§6.1) | `player.needs.*`, `player.attributes.*`, `player.skills.*`, `player.reputation.*` | `derivedValueResolver.resolve` recombines `activeEffects` against the stored base on every read — nothing is ever written back to state |
4857
+
| A specific system's own recompute | `calendar.committedTimeUnits` | Not a `DerivedPath` — a genuinely stored field with no per-read layering. `time_commit` (§3) is the one place this contract describes recomputing it, by applying this same order/stacking/rounding rule once, at the start of the week |
4858
+
4859
+
Nothing else is writable: the four formula-only `DerivedPath` members (§6.1's table above) are
4860
+
`read_only_field`, and any `target` naming a field outside both rows — a plain stored value
4861
+
with no recompute system of its own, such as `player.finances.cashCents` — is equally
4862
+
`read_only_field`, because nothing exists to apply the modifier's `operation` to it. This
4863
+
table is the Tier 1 check (§14) stated as data rather than as a rule to re-derive from the two
4864
+
paragraphs it was previously scattered across.
4865
+
4835
4866
**`multiply`'s arithmetic, stated precisely.** `value` is basis-points-shaped: `value/100` is
4836
4867
the percentage change, so `value: 250` means "+2.50%" (a factor of `1.0250`), matching this
4837
4868
kind's `BasisPoints` convention (§2) exactly even though the field itself is typed `number`
0 commit comments