Skip to content

Commit bd4a2d9

Browse files
claudehyperpolymath
authored andcommitted
migration: C10 NO_NEW_BRAINS — utils/tools/companions/narrative/proven
All 21 files classified as host-side senses. 9 bridge files wrap already-live wasm brains (moletairecoprocessors, moletairehunger, missionbriefing, safefloat, passwordcracker, portscanner, colorpalette, fontscale, gamei18n). Float-wall: MoletaireHunger (f64 physics; integer enum functions already extracted), SafeAngle (atan2/cos/sin/mod_float). String-wall: ProvenError, MoletairePersistence, Locales (~650 string pairs, 5 languages), PolyglotI18n (String.replaceAll, async fetch). Effect-gated: Announcer, DomA11y, ColorPalette, KeyboardNav, PanicHandler, UserSettings. No new wasm produced; no 4-gate run. Evidence in EVIDENCE-C10.adoc. https://claude.ai/code/session_01WoKhFQePiRsAj7aqnxbG8s
1 parent 463e835 commit bd4a2d9

3 files changed

Lines changed: 192 additions & 2 deletions

File tree

proposals/MIGRATION-PLAN.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,8 @@ Heuristic:
198198
| C5 | DONE | Engine coprocessors (2026-06-05, Opus). *2 integer brains extracted + 9 senses classified.* `Maths` (clamp/lerp-milli/dist_sq — float-wall convention, sqrt host-side) and — the strategic one — `Random`, the deterministic **xmur3 + mulberry32 PRNG**, the multiplayer-reproducibility backbone (host iterates the seed string + does the final u32→[0,1) float div; brain owns the i32 mixing). *Four gates green:* 2/2 compile, *2108/2108 parity* (Random **bit-exact** vs the JS source over the full i32 domain + UTF-16 code units, incl. the `>>>` emulation + signed-i32 multiplier constants), G3 n/a (transforms/mixing), 2/2 assail-clean. Senses (classified, not migrated): 5 `*Coprocessor` FFI bridges, Resize/GetResolution (float+DOM), Audio (Pixi), Navigation (screen-stack orchestration + async asset load, effect-gated), WaitFor (timing). Evidence: `migrated/EVIDENCE-C5.adoc`. NEXT: C11 (done below).
199199
| C11 | DONE | UI and accessibility coprocessors (2026-06-05) — *classified, NO_NEW_BRAINS.* All 10 files are host-side senses. `DualAlert.res` integer core (alert-level ordinals, escalation, trigger-milli, scrub, overall-threat, dispatch predicates) was already extracted in C6 (`DualAlert.affine`, 613/613 parity, LOSSLESS boundary proof). `DualAlertCoprocessor.res` is the existing ReScript FFI bridge to that wasm. `ForceLayoutCoprocessor.res` wraps `forcelayout.wasm`, a float-only physics kernel (euclidean/repulsion/attraction/velocity/alpha — f64 throughout; float-wall: brain stays host-side). Remaining 7 files (`Button`, `HubButton`, `NavButton`, `Label`, `VolumeSlider`, `InventoryUI`, `HardwareWiring`) are pure PixiJS/PixiUI senses with zero separable integer computation. No 4-gate run. Evidence: `migrated/EVIDENCE-C11.adoc`. NEXT: C9.
200200
| C9 | DONE | Game-loop / AffineTEA / VeriSim types (2026-06-05) — *classified, NO_NEW_BRAINS.* All 16 files are host-side senses. *4 bridge files* wrap already-live wasm brains: `AffineTEA.res` → `titlescreen.wasm` (TEA title-screen state machine), `AffineTEARouter.res` → `router.wasm` (affine nav back-stack), `PixiCoprocessor.res` → `pixi.wasm` (AffineScript PixiJS scene driver), `VmCoprocessor.res` → `vmcoprocessor.wasm` (C2). *8 VeriSimDB/Burble HTTP clients* (`SaveGame`, `VeriSimDrift`, `VeriSimFederation`, `VeriSimHexad`, `VeriSimProvenance`, `VeriSimSearch`, `VeriSimVcl`, `BurbleIntegration`) are async `fetch` wrappers — effect-gated throughout. `VeriSimTypes.res` enum variants (`modality`/`hexadStatus`/`driftLevel`) appear integer-clean but `modalityToString`/`modalityFromString` use string literals and all enums are used only in string-bearing records — string-wall gated, no standalone computation. `VeriSimError.res` constructors all carry `string` payloads — string-wall gated. `Main.res` / `GameLoop.res` are effect-gated orchestration; GameLoop integer counters are trivial increments interleaved with float physics and mutable JS objects. No 4-gate run. Evidence: `migrated/EVIDENCE-C9.adoc`. NEXT: C10.
201-
| C10..C12 | TODO | Remaining clusters per `migration-map.json`: *C10 (21, utils/tools/companions/narrative/proven — mixed)* next; then C12 (43, render-glue screens/PixiJS bindings — senses-heavy, migrated last). Established scalar/enum/predicate recipe. Genuine compiler gates remain: string wall (52 non-test .res — note the `[len:i32][utf8]` layout is already in `codegen.ml:375`, only the *ops* are missing), effect wall (110); unary-`~` codegen bug is a candidate Phase-F fix.
201+
| C10 | DONE | Utils/tools/companions/narrative/proven (2026-06-05) — *classified, NO_NEW_BRAINS.* All 21 files are host-side senses. *9 bridge files* wrap already-live wasm brains: `moletairecoprocessors.wasm` (Moletaire behaviour FSM), `moletairehunger.wasm` (hunger ordinals), `missionbriefing.wasm` (mission briefing state machine), `safefloat.wasm` (safe-float arithmetic), `passwordcracker.wasm` (password-crack score), `portscanner.wasm` (port-scan classifier), `colorpalette.wasm` (color lookup), `fontscale.wasm` (font-scale arithmetic), `gamei18n.wasm` (plural-form + language-cycle). Float-wall: `MoletaireHunger.res` (f64 gravity/hunger physics — integer enum functions already in `moletairehunger.wasm`), `SafeAngle.res` (Math.atan2/cos/sin/mod_float, all f64). String-wall: `ProvenError.res` (all constructors carry string fields), `MoletairePersistence.res` (equipmentToString/FromString), `Locales.res` (5-language translation dicts, ~650 string pairs), `PolyglotI18n.res` (String.replaceAll, async fetch of locale JSON). Effect-gated: `Announcer.res` (AccessibilitySettings + DomA11y), `DomA11y.res` (%raw DOM), `ColorPalette.res` (AccessibilitySettings mutable refs; color tables already in wasm), `KeyboardNav.res` (%raw window events), `PanicHandler.res` (Console.error), `UserSettings.res` (Storage/Audio/DesktopIntegration; stance enum string-serialized). No 4-gate run. Evidence: `migrated/EVIDENCE-C10.adoc`. NEXT: C12.
202+
| C12 | TODO | Remaining cluster per `migration-map.json`: *C12 (43, render-glue screens/PixiJS bindings — senses-heavy, migrated last)*. Established scalar/enum/predicate recipe. Genuine compiler gates remain: string wall (52 non-test .res — note the `[len:i32][utf8]` layout is already in `codegen.ml:375`, only the *ops* are missing), effect wall (110); unary-`~` codegen bug is a candidate Phase-F fix.
202203
| F+ | TODO | Compiler walls (string backend, then effects).
203204
| Ω | TODO (access-gated) | Cutover + ReScript extinction.
204205
|===
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
// SPDX-License-Identifier: AGPL-3.0-or-later
2+
// SPDX-FileCopyrightText: 2025-2026 Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
3+
= Cluster C10 (utils/tools/companions/narrative/proven) — migration evidence (2026-06-05)
4+
:toc: macro
5+
6+
[IMPORTANT]
7+
====
8+
*Verdict: NO_NEW_BRAINS — coprocessor bridges, float-wall physics, string-wall
9+
i18n/persistence/errors, and effect-gated accessibility/settings orchestration.*
10+
All 21 files are host-side senses. No new AffineScript kernels are required
11+
because:
12+
13+
1. Nine `*Coprocessor.res` bridge files are pure `external` FFI declarations
14+
wrapping already-compiled wasm brains:
15+
`moletairecoprocessors.wasm` (Moletaire behaviour FSM),
16+
`moletairehunger.wasm` (hunger ordinals — already extracted),
17+
`missionbriefing.wasm` (mission briefing state machine),
18+
`safefloat.wasm` (safe-float arithmetic coprocessor),
19+
`passwordcracker.wasm` (password-crack score engine),
20+
`portscanner.wasm` (port-scan result classifier),
21+
`colorpalette.wasm` (color-palette lookup),
22+
`fontscale.wasm` (font-scale arithmetic),
23+
`gamei18n.wasm` (plural-form selection + language-cycle arithmetic).
24+
2. Two float-wall files (`MoletaireHunger.res`, `SafeAngle.res`):
25+
`MoletaireHunger.res` contains gravity/hunger physics
26+
(`calculatePull`, `calculateTotalPull`, `calculateHungerRate` — all f64);
27+
the integer-flavoured `getBehaviour`/`hungerColor`/`willEatObjective` enum
28+
functions are already extracted to `moletairehunger.wasm`.
29+
`SafeAngle.res` is pure trigonometry (`Math.atan2`, `normalize`,
30+
`Math.cos`, `Math.sin`, `mod_float`) — float-wall throughout.
31+
3. String-wall files: `ProvenError.res` (all constructors carry `operation`,
32+
`message`, `errorType` string fields), `MoletairePersistence.res`
33+
(`equipmentToString`/`equipmentFromString` string serialization via
34+
`localStorage`), `Locales.res` (five-language translation dicts; all data
35+
is string key→value, `getTranslations(string)` dispatches on string param),
36+
`PolyglotI18n.res` (`String.replaceAll`, JSON string parsing, async
37+
`fetch` of locale JSON files, string template literals in `tw`/`tn`).
38+
4. Effect-gated files: `Announcer.res` (gated on
39+
`AccessibilitySettings.isScreenReaderEnabled()`; passes string messages to
40+
`DomA11y.announce`), `DomA11y.res` (all `%raw` DOM manipulation —
41+
`window.matchMedia`, `document.createElement`, `region.textContent`),
42+
`ColorPalette.res` (branches on `AccessibilitySettings.isHighContrastEnabled()`
43+
and `getColorBlindMode()` mutable JS refs; integer color tables are
44+
already extracted to `colorpalette.wasm`), `KeyboardNav.res` (all `%raw`
45+
`window.addEventListener/removeEventListener`, `e.key`, `e.preventDefault`),
46+
`PanicHandler.res` (`Console.error`, string template literals),
47+
`UserSettings.res` (`Storage` API, `Audio` API, `DesktopIntegration`;
48+
the `stance` enum serializes via string literals and has no standalone
49+
integer computation).
50+
51+
No 4-gate recipe is applied; no new wasm is produced.
52+
====
53+
54+
toc::[]
55+
56+
== File-by-file disposition
57+
58+
[cols="3,1,4",options="header"]
59+
|===
60+
| File | Disposition | Reason
61+
| `src/app/companions/MoletaireCoprocessorsCoprocessor.res` | SENSES (bridge) | ReScript FFI wrapping `MoletaireCoprocessorsBridge.js` → `moletairecoprocessors.wasm`. Pure `external` declarations. Moletaire behaviour FSM brain already live.
62+
| `src/app/companions/MoletaireHunger.res` | SENSES (float-wall) | Gravity/hunger physics: `calculatePull`, `calculateTotalPull`, `calculateHungerRate` — all f64. Integer-flavoured functions (`getBehaviour`, `hungerColor`, `willEatObjective`) already extracted to `moletairehunger.wasm`.
63+
| `src/app/companions/MoletaireHungerCoprocessor.res` | SENSES (bridge) | ReScript FFI wrapping `MoletaireHungerCoprocessorBridge.js` → `moletairehunger.wasm`. Pure `external` declarations. Hunger-ordinal brain already live.
64+
| `src/app/companions/MoletairePersistence.res` | SENSES (string-wall gated) | localStorage persistence: `equipmentToString`/`equipmentFromString` string serialization, `Storage.getString`/`setBool`. String-wall prevents extraction.
65+
| `src/app/narrative/MissionBriefingCoprocessor.res` | SENSES (bridge) | ReScript FFI wrapping `MissionBriefingCoprocessorBridge.js` → `missionbriefing.wasm`. Pure `external` declarations. Mission briefing state machine already live.
66+
| `src/app/proven/ProvenError.res` | SENSES (string-wall gated) | Error type `provenError` with `operation: string`, `message: string`, `errorType: string` fields. All constructors string-bearing. String-wall prevents extraction.
67+
| `src/app/proven/SafeAngle.res` | SENSES (float-wall) | Pure trigonometry: `Math.atan2`, `normalize`, `Math.cos`, `Math.sin`, `mod_float`. All f64 operations. No integer brain.
68+
| `src/app/proven/SafeFloatCoprocessor.res` | SENSES (bridge) | ReScript FFI wrapping `SafeFloatCoprocessorBridge.js` → `safefloat.wasm`. Pure `external` declarations. Safe-float arithmetic brain already live.
69+
| `src/app/tools/PasswordCrackerCoprocessor.res` | SENSES (bridge) | ReScript FFI wrapping `PasswordCrackerCoprocessorBridge.js` → `passwordcracker.wasm`. Pure `external` declarations. Password-crack score brain already live.
70+
| `src/app/tools/PortScannerCoprocessor.res` | SENSES (bridge) | ReScript FFI wrapping `PortScannerCoprocessorBridge.js` → `portscanner.wasm`. Pure `external` declarations. Port-scan classifier brain already live. Inline `deviceTypeId`/`securityLevelId` enum dispatch needs no wasm.
71+
| `src/app/utils/Announcer.res` | SENSES (effect-gated) | Screen-reader announcer: gated on `AccessibilitySettings.isScreenReaderEnabled()`, passes string messages to `DomA11y.announce`. No integer computation.
72+
| `src/app/utils/ColorPalette.res` | SENSES (effect-gated) | Color lookup tables (`alertColor(int)`, `deviceColor`, `securityColor`) read `AccessibilitySettings.isHighContrastEnabled()` and `getColorBlindMode()` mutable JS refs. Integer color tables already extracted to `colorpalette.wasm`. Effect-gated selector stays host-side.
73+
| `src/app/utils/ColorPaletteCoprocessor.res` | SENSES (bridge) | ReScript FFI wrapping `ColorPaletteCoprocessorBridge.js` → `colorpalette.wasm`. Pure `external` declarations. Color-palette lookup brain already live.
74+
| `src/app/utils/DomA11y.res` | SENSES (effect-gated) | DOM accessibility utilities: all `%raw` — `window.matchMedia`, `document.createElement`, `region.textContent`, event listeners. No integer computation.
75+
| `src/app/utils/FontScaleCoprocessor.res` | SENSES (bridge) | ReScript FFI wrapping `FontScaleCoprocessorBridge.js` → `fontscale.wasm`. Pure `external` declarations (`scaleFloat`, `scaleInt`, `clampScale`, `scaleIntClamped`). Font-scale arithmetic brain already live.
76+
| `src/app/utils/GameI18nCoprocessor.res` | SENSES (bridge) | ReScript FFI wrapping `GameI18nCoprocessorBridge.js` → `gamei18n.wasm`. Pure `external` declarations (`languageClamp`, `nextLanguage`, `selectPluralForm`). Plural-form selection + language-cycle brain already live.
77+
| `src/app/utils/KeyboardNav.res` | SENSES (effect-gated) | All `%raw` window event wiring: `window.addEventListener/removeEventListener('keydown')`, `e.key`, `e.preventDefault`. No integer computation.
78+
| `src/app/utils/Locales.res` | SENSES (string-wall gated) | Five-language translation dicts (~130 keys × 5 languages). `getTranslations(string)` dispatches on string lang-code parameter. All data is string key→string value. String-wall throughout.
79+
| `src/app/utils/PanicHandler.res` | SENSES (effect-gated) | Error reporting: `Console.error`, string template literals, `Promise.resolve()`. No integer computation.
80+
| `src/app/utils/PolyglotI18n.res` | SENSES (string-wall + effect-gated) | Polyglot i18n wrapper: async `fetch` of locale JSON files, `String.replaceAll` interpolation, `tw`/`tn` string ops, mutable `ref<string>` language state. String-wall + effect-wall prevents extraction.
81+
| `src/app/utils/UserSettings.res` | SENSES (effect-gated) | Settings persistence: `Storage` API (getString/setBool/setNumber), `Audio` API (setMasterVolume/setBgmVolume/setSfxVolume), `DesktopIntegration`. The `stance` enum (Jessica/Q) serializes via string literals — string-wall gated; no standalone integer computation.
82+
|===
83+
84+
== Already-live wasm brains referenced by C10 bridges
85+
86+
The nine bridge files reference wasm kernels that are already compiled and
87+
live in `public/assets/wasm/`:
88+
89+
[cols="2,2,3",options="header"]
90+
|===
91+
| Bridge file | Wasm target | Brain description
92+
| `MoletaireCoprocessorsCoprocessor.res` | `moletairecoprocessors.wasm` | Moletaire companion behaviour FSM. Position/action decisions for the robotic mole companion.
93+
| `MoletaireHungerCoprocessor.res` | `moletairehunger.wasm` | Hunger ordinal decisions: `getBehaviour`, `hungerColor`, `willEatObjective`, `objectiveAtRisk`. Already extracted; float-wall physics stays host-side.
94+
| `MissionBriefingCoprocessor.res` | `missionbriefing.wasm` | Mission briefing state machine. Screen-progression logic.
95+
| `SafeFloatCoprocessor.res` | `safefloat.wasm` | Safe-float arithmetic coprocessor. Guards float operations with formal safety bounds.
96+
| `PasswordCrackerCoprocessor.res` | `passwordcracker.wasm` | Password-crack score engine. Integer scoring for crack success/failure states.
97+
| `PortScannerCoprocessor.res` | `portscanner.wasm` | Port-scan result classifier. Maps scan outcomes to integer result codes.
98+
| `ColorPaletteCoprocessor.res` | `colorpalette.wasm` | Color-palette lookup. Integer RGB hex values for alert/device/security levels.
99+
| `FontScaleCoprocessor.res` | `fontscale.wasm` | Font-scale arithmetic. `scaleFloat`, `scaleInt`, `clampScale`, `scaleIntClamped` pure integer/float pixel-size operations.
100+
| `GameI18nCoprocessor.res` | `gamei18n.wasm` | Plural-form selection and language-cycle arithmetic. `languageClamp` (0..4 band), `nextLanguage` (EN→ES→FR→DE→JA→EN cycle), `selectPluralForm` (count == 1 → singular).
101+
|===
102+
103+
C10 being NO_NEW_BRAINS does not add to the wasm surface — all nine brains
104+
were already live before C10 was triaged.
105+
106+
== MoletaireHunger.res — float-wall analysis
107+
108+
`MoletaireHunger.res` contains f64 physics that cannot cross the float-wall:
109+
110+
* `calculatePull(dist: float, strength: float): float` — gravitational
111+
attraction formula (`strength / (dist * dist)`). Pure f64.
112+
* `calculateTotalPull(positions: array<...>, strength: float): (float, float)`
113+
— sum of pull vectors over all attractor positions. f64 throughout.
114+
* `calculateHungerRate(hungerMultiplier: float, ...): float` — speed-based
115+
hunger drain. f64 physics.
116+
117+
The integer-flavoured functions are NOT extractable because they are already
118+
in `moletairehunger.wasm` from a prior migration pass:
119+
120+
* `getBehaviour(hungerScore: float): behaviour` — float threshold → enum.
121+
* `hungerColor(hungerScore: float): int` — float → RGB hex. Already in wasm.
122+
* `willEatObjective(...)`, `objectiveAtRisk(...)` — float comparisons.
123+
124+
Verdict: no new brain needed; the integer surface is already live.
125+
126+
== SafeAngle.res — float-wall analysis
127+
128+
All six functions in `SafeAngle.res` are pure f64 trigonometry:
129+
130+
* `fromAtan2(dy: float, dx: float): safeAngle` — `Math.atan2`.
131+
* `normalize(a: safeAngle): safeAngle` — fmod-based angle normalization.
132+
* `diff(a: safeAngle, b: safeAngle): safeAngle` — angle subtraction with
133+
normalization.
134+
* `cos(a: safeAngle): float` — `Math.cos`.
135+
* `sin(a: safeAngle): float` — `Math.sin`.
136+
* `toFloat(a: safeAngle): float` — identity cast.
137+
138+
The float-wall convention (AffineScript wasm backend has no f64 `sqrt`
139+
or general float codegen) requires these to remain host-side. The `safefloat.wasm`
140+
brain handles safe arithmetic on simple float ranges; trigonometry is a
141+
separate concern with no integer-only reformulation possible.
142+
143+
== String-wall analysis: ProvenError, MoletairePersistence, Locales, PolyglotI18n
144+
145+
[cols="1,1,4",options="header"]
146+
|===
147+
| File | Wall type | Why NOT extracted
148+
| `ProvenError.res` | String-wall | Every constructor (`ProvenError` record) carries `operation: string`, `message: string`, `errorType: string` fields. No integer computation separable from the string payloads.
149+
| `MoletairePersistence.res` | String-wall + effect | `equipmentToString`/`equipmentFromString` use string serialization throughout; `Storage.getString`/`setBool` are DOM-side effects. No integer brain separable.
150+
| `Locales.res` | String-wall | Five-language dicts (~650 string pairs total). `getTranslations(langCode: string)` dispatches on a string parameter and returns `dict<string>`. No integer computation exists — the entire module is translation data.
151+
| `PolyglotI18n.res` | String-wall + effect | `tw` uses `String.replaceAll`; `tn` compares `count == 1.0` (float); async `fetch` for locale JSON; mutable `ref<string>` language state. String ops throughout; effect-wall (async + mutable ref).
152+
|===
153+
154+
In contrast, `GameI18nCoprocessor.res` already wraps `gamei18n.wasm` which
155+
handles the *integer* core (`languageClamp`, `nextLanguage`,
156+
`selectPluralForm`) — the AffineScript brain for this cluster's numeric
157+
i18n logic is already live.
158+
159+
== UserSettings.res — stance enum analysis
160+
161+
`UserSettings.res` contains a 2-value `stance` enum (Jessica | Q).
162+
At first glance it appears potentially extractable, but:
163+
164+
1. `getCharacterStance()` reads `Storage.getString(keyStance)` and matches on
165+
string values `"Q"` / `_` — string-wall gated.
166+
2. `setCharacterStance(s: stance)` serializes to string literals `"Jessica"` /
167+
`"Q"` before calling `Storage.setString` — string-wall gated.
168+
3. The remaining functions (`getMasterVolume`, `getBgmVolume`, `getSfxVolume`,
169+
`init`, `setMasterVolume`, `setBgmVolume`, `setSfxVolume`,
170+
`setSystemTrayEnabled`) are pure effect-gated orchestration over `Audio`
171+
and `Storage` APIs with float volume values.
172+
173+
No standalone integer brain is separable from the string serialization and
174+
effect-heavy orchestration.
175+
176+
== Impact on remaining clusters
177+
178+
C10 being NO_NEW_BRAINS does not affect the C12 roadmap. All nine wasm
179+
brains referenced by C10 bridges are already live. The utilities/tools/
180+
companions/narrative/proven modules remain host-side ReScript throughout
181+
Phase Ω. The completion-drive directive proceeds to *C12*.

0 commit comments

Comments
 (0)