Skip to content

Integrate post-1.0 hardening and opt-in high-rate presentation - #1

Open
akratch wants to merge 1 commit into
mainfrom
post-1.0-integration
Open

Integrate post-1.0 hardening and opt-in high-rate presentation#1
akratch wants to merge 1 commit into
mainfrom
post-1.0-integration

Conversation

@akratch

@akratch akratch commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Summary

  • Preserve the authored simulation cadence and original presentation policy as the defaults.
  • Add explicitly selectable display, numeric, and uncapped presentation rates with interpolation, bounded GPU queues, and lifecycle coverage.
  • Integrate real-ROM oracle replay diagnostics, fail-closed magic-code validation, macOS signing/notarization repairs, and native audio qualification.
  • Put the native/source and generated web repositories one click from each other in both READMEs.

The integration commit is parented directly to public main and contains only the reviewed public tree. No ROM or ROM-derived game assets are included.

Validation

  • Release CTest: 42/42 passed.
  • Public-surface policy: passed for the exact tree and new commit range.
  • Clean-room and full-history ROM guard: passed.
  • Release-readiness guard and shipped web artifact scan: passed.
  • Self-contained macOS app/DMG: launcher smoke passed; default/original and opt-in 240 Hz packaged runs passed; mounted app integrity and asset-free scan passed.

Release publication remains a separate manual decision.

Keep the authored simulation cadence and original presentation policy as defaults while adding explicitly selectable display, numeric, and uncapped presentation modes.\n\nAlso integrate presentation interpolation and lifecycle coverage, real-ROM oracle replay diagnostics, fail-closed magic-code validation, macOS signing/notarization repairs, native audio queue qualification, and clearer native/web repository navigation.\n\nNo ROM or ROM-derived game assets are included.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4d7d3bb6ac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +190 to +192
gh release view "$RELEASE_TAG" >/dev/null
gh release upload "$RELEASE_TAG" \
"$DMG_PATH" "${DMG_PATH}.sha256" "${DMG_PATH}.provenance.json"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Bind the uploaded release to the checked-out commit

When this workflow is dispatched from a ref other than the commit referenced by RELEASE_TAG, the provenance check only proves that the artifact was built from github.sha; it never verifies that the release tag points to that SHA. The gh release upload manual specifies gh release upload <tag> <files>..., so the subsequent command will attach the differently sourced, signed artifact to whatever existing tag the operator entered. Resolve and dereference the tag and require it to equal SOURCE_COMMIT before uploading, otherwise a release can distribute a binary built from the wrong commit.

Useful? React with 👍 / 👎.

akratch added a commit that referenced this pull request Sep 2, 2026
…d-off card

MINOR-4 (functional): the room-ready takeover latch was one-shot per adapter,
so a SECOND tournament in one session fell back to the per-race ImGui path
instead of the native takeover. Re-arm it edge-triggered + reason-aware:
- runOnlineLobbyStartLiveSession captures the session end reason and arms the
  re-arm ONLY on a FINISHED return (never LEFT/ERROR/NONE -- those can land with
  the room-ready condition still TRUE, so an instant re-arm would re-boot the
  session the player just left).
- OnlineRoom_observeRoomReadyRearm (called every drawBetaRoom frame) completes
  the re-arm: it clears the latch ONLY while the room-ready condition is FALSE
  (parked in RESULTS after FINISHED), so the next SELECTING+2+LOBBY+tournament
  arrival is a genuine false->true rising edge the poll re-fires on exactly once.
Cannot re-boot-loop: reason-gating blocks LEFT/ERROR; condition-false gating
blocks any instant re-fire. resetRoomReadyLatch clears the pending re-arm too,
so the room-ready probe's exactly-1-fire contract is unchanged.

Hand-off card (polish): for a TOURNAMENT room in the takeover window
(SELECTING+2+LOBBY+tournament) the now-dead tournament-scoped ImGui widgets --
the cup chips + series line in the session card, the tournament ready-gating
region, and the mid-cup Next-Race branch in RESULTS -- are replaced with a
concise "Starting tournament -- handing to the game..." card. Single-race
widgets (character grid, vehicle row, single-race track/ready/start), the MODE
chip (tournament entry), the room-ready trigger poll, and the post-FINISHED
RESULTS landing + New Tournament entry all survive untouched.

Test: new headless lane check_online_room_ready_rearm.py drives the re-arm
state machine via the MDKR_APP_TEST_ONLINE_ROOM_READY_REARM_PROBE seam and
proves tournament #1 fires once, a LEFT/ERROR return does not re-arm (no loop),
a FINISHED return does not instantly re-fire, and the fresh rising edge re-takes
native once for tournament #2. All online lanes green; ctest 220/221 (only
pre-existing network_viewport_invariance); OFF anchors byte-identical.
akratch added a commit that referenced this pull request Sep 2, 2026
…INISHED

Add the native, decomp-authentic 2D champion celebration shown after the final
tournament standings and before the session hands back to the launcher. The
MDKR_ONLINE_SESSION_CEREMONY phase was a dead enum swallowed by default:; make it
real as a beta-only, ZERO-offline-impact screen.

- New online_ceremony.{c,h}: mirrors the online_results.c screen contract
  (enter/tick/exit, borrowed portrait+font asset group, exit-frees-assets
  symmetry, same include set, throttled stderr witness, headless test seams).
  Renders a big gold CHAMPION headline, the winner's portrait + name ([YOU] if
  local) + point total, the runners-up rows, and a pulsed "RETURNING TO ROOM..."
  footer, using the SAME 2D primitives (draw_text/texrect_draw/bgdraw_fillcolour)
  and the shared navy backdrop every online screen uses. Crowd-cheer SFX on enter.
  It never enters the offline trophy-ceremony cinematic (which re-enters
  GAMEMODE_MENU).

- Advance gate: a bounded TIMED auto-advance (~6s) that fires for EVERY endpoint
  on the local clock -- no cross-endpoint/snapshot convergence gate -- so it is
  impossible to hang the session on. A host may skip early; a joiner never blocks
  anyone; a remote vacate ends it promptly. No second required "press A" (the
  RESULTS terminal already took the one FINISH confirm).

- Wiring (online_session.c): the final-standings RESULTS LEAVE now detours into
  the CEREMONY phase; the EXACT PD-T6d FINISHED note + platform_request_exit(0)
  moved intact into the new CEREMONY case, so FINISHED still fires EXACTLY ONCE,
  with the same reason/result the launcher reads, once the ceremony ends. The
  non-final LEFT path is unchanged.

- DRY winner identity: lift the RESULTS selection-sort into online_standings.h
  (mdkr_online_standings_compute), called by both online_results.c and the
  ceremony, so the champion (order[0]) is byte-for-byte the seat STANDINGS crowns
  #1. online_results.c output behavior is unchanged.

- Tests: new check_online_ceremony.py proves the ceremony enter/render sit
  strictly between the final standings and the single FINISHED (skip), auto-
  advances with no input (auto -- impossible-to-hang), and ends promptly on a
  remote vacate (vacate); champion cross-checked against the standings #1. The
  existing hold-ending lanes (lobby_tournament / session_end incl joiner /
  resident_live / lobby_single_endpoint) set MDKR_TEST_ONLINE_CEREMONY_SKIP so
  their frame budgets + FINISHED assertions are preserved with the ceremony in
  the path.

Beta-only: online_ceremony.c is added to GAME_SOURCES only under the
MDKR_ENABLE_ONLINE_BETA gate; thread3_main.c / menu.c / online_race_results.c
untouched (OFF-build objects byte-identical). All online lanes green; ctest
220/221 (only pre-existing network_viewport_invariance).
akratch added a commit that referenced this pull request Sep 2, 2026
…naments

The existing re-arm probe proves ONE FINISHED cycle (#1 -> #2) plus a fresh-
adapter reset coda; it cannot show the arm -> clear -> rising-edge cycle is
repeatable on the SAME adapter, so a latent one-shot bug would pass #1 -> #2 yet
silently drop the 3rd tournament (called out unexercised in the human plan).

Add a beta/test-only MDKR_APP_TEST_ONLINE_ROOM_READY_REARM3_PROBE branch
(main_app.cpp, inside the existing beta gate) that drives THREE consecutive
tournaments through the wiring's real re-arm edges, plus a LEFT return wedged
between #1 and #2 that must not re-arm. New lane check_online_rearm_third.py
asserts totalFires=3, one takeover per tournament, no mid-run re-boot loop, and
that "re-arm armed"/"re-arm complete" each log exactly twice in order (one re-arm
per FINISHED return, not a one-shot). No offline TU touched; anchors unaffected.
akratch added a commit that referenced this pull request Sep 2, 2026
…tate-hash convergence bar

Two intertwined pieces on the resident descriptor-less coordinator:

- FINAL-REPLAY (ruled): when the host picks a replay option at the tournament
  final (NEW TOURNAMENT / CHANGE CUP / CHANGE MODE / RACE AGAIN / CHANGE
  CHARACTER), the REMATCH wrap resets race_index 3 -> 0 -- which the
  coordinator's tournament re-cycle trigger (race_index ADVANCED) by
  definition never sees. The continuing host's coordinator parked in Results
  forever: roster/match-input never re-cycled, the next race never booted, and
  the per-round re-wait watchdog was the only exit. A new race_index-DECREASED
  arm now takes the OBSERVE-ONLY re-cycle (the single-race replay machinery):
  the engine's own re-selection screen owns the re-drive, the launcher clears
  the stale roster/match-input and re-arms on the engine-driven fresh epoch --
  auto-driving the mid-cup advance would race the host's re-selection to START
  on the old config. New lane check_online_final_replay.py (registered,
  documented) proves the ruled two-road re-convergence on the loopback
  2-endpoint rig: NEW TOURNAMENT at final #1 -> wrap -> observe-only re-cycle
  -> the second endpoint re-readies through the reducer -> race 5 boots on the
  fresh epoch as the fresh series' round 1 -> the full second cup races ->
  FINISH #2 ends cleanly. RED at the pre-fix coordinator: one cup raced, not
  two (race 5 never booted).
- STATE-HASH witness: the resident descriptor-less path now emits, once per
  epoch, the same FNV confirmed-input fold the per-race path logs
  ([online-resident-live] race fold ...), over a FIXED firstTick-anchored
  window so two endpoints' folds are directly comparable (an endpoint-local
  frontier anchor would never be). Log-only, launcher-side, session-gated;
  loopback rigs also fold the peer for in-process corroboration. The cloud
  capstone's (d)/(e) now require BOTH witnesses cross-process -- the
  reducer-agreed finish order AND identical span+hash folds -- restoring the
  convergence bar the resident path lost when it stopped emitting
  ENGINE-ONLINE-LIVE fold lines. Verified over the real cloud: both races,
  identical folds on both processes, full run green.
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