Update 2.198
8/1/2026
v2.198.0.0BETAMINOR
SeymourJul 31, 2026
P3-L2: `GameEnvironmentProbe` (runtime environment health check)
Core/GameEnvironmentProbe.cs(new, 10 tests): version detector / health check of the runtime environment — fulfills the P3 contract (prompt L410-416: detector · install/config/permission/path contract · fallback · actionable error without raw stack trace · compatibility matrix). Detects:FFX.exe(FileVersionInfo version + region viadata\jppc/intl/us/eu),modules\ffx-probe.dll+modules\FfxHooksDll.dll, active flags (config\*.flagand root), live probe viaFfxProbe_Service(MMFLocal\FFXProbeBlock_v1— IsAttached/IsHooked/Heartbeat, read-only, nothing armed). Game root discovery:FFX_GAME_ROOTenv → Steam registry →libraryfolders.vdf(unescape parse, testable) → common candidates. Typed resultGameEnvironmentReport(State Ok/Warning/Error +EnvironmentIssueCode/Message/ActionableMessage) — UI shows typed state, never a raw stack trace.- Baseline: 233/233 PASS (223 + 10 new). ### REVISION ### REVISION
v2.197.1.1
v2.198.1.0BETAPATCH
SeymourJul 31, 2026
P3-L3: operations-platform hardening (cancel/rollback/journal/lock/redaction) + resilience suite (12 tests)
Core/OperationExecutorV2.cs(hardening):ExecuteAsync(plan, CancellationToken)with checkpoints (before stage, between ops, before promote, during promote) and propagation intoStageAsync; automatic rollback on promote (failure/cancel restores already-promoted outputs from backups, or removes outputs created by this promote); journal.json in BackupRoot (states promoting/success/cancelled/failed — recovery contract, best-effort never fails the op); static lock serializing promote (concurrency contract — 2 ops on the same output never interleave); redaction (LlmRedactor) in ErrorMessage/RecoveryInstructions/journal (secret never appears on failure surfaces).FFXProjectEditor.Tests/Core/OperationResilienceTests.cs(new, 12 tests): cancel before stage / during stage (adapter observes token) → nothing written; injected promote failure → rollback of already-promoted output (original hash restored); journal failed/success + .bak backup with original bytes; concurrency (2 parallel executions same output → intact result, one complete winner); secret redacted from failure messages; empty plan → "No operations"; forbidden diff (EditSession.Build rejects field outside allowlist); OperationPlan JSON round-trip; failure receipt consistent (FilesWritten=0).- Baseline: 245/245 PASS (233 + 12 new). ### MINOR ### MINOR
v2.198.0.0
v2.198.2.0BETAPATCH
SeymourJul 31, 2026
FfxSaveSphereGrid hardening (bounds guard + native truth) + Ghidra/Fahrenheit symbol-table import into the canonical DB (8,281 renames)
FfxLib/Save/FfxSaveSphereGrid.cs(fix):FfxSaveSphereGridNodeSnapshot.Read/Write/ReadActivation/WriteActivationnow guardNodeIndex(0..859 in the legacy FFXED model) with actionableArgumentOutOfRangeException— fixes a latent OOB write into the save buffer; new constantsNativeTableBase(=8684) andNativeMaxNodeIndex(=1279) expose the native save capacity; XML docs clarify the +64 skew vsFfxSaveSphereGridRuntimeTableand that 860 is NOT the engine limit.FfxLib/Save/FfxSaveSphereGridRuntimeTable.cs(doc): cross-confirmed by the Fahrenheit/Ghidra symbol table —eiAbmDataInit(SaveSphereGrid*)@ 0xA53DE0 andMsGetSaveAbilityMap() → SaveSphereGrid*@ 0x785000 prove the state block is a real engine type; native capacity 1280 nodes / 1280 links / cursor.FfxLib/Save/FfxSaveBatchActions.cs(doc):ImportSphereGridRegiondocumented as legacy +64 model; native path pointed out (span 8684..13579) for grids >860.- RE — Fahrenheit-crew/fahrenheit (Ghidra) symbol-table import: 7,609 functions + 672 globals renamed on the base DB
ffxoficial.exe.i64(8,281 total; sources USER_DEFINED 460 + IMPORTED 2,816 + filtered ANALYSIS 7,570; never overwrites projectFFX_*names — 3,774 preserved); globals got primitive types; backupbackups_ffxoficial\ffxoficial.exe.before_ghidra_renames_20260731_231338.i64. Propagated to the team's working DBffxoficial_COPY.i64via the ida-pro-mcp plugin RPC inside the GUI (port 13338): 7,440 functions + 490 globals applied on the COPY, 17 skipped (GUI names preserved), DB saved; backupffxoficial_COPY.before_ghidra_renames_20260731_233813.i64. Findings:LpAbilityMapEnginestruct (0x12FC0; clusters[128]/nodes[1024]/links[1024] — full layout in doc), static.databuffer0x16AD870(InitLpamng @ A572E0), 12 functions with a1024loop mapped (RenderPathNodes A50290, eiAbmCalc A53570, eiAbmParaGet A54860, ClearNodeTransforms A57120, ReadAndProcessInputState A57520, BuildLinkBatchSegment A57710, UpdatePlacementSlotTransform A58080, DialogDispatch A583E0, InitPlacementGrid A5B230, +3), render 861 (681DB0/7F4900), original nameseiAbm*/+AbmapState_*/abmap_*,SaveSphereGridtype confirmed. Key conclusion: the native save already supports 1280/1280 — the bottleneck to exceed 1024 is the static runtime struct + loops + render, not the save. Doc:docs/reverse/FFX_GHIDRA_FAHRENHEIT_SYMBOL_IMPORT_2026-07-31.md; scripts/reports inwork/_fahrenheit_probe/. - Status:
Needs Testing— green build; new guards have no out-of-range consumers (no code usage beyond docs). ### PATCH
v2.198.1.0
v2.198.2.1BETAREVISION
SeymourJul 31, 2026
fahrenheit-excel: real kernel field names applied to the editor (KeyItem/Important + Treasure/takara) + "Excel" container documented
- Source: second fahrenheit repo (
fahrenheit-excel) with 8 new structs +excel.csrewrite (Excel container:ExcelProlog0x8 +ExcelHeader0xC +ExcelTextOffset0x4 — matches ourCustomization_File.ReadHeader, HeaderLength 0x14). FfxLib/Common/KeyItem_File.cs+ KeyItemEditor (rename):PrimerByte10/RawByte11/RawByte12/OrderingByte13→ItemType/ItemValue/Icon/Number(real Ghidra names; 0x10 = "is Al Bhed Primer?", 0x13 = primer number) — XAML, summaries and RT0 updated.FfxLib/Treasure/Treasure_File.cs+ TreasureEditor + BukiGetTreasureCatalog + TaskRewardGameFileLoader + TreasureRt0 (rename):Treasure_Entry.Type→ItemId(confirms fahrenheitTreasure{item_id u16}); VMTreasureRow.Type/TypeHex/TypeDecimal→ItemId/ItemIdHex/ItemIdDecimal; XAML bindings updated.- Confirmations:
MixRecipe= ushort[0x70] matchesMixTable_File(EntryLength 0xE0);SphereGridNodeType.amount@0x14confirmsIncreaseAmount;SphereGridNodeTypeInfo→SphereGridNodeTypeUiInfo(lpamngnode_type_infosarray is UI-only). - Documented (future writers):
Sphere(ACTIVATOR/MODIFIER + 11-stat bitmask + NORMAL/UNLIMITED range),Rate,WeaponName,HelpText/NameHelpText,Treasure. - Baseline: 245/245 PASS · Build 0 errors. Doc:
docs/reverse/FFX_GHIDRA_FAHRENHEIT_SYMBOL_IMPORT_2026-07-31.md§fahrenheit-excel. ### PATCH
v2.198.2.0
v2.198.3.0BETAPATCH
SeymourJul 31, 2026
P3-L4: release — `scripts/release_manifest.ps1` (verifiable manifest) + process doc
scripts/release_manifest.ps1(new, operational): release manifest — version read from<Version>in the csproj (source of truth), SHA-256 of every.exe/.dllbuild artifact (+.sha256sidecars via .NET SHA256 — compatible with this machine's PS), first changelog entry (cross-check),gitCommit/gitDirty(dirty-worktree release = alert) andsigning: "not-signed"(signature never declared done without executing). Validated: 103 artifacts from the Release build with correct hashes.docs/ai/P3_RELEASE_2026-07-31.md(new): 7-step release flow (build → tests → offline_ci → deploy all targets → manifest → hash verification → signing);.gitignoreaudit (coverage already present — bin/obj/work/.vs, no changes needed; no destructive cleanup in a worktree with foreign work); signing documented AS A PLAN (signtool/Authenticode — not executed, no certificate imported).- No editor behavior change — baseline 245/245 PASS untouched. ### PATCH
v2.198.3.3
v2.198.3.1BETAREVISION
SeymourJul 31, 2026
P3-L5: short Gemini contract (UI ↔ Core)
docs/ai/P3_GEMINI_CONTRACT_2026-07-31.md(contract based on the real types): file ownership (Core = backend / Modules+AXAML = UI); public DTOs (CapabilityDescriptor, OperationPlanPreview/ChangeSetSummary, OperationProgress, CommitReceipt, ValidationResult, OperationResult, FilePreviewSummary/OperationPreview, GameEnvironmentReport); commands (EditSession fluent, OperationExecutorV2, OperationPreview, ReceiptBuilder, GameEnvironmentProbe); typed states loading/empty/unavailable/warning/blocked/failure with real origins; ValidationIssue codes; the 10 real capability IDs; mock/provisional (heuristic Steam discovery, LAB FfxProbe_Service, opt-in LlmHttpAdapter, OperationProgress without full wiring); hard rules (UI never creates a writer outside OperationPlan; messages already redacted; AXAML/themes only with coordination). Read-only — baseline 245/245 PASS untouched. ### PATCH
v2.198.3.0
v2.198.3.2BETAREVISION
SeymourJul 31, 2026
P3-L6: per-family RT2 protocol (reproducible, logged)
docs/ai/P3_RT2_PROTOCOL_2026-07-31.md(protocol; execution = human runtime): distinct RT0/RT1/RT2 with exit gates (RT0 = CLI byte-identity gates; RT2 = reproducible before/after log + throwaway save); session prerequisites (probe deployed,ffxprobectl mon, throwaway save, editor closed); Phase Rotation family pilot in 7 steps (apply recipe → hash H2 → deploy with vanilla backup H1 → battle → 5 observed turns → read-only counter-var read → restore H1 → promotion only with log); per-family checklist (probe PROVEN/Force Battle 1 scenario/Phase Rotation pending/hooks partial/read-only probes); promotion rules (never RT0→production without RT2; never the main save; never CreateRemoteThread); Force Battle contradiction referenced (PROVEN mechanism / LAB product). Read-only — baseline 245/245 PASS untouched. ### REVISION ### REVISION
v2.198.3.1
v2.198.3.3BETAREVISION
SeymourAug 1, 2026
Gemini prompt updated: full P3 backend reflected (245/245, executor cancel/rollback/journal/lock, real adapter IDs, mandatory UI↔Core contract)
docs/ai/PROMPT_GEMINI_UI_UX_FINAL_2026-08-01.md(updated): header with version2.198.3.2+ 245/245 PASS; mandatory reading now includesP3_GEMINI_CONTRACT_2026-07-31.md(item 5 — the official UI↔Core contract); Core table with updatedOperationExecutorV2(CancellationToken 4 checkpoints, automatic rollback, journal.json, PromoteGate, redacted messages) + new typesOperationPreview/FilePreviewSummary(3-layer diff); adapter table fixed (10 registered — was "8" with 10 rows — and REAL IDs:ability-commandandatel-recipe-phase-rotation, which were wrong);GameEnvironmentProbewith discovery (env/registry/libraryfolders.vdf); new "Backend state" block (245/245, trustworthy executor, already-redacted messages, exception-free health check, 3-layer preview, release manifest, RT2 protocol, other-lane changes — FfxSaveSphereGrid bounds guard, fahrenheit renames, known annotated FAILmcyt00_21); Limits now include selective commits (lane race — nevergit add -A). No behavior change — baseline 245/245 PASS untouched. ### REVISION ### REVISION
v2.198.3.2
v2.198.3.4BETAPATCH
SeymourAug 1, 2026
SphereGrid sphere.bin adapted to the fahrenheit `Sphere` struct (real names + enums + corpus-proven validator fix)
FfxLib/SphereGrid/SphereGrid_File.cs(+Write.cs) (rename+enums):SphereGridSphereTypeEntryActionValue/ActivationBitfield/RangeValue/AlwaysZero→Behavior/Activates/Range/Reserved0x0E(Ghidra/fahrenheitSpherenames); new enumsSphereBehavior(None/Activator/Modifier),SphereTargets[Flags] (11 stats,All=0x07FF— bit order not proven, vanilla values documented),SphereRange(None/Normal/Unlimited=0x20); derived propsBehaviorKind/ActivatesTargets/RangeKind;ActionLabelfixed ("Mutator"→"Modifier").Core/Writers/SphereGridAdapter.cs(fix+hardening): keys renamed (Behavior/Activates/Range/Reserved0x0E);SpecialRolevalidator fixed 0x0F→0x1F (vanilla corpus uses special roles up to 24 — sphere.bin slots 14..29; the old validator rejected legitimate grids);Behaviorvalidated 0..2 (corpus proves only 0..2); messages cite the enums.SphereGridExplorer(rename): VMSphereGridSphereTypeEditorRow+ state + helpers + XAML updated;SetSelectedOptions/diffs/baseline renamed.- Corpus proof (jppc
battle\kernel\sphere.bin, 50 entries, elem 0x10): ACTIVATOR=1 (Ability/Power/Mana/Speed/Luck + Key L1–L4 special 8..11 + Friend 0x07FF), MODIFIER=2 (Return=1, Teleport=2, Clear=3, Master=4), range 0x01 NORMAL / 0x20 UNLIMITED; indices matchSphereGridNodeSphereRequirementKind(Ability=0..Luck=4). Doc:docs/reverse/FFX_GHIDRA_FAHRENHEIT_SYMBOL_IMPORT_2026-07-31.md§sphere.bin. - Baseline: 245/245 PASS · Build 0 errors. Status:
validated(byte-idempotent renames + RT0/RoundTrip intact). ### REVISION
v2.198.3.3
v2.198.4.0BETAPATCH
SeymourAug 1, 2026
Clean no-hook RT2 test path for True New Node + crash-theory correction + external community confirmation (1024/1024/128)
SphereGridDeployPolicy.cs(revision): the "no-hook 861/882 crashes on exit" finding came from RT2 runs of the retired v5 hook stack (manifest/sidecar/SEH) — never from a clean deploy. With today's RE (header-driven engine; staticLpAbilityMapEngine1024/1024/128; native save 1280/1280), counts ≤ 1024 need no hook. Suspected real ceiling: render (681DB0861×48 buffers +7F4900n861 >= 861gate). New opt-in overridebuilder.AllowRuntimeTestDeploy(default OFF) unlocks SaveToProject/SaveSquareToProject with changed counts for the clean test.SphereGrid_File.Builder.cs:AllowRuntimeTestDeployproperty + docs.SphereGridCanvas_DataModel.cs+SphereGridCanvas_Control.axaml: "Allow RT2 test deploy (no-hook)" toolbar checkbox;RefreshTopologySafetySummaryshows the test state (🧪 released with disposable-save warning / 🚫 blocked with the corrected explanation).- External confirmation: EvelynTSMG (fahrenheit-crew) confirmed the ceiling 1024 nodes / 1024 links / 128 clusters — exact match with the
LpAbilityMapEnginewe proved (arrays at 0x808/0xA808/0x8,.databuffer 0x16AD870). Dragoon (community) testing add/tie/expand in his editor. - Clean RT2 test protocol documented (doc RE §external confirmation): Standard → Square Mode → +1 node/+1 link → checkbox → Save → deploy → disposable save → open/move/exit → no crash = ceiling exceeded (repeat 900/1024); crash = render is the ceiling (2-byte patch, no hook).
- Baseline: 245/245 PASS · Build 0 errors. Status:
Needs Testing(human RT2). ### PATCH
v2.198.3.4
v2.198.4.1BETAPATCH
SeymourAug 1, 2026
semantic fix of ATEL comparison opcodes (0x0A/0x0B/0x0E/0x0F) — proven by interpreter decompile
- Discovery (source: noclip.website
src/FinalFantasyX/script.ts— field-script opcode enum): the codec mapping (GT=0x0A, LT=0x0B, GE=0x0E, LE=0x0F) was inverted vs noclip (LT=0x0A, GT=0x0B...). Proven by decompile ofFFX_Atel_InterpretWorkerOpcodes@0x864180+FFX_FieldVM_PopOperand@0x86DE90(pop = top): with stack[A(base), B(top)], 0x0B testsA < B, 0x0A testsA <= B(0x0E/0x0F = float variants). There is no direct "greater-than" — the compiler expressesA > Bas[B, A] + 0x0B(B < A). The RT0 gate (structural round-trip) cannot catch semantic errors — only the decompile exposes them. - Fix:
AiVarConditionBuilder(GreaterThan/GreaterOrEqual now emit swapped order[N, var]+ LT/LE; LessOrEqual fixed 0x0F→0x0A),AiAutomation(field/status/Overdrive guards:[threshold, field]+ LT; GT/GE constants removed),AiPhaseRotationRecipe(final-phase guard:[FinalLimit, counter]+ LT),AiBibleCatalog(0x0A–0x0F table corrected with real semantics)..i64commented at the cases (0x8646E4/0x864759) — GOLDEN RULE. Doc:docs/reverse/FFX_ATEL_COMPARISON_OPCODE_SEMANTICS_2026-08-01.md(3 sources: interpreter = truth, noclip = direction, fahrenheit = naming). - Validation:
--phase-rotation-rt0319/319 PASS · AI + platform tests 64/64 PASS · baseline 254 (1 failure is a new SphereGrid-lane test in progress, out of scope). ### PATCH
v2.198.4.0
v2.198.4.2BETAREVISION
LuluAug 1, 2026
C3-1: magic DLL resource-key catalog VALIDATED - draft premise refuted (0/149 keys index the root table; real semantics = host global table, runtime-populated)
v2.198.4.1