Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/review/device-qa/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,5 +336,15 @@ Each note records one fact about bytes or draw calls already on main. None of th
| [anchor-offset-2026-11-05.md](anchor-offset-2026-11-05.md) | The camera offset |
| [view-contains-2026-11-05.md](view-contains-2026-11-05.md) | The view contains a point |
| [utf8-order-2026-11-05.md](utf8-order-2026-11-05.md) | The byte order |
| [hint-latch-2026-11-05.md](hint-latch-2026-11-05.md) | The hint, shown once |
| [offscreen-sector-2026-11-05.md](offscreen-sector-2026-11-05.md) | The offscreen sector |
| [clip-select-2026-11-05.md](clip-select-2026-11-05.md) | The selected frames |
| [upgrade-accept-2026-11-05.md](upgrade-accept-2026-11-05.md) | The one upgrade accept |
| [touch-route-2026-11-05.md](touch-route-2026-11-05.md) | The touch route |
| [court-rehearse-2026-11-05.md](court-rehearse-2026-11-05.md) | The rehearsal card |
| [intro-frame-2026-11-05.md](intro-frame-2026-11-05.md) | The intro frame |
| [concealment-flag-2026-11-05.md](concealment-flag-2026-11-05.md) | The concealment flag |
| [body-clearance-2026-11-05.md](body-clearance-2026-11-05.md) | The body clearance |
| [ghost-verify-2026-11-05.md](ghost-verify-2026-11-05.md) | The ghost's second check |

Next session: follow [retest-checklist.md](retest-checklist.md) (D-105 allows device checks on any build).
9 changes: 9 additions & 0 deletions docs/review/device-qa/body-clearance-2026-11-05.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# The body clearance

Read 2026-11-05 from `CornerPursuit.bodyClear` on `ef68565`. No corner was moved.

The live call stays in [corner-pursuit-2026-11-04.md](corner-pursuit-2026-11-04.md). That call leaves body clearance off, so its reached distance stays 8.

When clearance is requested, a corner within 2 units is skipped, and the corner must also pass `bodyClear`. The ends are truncated to units. A segment that meets the box has distance 0. Otherwise the squared distance is the minimum of each end's squared distance to the box and each of the four corners' squared distance to the segment. An end outside the box uses the outside deltas. A point whose projection falls at or before the start uses the start, and one at or past the end uses the end. Between them the square is `(cross² + len² − 1) / len²`. The path is clear when every solid's squared distance is at least the radius squared.

This does not turn clearance on.
15 changes: 15 additions & 0 deletions docs/review/device-qa/clip-select-2026-11-05.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# The selected frames

Read 2026-11-05 from `ClipTiming.selecting` on `ef68565`. No frame was dropped.

The 60 Hz walk, the round-up, and the last frame's hold stay in [clip-frame-clock-2026-11-04.md](clip-frame-clock-2026-11-04.md). The delivered paths stay in [frame-backing-2026-11-05.md](frame-backing-2026-11-05.md).

`selecting` throws `Failure.index` unless the index list is non-empty, every index is inside `frameUnits`, and each index is strictly greater than the one before it. The result is a new timing at the same `unitsPerSecond`, with `frameUnits` taken from those indices.

`init` throws `Failure.invalid` when the rate is not positive, the unit list is empty, or a unit is not positive. It throws `Failure.overflow` when the running sum overflows.

`frameIndex` compares full-width products. The elapsed product is the offset times `unitsPerSecond`. Each frame's end is the cumulative units times 60. The index is the first frame whose end is strictly above that elapsed product: a lower high word, or equal high words and a lower low word. The boundary belongs to the following frame.

`ClipFrameLibrary.timing` calls `selecting` when the clip has authored timing, a direction was asked, and the direction list is non-empty and contains that direction. The indices are the frame ids that contain `_<direction>_`. An asked direction missing from a non-empty list returns nil. Authored timing with no asked direction, or an empty direction list, returns that timing. With no authored timing, a clip that has `framesPerSecond` builds `uniform` from that direction's frame count and that rate. No rate returns nil.

This does not change a rate.
9 changes: 9 additions & 0 deletions docs/review/device-qa/concealment-flag-2026-11-05.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# The concealment flag

Read 2026-11-05 from `PresentationSnapshot` on `ef68565`. No window was changed.

The mark stays in [combat-feedback-marks-2026-11-04.md](combat-feedback-marks-2026-11-04.md). The until-tick write stays in [player-movement-2026-11-04.md](player-movement-2026-11-04.md).

`ghostConcealmentActive` is set when Ghost Step is selected, the tick is above 0, the tick is at or before `cameraInvisibleUntilTick`, and the outcome is not terminal.

This does not change the dodge.
13 changes: 13 additions & 0 deletions docs/review/device-qa/court-rehearse-2026-11-05.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# The rehearsal card

Read 2026-11-05 from `GameScene.rehearseCourt` on `ef68565`. No court was added.

The snapshot stays in [court-capture-2026-11-05.md](court-capture-2026-11-05.md). The receipt guard stays in [receipt-archive-2026-11-04.md](receipt-archive-2026-11-04.md). The ghost store stays in [ghost-file-2026-11-04.md](ghost-file-2026-11-04.md). The clock stays in [run-card-2026-11-04.md](run-card-2026-11-04.md). The titles stay in [terminal-surface-2026-11-04.md](terminal-surface-2026-11-04.md).

`beginRehearsal` returns false when there is no court snapshot. `rehearseCourt` then returns false. Otherwise it calls `resetForNewSimulation`, sets the ghost to nil, increments `ghostGeneration`, sets `terminalEvidenceStored` true, and redraws.

`resetForNewSimulation` clears the spoken HUD, the run card, the rehearsal offer, the sound engine, the renderer, combat feedback, camera follow, the last display time, the lockdown tint, the court, the effects, the near-miss edges, the intro, and the instrumentation. It also resets the touch controller, so a held stick does not enter the new run.

`finishRunIfNeeded` offers rehearsal when the outcome is failure, the court was reached, and a court snapshot exists. A rehearsal card is one row, label `REHEARSAL`, value the clock of the tick minus `courtStartTick`, or of the tick when that start is nil. The card's outcome is nil, and it is marked a rehearsal. The function returns before the ghost store and the medal store. The accessibility surface omits the share rect on that card.

This does not store a rehearsal.
11 changes: 11 additions & 0 deletions docs/review/device-qa/ghost-verify-2026-11-05.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# The ghost's second check

Read 2026-11-05 from `GhostRun` on `ef68565`. No record was rewritten.

The build, the fade, and the lead stay in [ghost-replay-2026-11-04.md](ghost-replay-2026-11-04.md). The envelope's upgrade index stays in [replay-commands-2026-11-04.md](replay-commands-2026-11-04.md).

`commandsAreOrdered` returns false when a command carries an upgrade index and `UpgradeID.from` returns nil.

`replay` returns nil when a step leaves the tick unchanged. After a replay whose tick and digest match the record, the ghost that is kept is a new `Simulation.make` of that seed. `advance` steps while the tick is below the minimum of the live tick plus the lead and the recorded length, and it stops when that simulation is already terminal.

This does not change a ghost.
13 changes: 13 additions & 0 deletions docs/review/device-qa/hint-latch-2026-11-05.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# The hint latch

Read 2026-11-05 from `AwarenessHintProjector` on `ef68565`. No hint was added.

The copy stays in [tutorial-line-offer-2026-11-04.md](tutorial-line-offer-2026-11-04.md). The row that is drawn stays in [takedown-streak-2026-11-04.md](takedown-streak-2026-11-04.md) and [streak-type-2026-11-05.md](streak-type-2026-11-05.md). The card's 300-tick cap stays in [tutorial-timing-2026-11-04.md](tutorial-timing-2026-11-04.md). The heat row stays in [heat-caption-2026-11-04.md](heat-caption-2026-11-04.md). The quiet caption at this y stays in [quiet-approach-tag-2026-11-04.md](quiet-approach-tag-2026-11-04.md).

`project` stores `shownAt` on the first tick the query is visible. It then returns the copy while `tick` is at or after `shownAt` and fewer than `visibleTicks` have passed. `visibleTicks` is 300. `reset` replaces the projector. `project` does not read `tutorialsEnabled`.

`referenceRect` is `HUDRect(x: 422 - 180, y: 108, width: 360, height: 24)`.

The snapshot query keeps an enemy whose `unaware` flag is set and whose absolute deltas from the camera centre are at most half the visible width and half the visible height. The state query keeps a living `isUnaware` enemy whose truncated position `PresentationCamera.contains` reports inside a follow camera of the truncated player. That contains test stays in [view-contains-2026-11-05.md](view-contains-2026-11-05.md). The visible size stays in [camera-follow-2026-11-03.md](camera-follow-2026-11-03.md).

This does not draw the hint.
11 changes: 11 additions & 0 deletions docs/review/device-qa/intro-frame-2026-11-05.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# The intro frame

Read 2026-11-05 from `GameScene.introFrame` on `ef68565`. No frame was added.

The durations, the skip, and the rule that the simulation does not step while the intro runs stay in [intro-sequence-2026-11-04.md](intro-sequence-2026-11-04.md).

No intro returns `mayStep` true and an empty chirp list. A finished intro is set to nil and returns the same. A hold at or past the current frame returns `mayStep` false, an empty chirp list, and `held` true. Otherwise the frame advances, the intro is stored, and `mayStep` stays false, with the chirps from that advance.

The production call passes no hold. `startIntro` builds the sequence from the camera entity ids and `settings.vfx.reducedMotion`.

This does not add a frame.
11 changes: 11 additions & 0 deletions docs/review/device-qa/offscreen-sector-2026-11-05.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# The offscreen sector

Read 2026-11-05 from `AudioProjector.sector` on `ef68565`. No speaker was moved.

The four-letter heading stays in [facing-direction-2026-11-04.md](facing-direction-2026-11-04.md). `atan2Milli` stays in [millidegree-2026-11-04.md](millidegree-2026-11-04.md). The shipped view stays in [camera-follow-2026-11-03.md](camera-follow-2026-11-03.md). The voice cap stays in [effect-voice-ceiling-2026-11-03.md](effect-voice-ceiling-2026-11-03.md).

A missing source returns nil. The deltas are `unitsTruncated`. A source whose absolute x delta is at most half `baselineWorldWidth`, and whose absolute y delta is at most half `baselineWorldHeight`, returns nil. Past either half, the sector is `MilliDeg.normalize` of `Cordic.atan2Milli(y:dy, x:dx)`, divided by 45,000. `normalize` stays inside 0 through 359,999, so the quotient is 0 through 7.

After the cues are appended, each candidate stores the next sequence number, starting from 0, and the counter advances. A cue whose `sourceEntityId` is set then stores this sector.

This does not add a speaker.
15 changes: 15 additions & 0 deletions docs/review/device-qa/touch-route-2026-11-05.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# The touch route

Read 2026-11-05 from `GameScene.beginTouch` on `ef68565`. No control was added.

The intro skip stays in [intro-sequence-2026-11-04.md](intro-sequence-2026-11-04.md). Pause stays in [pause-2026-11-04.md](pause-2026-11-04.md). Share stays in [share-sheet-2026-11-04.md](share-sheet-2026-11-04.md).

A missing projector returns false, and the rest of the batch continues. A skip that is still running returns true and consumes the rest of the batch.

A terminal outcome returns true. A restart hit calls `restartRun`. A rehearse hit calls `rehearseCourt`. A share hit calls `presentShare`. A terminal tap that misses those controls is still consumed.

An upgrade that is pending, or a paused run, returns true and does not call the controller. Otherwise a stick or dodge touch is handed to the controller. A pause result calls `onPauseRequested`. That path returns false, so a later touch in the same batch still runs.

`moveTouch` returns immediately while an upgrade is pending or the run is paused. `endTouch` ends that token.

This does not add a control.
11 changes: 11 additions & 0 deletions docs/review/device-qa/upgrade-accept-2026-11-05.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# The one upgrade accept

Read 2026-11-05 from `GameScene.chooseUpgrade` on `ef68565`. No upgrade was added.

The sheet's submit stays in [upgrade-choice-layout-2026-11-04.md](upgrade-choice-layout-2026-11-04.md).

`chooseUpgrade` returns true once. The upgrade must be pending, `session.pendingUpgradeChoice` must be nil, and `upgradeSelection.submit` must accept the index. It then resets the touch controller, stores move x 0, move y 0, and dodge clear, and stores the index on the session. A later call returns false.

While a redraw sees the upgrade pending and the sheet is not yet presented, the same input clear runs before the sheet synchronizes.

This does not add an upgrade.
Loading