Skip to content

EQ Client Settings overhaul — Phase 2+ (sub-forms on the engine) + v3.24.49 fix-forward#16

Merged
itsnateai merged 7 commits into
mainfrom
feat/eqclient-settings-phase2plus
Jun 7, 2026
Merged

EQ Client Settings overhaul — Phase 2+ (sub-forms on the engine) + v3.24.49 fix-forward#16
itsnateai merged 7 commits into
mainfrom
feat/eqclient-settings-phase2plus

Conversation

@itsnateai

@itsnateai itsnateai commented Jun 6, 2026

Copy link
Copy Markdown
Owner

Continuation of the EQ Client Settings overhaul. Spec: docs/specs/2026-06-06-eqclient-settings-overhaul.md. Phase 0+1 shipped as v3.24.48 on main; this branch carries the fix-forward from the Phase-1 verifier swarm plus Phases 2–10.

Safety / no limbo release: releases here are tag-gated — nothing ships until this PR is merged and a vX.Y.Z tag is pushed. main stays at the working v3.24.48 the whole time, so a half-finished branch can never become a bad release.

Done

  • STEP 0 — Phase-1 verifier swarm — 6 read-only agents (Sonnet+Opus × diff-clean / gap-audit / code-review) over 584039c..13c2f30. The two high-risk areas (EnforceOverrides narrowing → Operational-only; SaveSettings touch-gating) verified clean. Engine is section-correct, ANSI-preserving, InvariantCulture throughout. One shipped regression found.
  • v3.24.49 fix-forward — the v3.24.48 MaxFPS cap raise (99→999) had landed in only 2 of 6 sites; MaxFPS=100 (EQ stock) snapped back to 99 on reload / on opening Process Manager. Unified every cap site to one EqClientIniSchema.MaxFpsCap constant. + enforce-test regression lock (a stripped Bucket-2 numeric must survive relaunch) + AANoConfirm seed-polarity alignment. Build clean; all 4 --test-eqclient-* pass.

In progress / planned

  • Phase 2EQChatSpamForm onto the schema engine: register controls → schema keys, live-read display, touch-gated save (it currently writes all keys — the bug), drop its launch re-stamp.
  • Phases 3–6 — Models / Particles / VideoMode / Keymaps → engine; drop launch enforce (these already touch-gate).
  • Phase 7 — launch writer = Operational-only everywhere; retire vestigial ConfiguredKeys.
  • Phase 8 — one-time hard-push mechanism + curate Defaults to EQ-stock + deferred popup.
  • Phase 9 — hide experimental VideoMode geometry dims; WindowedModeX/YOffset canonical → [Defaults].
  • Phase 10 — verify all 6 windows at 100% + 150% DPI, remove EXPERIMENTAL, ship (tag).

Sub-forms not yet migrated stay fully functional throughout — each phase ends green before the next starts.

Summary by CodeRabbit

  • Bug Fixes

    • Resolved FPS cap setting persistence issue; performance frame rate settings now reliably persist across application relaunches and configuration saves.
    • Corrected initial configuration import interpretation for AANoConfirm setting alignment.
  • Refactor

    • Unified FPS limit constraint enforcement across all application interfaces to prevent validation inconsistencies between different components.
  • Chores

    • Version updated to v3.24.49.

v3.24.48 raised the MaxFPS/MaxBGFPS cap 99->999 in only 2 of 6 places (schema + EQ-Client NUD). AppConfig.Validate, SeedFromIni (x4), and the Process Manager NUD + FpsForDisplay still clamped at 99, so MaxFPS=100 (EQ's stock default) snapped back to 99 on next load / on opening the Process Manager. All cap sites now reference EqClientIniSchema.MaxFpsCap (one source, no Section-F drift).

Also: the enforce self-test now proves a Bucket-2 numeric (MaxFPS) left in the ini survives relaunch untouched (eqgame-wins regression lock); the now-vestigial AANoConfirm first-run import was aligned to the corrected schema polarity (inert today - no readers post-Phase-1 - but closes the drift bomb).

STEP 0 of the Phase-2 verifier swarm (6 agents Sonnet+Opus on diff 584039c..13c2f30) flagged this as the one shipped regression. Build clean; --test-eqclient-{schema,inidoc,save,enforce} all pass.
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@itsnateai, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 7 minutes and 4 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c77be297-3549-43e0-af70-616626bef93b

📥 Commits

Reviewing files that changed from the base of the PR and between 4b76a00 and 32cfb30.

📒 Files selected for processing (10)
  • CHANGELOG.md
  • Program.cs
  • UI/DiagRender.cs
  • UI/EQChatSpamForm.cs
  • UI/EQClientSettingsForm.cs
  • UI/EQKeymapsForm.cs
  • UI/EQModelsForm.cs
  • UI/EQParticlesForm.cs
  • UI/EqClientBindings.cs
  • docs/specs/2026-06-06-eqclient-settings-overhaul.md
📝 Walkthrough

Walkthrough

This PR unifies FPS cap handling by introducing a shared EqClientIniSchema.MaxFpsCap constant and applying it consistently across config parsing and UI forms. It also fixes the AANoConfirm INI polarity and hardened launch-enforcement testing to verify MaxFPS persistence.

Changes

FPS Cap Unification

Layer / File(s) Summary
Schema constant and row definitions
Config/EqClientIniSchema.cs
MaxFpsCap constant is added with documentation, and the MaxFPS/MaxBGFPS schema rows are updated to reference this constant instead of hardcoded 999 bounds.
Config validation and INI parsing alignment
Config/AppConfig.cs
Validate() and SeedFromIni() now clamp FPS values using MaxFpsCap in both [Defaults] and [Options] sections. The aanoconfirm key polarity is corrected so AANoConfirm is set when the INI value equals "1".
UI form controls for FPS limits
UI/EQClientSettingsForm.cs, UI/ProcessManagerForm.cs
Both settings and process manager forms replace hardcoded FPS numeric bounds with MaxFpsCap. The FpsForDisplay helper maps values into the 10..MaxFpsCap range.
Launch-enforce smoke test with MaxFPS preservation
UI/DiagRender.cs
The test fixture includes MaxFPS=123 in [Defaults] and verifies that EnforceOverrides does not re-stamp this value in [Options].
Version bump and release notes
EQSwitch.csproj, CHANGELOG.md
Project version is incremented to 3.24.49 with a changelog entry documenting the FPS cap unification, MaxFPS persistence fix, and AANoConfirm polarity alignment.

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title references the overhaul phase and version, but the actual changeset focuses primarily on the v3.24.49 FPS cap unification fix and regression test, not Phase 2+ sub-forms implementation work. Revise the title to accurately reflect the main deliverable: focus on the MaxFPS cap unification fix and regression test for v3.24.49, with a note that Phase 2+ work is planned but not included in this PR.
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/eqclient-settings-phase2plus

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
UI/DiagRender.cs (1)

587-590: 💤 Low value

Optional: verify the [Defaults] mirror is also untouched.

The schema defines MaxFPS with a [Defaults] mirror, and the fixture seeds only [Options] MaxFPS=123 without a corresponding [Defaults] entry. The current assertion verifies [Options] remains "123", proving EnforceOverrides didn't touch the canonical section.

For additional robustness, consider also asserting that [Defaults] MaxFPS remains absent (or seed both sections in the fixture and verify both are preserved). This would guard against a regression that writes only the mirror section.

Optional enhancement
 Eq("Options", "MaxFPS", "123");
+// Verify the [Defaults] mirror was not written by EnforceOverrides either:
+Eq("Defaults", "MaxFPS", null);  // or seed fixture with "[Defaults]\nMaxFPS=123" and assert "123"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@UI/DiagRender.cs` around lines 587 - 590, Add an additional assertion to
ensure the [Defaults] mirror for MaxFPS is not created/modified by
EnforceOverrides: check that there is no [Defaults] MaxFPS entry (or if you
prefer, seed both sections in the fixture and assert both remain unchanged).
Specifically, alongside the existing Eq("Options","MaxFPS","123") assertion, add
a check referencing the same fixture/schema that verifies the absence (or
preserved value) of the [Defaults] MaxFPS mirror to guard against regressions
that would write the mirror section; use the same test helpers that produced
Eq(...) so the check integrates with the current test flow and EnforceOverrides
verification.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CHANGELOG.md`:
- Line 9: Update the changelog entry so all CLI flags use their full long-form
names for clarity: replace the shorthand fragments '-inidoc', '-save',
'-enforce' with the long forms '--inidoc', '--save', '--enforce' to match the
existing '--test-eqclient-schema' usage in the same line; ensure the final line
reads something like "Verified: clean build; `--test-eqclient-schema` /
`--inidoc` / `--save` / `--enforce` all pass."

---

Nitpick comments:
In `@UI/DiagRender.cs`:
- Around line 587-590: Add an additional assertion to ensure the [Defaults]
mirror for MaxFPS is not created/modified by EnforceOverrides: check that there
is no [Defaults] MaxFPS entry (or if you prefer, seed both sections in the
fixture and assert both remain unchanged). Specifically, alongside the existing
Eq("Options","MaxFPS","123") assertion, add a check referencing the same
fixture/schema that verifies the absence (or preserved value) of the [Defaults]
MaxFPS mirror to guard against regressions that would write the mirror section;
use the same test helpers that produced Eq(...) so the check integrates with the
current test flow and EnforceOverrides verification.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a51ff9e9-760b-4877-bf6e-71988460dd35

📥 Commits

Reviewing files that changed from the base of the PR and between ebc8f96 and 4b76a00.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • Config/AppConfig.cs
  • Config/EqClientIniSchema.cs
  • EQSwitch.csproj
  • UI/DiagRender.cs
  • UI/EQClientSettingsForm.cs
  • UI/ProcessManagerForm.cs

Comment thread CHANGELOG.md Outdated

**Hardening** — the launch-enforce self-test now also proves a Bucket-2 numeric (`MaxFPS`) left in the INI survives a relaunch untouched (the "eqgame wins" guarantee), locking the Phase-1 win against regression; and the now-vestigial `AANoConfirm` first-run import was aligned to the corrected polarity.

Verified: clean build; `--test-eqclient-schema` / `-inidoc` / `-save` / `-enforce` all pass.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use full test flag names to avoid operator confusion.

Line 9 mixes one full flag with shorthand fragments (-inidoc, -save, -enforce), which can mislead copy/paste execution. Use the full flag forms consistently.

Proposed wording update
-Verified: clean build; `--test-eqclient-schema` / `-inidoc` / `-save` / `-enforce` all pass.
+Verified: clean build; `--test-eqclient-schema` / `--test-eqclient-inidoc` / `--test-eqclient-save` / `--test-eqclient-enforce` all pass.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Verified: clean build; `--test-eqclient-schema` / `-inidoc` / `-save` / `-enforce` all pass.
Verified: clean build; `--test-eqclient-schema` / `--test-eqclient-inidoc` / `--test-eqclient-save` / `--test-eqclient-enforce` all pass.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` at line 9, Update the changelog entry so all CLI flags use
their full long-form names for clarity: replace the shorthand fragments
'-inidoc', '-save', '-enforce' with the long forms '--inidoc', '--save',
'--enforce' to match the existing '--test-eqclient-schema' usage in the same
line; ensure the final line reads something like "Verified: clean build;
`--test-eqclient-schema` / `--inidoc` / `--save` / `--enforce` all pass."

itsnateai added 2 commits June 6, 2026 17:39
Extract the Phase-1 binding loop into a shared engine (UI/EqClientBindings: LoadInto / SaveChanged) and migrate the main form + ChatSpam onto it, so the six EQ Client Settings forms can't drift in how they read / snapshot / touch-gate (spec S3 - one engine, not N hand-synced parsers).

EQChatSpamForm was the write-all offender: every Save stamped all 22 filters and EnforceOverrides re-stamped them at launch. Now:
- display = live read of eqclient.ini via the schema (was a config-dict seed),
- Save = touch-gated (only changed filters written to [Options]),
- dropped its launch re-stamp from EQClientSettingsForm.EnforceOverrides (eqgame wins after first set),
- 4 (Key,Label,Default) arrays collapse to grouped key-lists; label/default/polarity now live once in EqClientIniSchema.

Main form refactored onto the shared engine with no behaviour change (--test-eqclient-save still green).

Verify: clean build; --test-eqclient-{schema,inidoc,save,enforce,chatspam-save} all pass; --diag-render-form EQChatSpamForm renders without crash. New --test-eqclient-chatspam-save proves the touch-gate (absent/untouched keys NOT inserted = no write-all; unmanaged preserved; no ghost).
@itsnateai

Copy link
Copy Markdown
Owner Author

Progress checkpoint (2026-06-06):

  • ✅ STEP 0 — Phase-1 verifier swarm clean on the two high-risk areas (EnforceOverrides narrowing, SaveSettings touch-gating).
  • ✅ v3.24.49 fix-forward — MaxFPS cap unified to one EqClientIniSchema.MaxFpsCap (was raised in only 2 of 6 sites in v3.24.48). 4b76a00
  • ✅ Phase 2 — ChatSpam on the shared engine; main form refactored onto it too; touch-gated, no launch re-stamp; --test-eqclient-chatspam-save added. 0319005

Build clean; all 5 --test-eqclient-* pass; --diag-render-form EQChatSpamForm renders. Remaining: Phases 3-10 (now cheap — engine exists) + a pre-merge verifier pass on the full PR diff before tag-to-ship.

itsnateai added 4 commits June 6, 2026 17:58
EQModelsForm migrated onto the shared EqClientBindings engine: live-read display, touch-gated save (only changed models), launch re-stamp dropped from EnforceOverrides (eqgame wins after first set). 32 (Key,Label) entries collapse to grouped key-lists; quick All-Luclin/All-Classic buttons now filter _bindings via RaceKeySet instead of a parallel checkbox dict. ModelOverrides config dict + _initialValues snapshot retired (engine's per-binding snapshot replaces them).

Verify: clean build; all 5 --test-eqclient-* pass (no regression); --diag-render-form EQModelsForm renders (validates all 32 keys resolve in the schema).
EQKeymapsForm migrated onto the shared EqClientBindings engine via the numeric path (EQ scan codes are decimals:0 numerics; modifier flags in the high bits are opaque to the engine). The live-decoded key-name label stays as cosmetic UI driven by ValueChanged + an explicit post-load sync. Keymaps already had no launch re-stamp (was eqgame-wins), so this is a pure consistency wire-up - no behaviour change. _nudValues/_initialValues dicts retired.

Verify: clean build; all 5 --test-eqclient-* pass; Keymaps/Models/ChatSpam all render via --diag-render-form.
Extended EqClientBindings with a third control type: TrackBar sliders (Slider + SliderScale; INI float = Slider.Value / scale). EQParticlesForm migrated onto the engine - opacity/density sliders (scale 100 over the schema 0..1 floats), clip/filter/FogScale/LODBias numerics, SameResolution checkbox - all live-read + touch-gated; launch re-stamp dropped from EnforceOverrides (only VideoMode's dict remains, Phase 5). Slider keeps its coarse-but-safe round-trip: a finer on-disk float snapshots to the slider's resolution and is left untouched on save unless dragged. ParticleOverrides config dict now inert.

New --test-eqclient-particles-save proves the slider->float write (drag -> 0.750000), an untouched numeric preserved exactly, an absent managed key NOT inserted (touch-gated), unmanaged preserved, no ghost.

Verify: clean build; all 6 --test-eqclient-* pass; --diag-render-form EQParticlesForm renders.
@itsnateai itsnateai merged commit 32cfb30 into main Jun 7, 2026
1 check passed
@itsnateai itsnateai deleted the feat/eqclient-settings-phase2plus branch June 7, 2026 00:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant