docs(02-06): complete uat-gap-closure plan
5 tasks executed sequentially; all 4 first-impression UX gaps from 2026-05-09 live UAT structurally closed (G1 BLOCKING white halo, G2 BLOCKING no first-run prompt, G3 HIGH dim tile grid, G4 MEDIUM floating gate). 21 new Vitest cases (312 → 333 green); 3 new Playwright assertions (16 → 19); npm run ci + npm run test:e2e both exit 0. Phase 3 watercolor deferral preserved (no painted assets, no new dependencies); V1Payload unchanged (firstRunHintDismissed is session-state only, no migrations[2]). Hint copy chosen: "Begin where the soil is bare." (plan's #1 ranked candidate; bible voice — warm, specific, contemplative). Externalized in content/seasons/01-soil/ui-strings.yaml; UiStringsSchema extended with first_run_hint: z.string().min(1) so Zod strip mode does not silently drop the YAML key from parsed.data. Verifier handoff unblocked: 02-VERIFICATION.md frontmatter `gaps:` block ready to flip status from gaps_found → verified. The 6 HUMAN-UAT.md tone items remain pending (out of scope; addressed by separate workflow). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
---
|
||||
phase: 02-season-1-vertical-slice-soil
|
||||
plan: 06
|
||||
subsystem: uat-gap-closure
|
||||
tags: [gap-closure, uat, css, first-run-hint, tile-contrast, gate-context, mvp, wave-0]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 02-01
|
||||
provides: Zustand store + V1Payload + session slice (extended in this plan with firstRunHintDismissed)
|
||||
- phase: 02-02
|
||||
provides: BeginScreen (analog component for FirstRunHint shape) + tile-renderer (G3 modifies its constants) + ui-strings.yaml shape
|
||||
- phase: 02-03
|
||||
provides: JournalIcon (analog corner-affordance pattern) + Journal modal
|
||||
- phase: 02-04
|
||||
provides: gate-renderer (G4 adds wall band primitive) + Lura gate location at canvas (880, 384)
|
||||
- phase: 02-05
|
||||
provides: tests/e2e/season1-loop.spec.ts (Playwright PIPE-07 full-loop smoke — Task 5 threads 3 new gap-closure assertions into it) + App.tsx render tree (FirstRunHint mounts alongside Letter / Settings / etc.)
|
||||
provides:
|
||||
- src/index.css — global page styles (body bg #1a1a1a, color #e8e0d0, zero margin, 100vh, serif, #game-container flex centering). Imported once from src/main.tsx so Vite bundles it into the entry chunk; body styles apply before React mounts.
|
||||
- src/ui/first-run/FirstRunHint.tsx — single-line bible-voice hint surfaced after BeginScreen dismisses, auto-dismisses on first plant !== null transition. Reads externalized line from uiStrings[1]?.first_run_hint per STRY-09.
|
||||
- src/store/session-slice.ts extended — firstRunHintDismissed: boolean + dismissFirstRunHint() action. Session state ONLY; NEVER added to V1Payload (no migrations[2]).
|
||||
- src/content/schemas/ui-strings.ts extended — UiStringsSchema gains first_run_hint: z.string().min(1) so Zod's default strip mode does NOT silently drop the YAML key from parsed.data at runtime.
|
||||
- content/seasons/01-soil/ui-strings.yaml — first_run_hint key added with bible-voice copy "Begin where the soil is bare." (the plan's #1 ranked candidate; rationale documented in §Decisions Made).
|
||||
- src/render/garden/tile-renderer.ts — OUTLINE_COLOR brightened 0x4d4d52 → 0x5a5a60 + OUTLINE_HOVER 0x6e6e75 → 0x7a7a82 + HOVER_FILL_ALPHA=0.06 fill bump on the hit rectangle. Constants exported for testability.
|
||||
- src/render/garden/gate-renderer.ts — adds 4th Phaser primitive (wall band) at GATE_X column spanning the full 768px canvas height with alpha=0.18 (mid of 0.15-0.20 fix_shape range). GateGameObjects interface gains a wall field — additive, Garden.ts unchanged.
|
||||
- tests/e2e/season1-loop.spec.ts — extended with 3 new assertions covering G1 + G2 end-to-end (body bg = rgb(26, 26, 26), FirstRunHint visible after Begin dismiss, FirstRunHint gone after first plant).
|
||||
- 21 new Vitest cases across 4 test files (G1: 6 file-read smoke, G2: 6 behavioral, G3: 5 phaser-mocked, G4: 4 phaser-mocked).
|
||||
- 4 first-impression UX gaps from 2026-05-09 live UAT structurally closed (G1 BLOCKING, G2 BLOCKING, G3 HIGH, G4 MEDIUM).
|
||||
affects: [/gsd-verify-work (re-verifier consumes this SUMMARY to flip 02-VERIFICATION.md status from gaps_found → verified), Phase 3 (Watercolor & Cello — paints over the structural primitives without changing the layout intent)]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Single CSS file imported from main.tsx as the global-style anchor: Vite bundles plain CSS imports natively, no build-config change needed. body bg + color + font-family all match the BeginScreen overlay so there is no tonal break at any frame."
|
||||
- "Session-state-only first-run gate: firstRunHintDismissed lives in src/store/session-slice.ts (NOT V1Payload). The hint reappears on hard reload until the first plantSeed commits — that is the correct A-Dark-Room first-run UX (re-prompt on a fresh tab, dismiss on first action)."
|
||||
- "Schema extension MANDATORY when adding YAML keys: Zod's default z.object() strip mode silently drops unknown keys from parsed.data. Without extending UiStringsSchema, the runtime would have rendered first_run_hint as undefined and FirstRunHint would have rendered null — production-only failure that unit tests mocking the store directly would not catch."
|
||||
- "Phaser-mock pattern for renderer unit tests: vi.mock('phaser', ...) short-circuits the Phaser bundle import so the renderer module loads under happy-dom (Phaser 4's checkInverseAlpha boot probe crashes on canvas.getContext returning null). Combined with a mocked Phaser.Scene surface (add.graphics + add.rectangle returning vi.fn() spies), the test pins constants and call args without needing a real Chromium canvas. Reusable for plant-renderer and ready-pulse coverage in future phases."
|
||||
- "Tile hover as steady-state outline + fill swap (NOT animation): pointerover swaps OUTLINE_COLOR → OUTLINE_HOVER and bumps the hit rectangle's fill alpha from 0 → 0.06; pointerout reverses. No tweens, no setInterval. Reduced-motion-safe by construction; Phase 8's global motion-preference owner has no work to do here."
|
||||
- "Gate wall band as structural primitive (Phase 3 deferral preserved): a single Phaser Rectangle at GATE_X with alpha=0.18 spans the canvas height to give the gate visual context (the bible's 'walled garden' framing). Phase 3 paints the watercolor wall over this primitive without changing the geometry or interaction surface."
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- src/index.css (G1 — global page styles, ~25 lines)
|
||||
- src/index.css.test.ts (G1 — 6 file-read smoke cases pinning the load-bearing CSS rules)
|
||||
- src/ui/first-run/FirstRunHint.tsx (G2 — single-line hint component, externalized copy, auto-dismiss subscription)
|
||||
- src/ui/first-run/FirstRunHint.test.tsx (G2 — 6 behavioral cases: hidden when Begin still up, hidden when dismissed, renders externalized line, reads uiStrings, auto-dismisses on first plant, stays dismissed)
|
||||
- src/ui/first-run/index.ts (G2 — barrel)
|
||||
- src/render/garden/tile-renderer.test.ts (G3 — 5 cases via Phaser-Scene-mock pattern: constants pinned, 16 tile groups, initial draw uses OUTLINE_COLOR, pointerover swaps to OUTLINE_HOVER + fill bump)
|
||||
- src/render/garden/gate-renderer.test.ts (G4 — 4 cases via Phaser-Scene-mock pattern: constants in fix_shape range, wall is first rectangle with full canvas height, 4 total rectangles, GateGameObjects exposes wall handle)
|
||||
- .planning/phases/02-season-1-vertical-slice-soil/02-06-uat-gap-closure-SUMMARY.md (this file)
|
||||
modified:
|
||||
- src/main.tsx (G1 — single import './index.css'; line added)
|
||||
- src/store/session-slice.ts (G2 — firstRunHintDismissed + dismissFirstRunHint added; session state only, NOT in V1Payload)
|
||||
- src/content/schemas/ui-strings.ts (G2 — UiStringsSchema gains first_run_hint: z.string().min(1) so Zod strip mode does not drop the YAML key)
|
||||
- content/seasons/01-soil/ui-strings.yaml (G2 — first_run_hint key with bible-voice copy)
|
||||
- src/ui/index.ts (G2 — re-exports ./first-run)
|
||||
- src/App.tsx (G2 — <FirstRunHint /> mounted between BeginScreen and SeedPicker)
|
||||
- src/render/garden/tile-renderer.ts (G3 — OUTLINE_COLOR + OUTLINE_HOVER brightened, HOVER_FILL_ALPHA=0.06 added; constants exported)
|
||||
- src/render/garden/gate-renderer.ts (G4 — wall band primitive added; WALL_BAND_X / WALL_BAND_WIDTH / WALL_BAND_HEIGHT / WALL_BAND_ALPHA / WALL_BAND_COLOR exported; GateGameObjects gains wall field)
|
||||
- tests/e2e/season1-loop.spec.ts (Task 5 — 3 new assertions threaded into PIPE-07 happy path: body bg, FirstRunHint visible after Begin, FirstRunHint gone after first plant)
|
||||
|
||||
decisions:
|
||||
- id: 02-06-D1
|
||||
decision: "First-run hint copy: 'Begin where the soil is bare.' (plan's #1 ranked candidate)"
|
||||
rationale: "CLAUDE.md tone constraint says player-visible copy must match the bible's voice — warm, specific, intermittent, sometimes funny, sometimes devastating. Of the three ranked candidates, #1 has all four bible markers — soil + bare are specific and contemplative; the imperative 'Begin' echoes the BeginScreen CTA without redundancy; the construction is intermittent (one beat, no follow-on). #2 ('The soil is waiting.') is quieter but more elliptical for a brand-new player on frame one. #3 ('Click a tile to plant.') is the functional fallback and would only be chosen if HUMAN-UAT review surfaced #1 as too elliptical. The plan's recommended choice was #1 and there was no reason to deviate."
|
||||
- id: 02-06-D2
|
||||
decision: "Session-state for firstRunHintDismissed (NOT V1Payload — no migrations[2])"
|
||||
rationale: "Plan scope_constraint #3 (also CLAUDE.md hard constraint). The hint is a first-run-of-this-tab affordance, like A Dark Room's '...the room is empty' or '...the fire is dead' surfaces. The player should see it again if they hard-reload before planting; once they plant it stays down for the session. Persisting to save would (1) require migrations[2] which Phase 1 has shipped zero v1 saves to migrate forward and is structurally premature; (2) force a one-time 'permanent dismissal' UX that loses the cozy re-onboarding signal across reloads. Session state is the cleaner shape."
|
||||
- id: 02-06-D3
|
||||
decision: "UiStringsSchema extended with first_run_hint: z.string().min(1) — schema edit was MANDATORY, not optional"
|
||||
rationale: "Zod's default object mode is 'strip' — unknown keys parse SUCCESSFULLY but are SILENTLY DROPPED from parsed.data. Without the schema edit, content/seasons/01-soil/ui-strings.yaml could carry the first_run_hint key but uiStrings[1].first_run_hint would be undefined at runtime, FirstRunHint would render null in production, and only the unit tests that mock the store directly would catch it. The plan's Step 2 calls this out explicitly. The edit is one line in src/content/schemas/ui-strings.ts; the cost of skipping it is a production-only failure mode that unit tests cannot detect. .min(1) defends against an accidental empty-string in YAML."
|
||||
- id: 02-06-D4
|
||||
decision: "Phaser-mock pattern via vi.mock('phaser') for tile-renderer + gate-renderer tests"
|
||||
rationale: "First attempt at tile-renderer test imported the source file directly; Phaser 4's checkInverseAlpha boot probe (canvas.getContext('2d') returning null under happy-dom) crashed the test setup. The plan acknowledged this risk via the SeedPicker mock pattern reference. vi.mock('phaser', () => ({ default: {} })) at module top short-circuits the bundle load entirely; the test then mocks the Scene's add.graphics + add.rectangle surface to capture call args. For gate-renderer, BlendModes.ADD is mocked as the sentinel value 1 so setBlendMode receives a non-undefined argument. The pattern is reusable for plant-renderer + ready-pulse coverage in future phases."
|
||||
- id: 02-06-D5
|
||||
decision: "WALL_BAND_ALPHA = 0.18 (mid of the 0.15-0.20 fix_shape range)"
|
||||
rationale: "The plan's fix_shape says alpha 0.15-0.20. 0.18 is the mid of that range — low enough that the gate body remains the visual focal point (the load-bearing element), high enough that the wall actually reads against the #1a1a1a canvas. Lower (0.15) would be invisible at the edge of the gate; higher (0.20) would compete with the body. Phase 3 paints over without changing this geometry."
|
||||
|
||||
metrics:
|
||||
duration: ~30 min (5 tasks: ~6 min/task average; G1 fastest at ~3 min; G2 longest at ~10 min due to 7-step shape)
|
||||
completed: 2026-05-09
|
||||
tests-added: 21 (was 312 → 333)
|
||||
tests-green: 333/333
|
||||
e2e-assertions-added: 3 (was 16 → 19)
|
||||
e2e-runtime: 1.7s (was 1.6s — 0.1s growth from 3 cheap evaluations + 1 visibility + 1 negation)
|
||||
ci-runtime: ~30s (lint + compile:ink + 333 vitest + validate:assets + build + check:bundle-split)
|
||||
bundle-size: 1.9MB (unchanged — no new dependencies, no new image assets)
|
||||
commits: 5 (one per task; conventional-commit format with `fix(02-06,GN):` / `test(02-06):` scopes)
|
||||
|
||||
requirements-completed: [GARD-01, AEST-07, UX-01]
|
||||
---
|
||||
|
||||
# Phase 2 Plan 06: UAT Gap Closure (G1–G4) Summary
|
||||
|
||||
Closed the 4 first-impression UX gaps that the 2026-05-09 live UAT walkthrough surfaced — the dark canvas no longer floats in a white viewport (G1), a first-time player sees a single bible-voice instructional line after Begin dismisses (G2), the 4×4 tile grid reads as legible interactive surfaces (G3), and the gate has structural wall context instead of floating as a stray gray rectangle (G4). All fixes use Phaser primitives or one CSS file; Phase 3 watercolor deferral preserved.
|
||||
|
||||
## Tasks Executed
|
||||
|
||||
| # | Gap | Severity | Files | Commit | Tests |
|
||||
|---|-----|----------|-------|--------|-------|
|
||||
| 1 | G1 — white halo | BLOCKING | src/index.css, src/main.tsx, src/index.css.test.ts | f52de0b | 6 file-read smoke |
|
||||
| 2 | G2 — no first-run prompt | BLOCKING | content/seasons/01-soil/ui-strings.yaml, src/content/schemas/ui-strings.ts, src/store/session-slice.ts, src/ui/first-run/{FirstRunHint.tsx, FirstRunHint.test.tsx, index.ts}, src/ui/index.ts, src/App.tsx | c46fc75 | 6 behavioral |
|
||||
| 3 | G3 — dim tile grid | HIGH | src/render/garden/tile-renderer.ts, src/render/garden/tile-renderer.test.ts | ab48c7e | 5 phaser-mocked |
|
||||
| 4 | G4 — floating gate | MEDIUM | src/render/garden/gate-renderer.ts, src/render/garden/gate-renderer.test.ts | 88adc4f | 4 phaser-mocked |
|
||||
| 5 | Integration | — | tests/e2e/season1-loop.spec.ts | 47b5b8d | 3 e2e assertions |
|
||||
|
||||
## Hint Copy Chosen
|
||||
|
||||
**`Begin where the soil is bare.`**
|
||||
|
||||
This is the plan's #1 ranked candidate (recommended). Rationale documented in decision 02-06-D1: bible voice (warm + specific + contemplative), echoes the BeginScreen CTA without redundancy, intermittent construction (one beat, no follow-on). The candidate was committed unchanged; no deviation from the plan's recommendation.
|
||||
|
||||
## Test & Gate Results
|
||||
|
||||
- **Vitest:** 312 → 333 (+21 new cases) — 333/333 green.
|
||||
- **Playwright e2e:** 16 → 19 assertions (+3 gap-closure) — 1.6s → 1.7s runtime; 1 passed in 4.7s end-to-end.
|
||||
- **`npm run ci`:** Exit 0 (lint + compile:ink + 333 vitest + validate:assets + build + check:bundle-split).
|
||||
- **`npm run test:e2e`:** Exit 0 (Playwright PIPE-07 with all 3 new assertions green).
|
||||
- **Bundle size:** 1.9MB unchanged — no new dependencies, no new image assets.
|
||||
- **V1Payload:** Unchanged — `firstRunHintDismissed` is session-state only; `migrations[2]` does NOT exist; no `migrations.ts` edits.
|
||||
|
||||
## Constraint Compliance Confirmation
|
||||
|
||||
| Constraint | Verification | Status |
|
||||
|------------|--------------|--------|
|
||||
| No painted assets (Phase 3 watercolor deferral) | `git diff main~5 HEAD -- '*.png' '*.jpg' '*.webp'` is empty | ✓ |
|
||||
| No new npm dependencies | `git diff main~5 HEAD -- package.json package-lock.json` is empty | ✓ |
|
||||
| firstRunHintDismissed is session-state, not save-state | `grep -c firstRunHintDismissed src/save/migrations.ts` = 0 | ✓ |
|
||||
| No migrations[2] entry | `grep -E 'migrations\[2\]\s*=' src/save/migrations.ts` returns no match | ✓ |
|
||||
| Hint copy externalized (not hardcoded) | `grep -L "Begin where the soil is bare\|The soil is waiting\|Click a tile to plant" src/ui/first-run/FirstRunHint.tsx` matches the file (i.e. the candidate strings do NOT appear in the component) | ✓ |
|
||||
| UiStringsSchema extended for first_run_hint | `grep -E 'first_run_hint:\s*z\.string\(\)' src/content/schemas/ui-strings.ts` matches | ✓ |
|
||||
| Tile outline brightened to 0x5a5a60 / 0x7a7a82 | tile-renderer.ts exports OUTLINE_COLOR=0x5a5a60 + OUTLINE_HOVER=0x7a7a82 (old hex literals appear ONLY in comment annotations documenting the change, not in active code paths) | ✓ |
|
||||
| Wall band alpha in 0.15-0.20 range | gate-renderer.ts exports WALL_BAND_ALPHA=0.18 | ✓ |
|
||||
| Wall band height = canvas height | gate-renderer.ts exports WALL_BAND_HEIGHT=768 | ✓ |
|
||||
| Sim purity preserved (no edits in src/sim/**) | `git diff main~5 HEAD -- 'src/sim/**'` is empty | ✓ |
|
||||
| No motion-only affordances | Tile hover is pointer-driven steady-state (color + alpha swap, no tweens); wall band is steady-state alpha, no pulse | ✓ |
|
||||
|
||||
## Gap Closure Evidence (vs 02-VERIFICATION.md frontmatter `gaps:` block)
|
||||
|
||||
| Gap | Fix verification |
|
||||
|-----|------------------|
|
||||
| **G1** white halo | `src/index.css` exists with the 6 required rules (body bg #1a1a1a, color #e8e0d0, margin 0, min-height 100vh, serif, #game-container flex). `src/main.tsx` imports it (line 4). Playwright Assertion A confirms `document.body.backgroundColor === 'rgb(26, 26, 26)'` from frame one in real Chromium. |
|
||||
| **G2** no first-run prompt | `src/ui/first-run/FirstRunHint.tsx` exists; mounted in App.tsx between BeginScreen and SeedPicker. `content/seasons/01-soil/ui-strings.yaml` carries `first_run_hint: "Begin where the soil is bare."`. `src/store/session-slice.ts` carries `firstRunHintDismissed` + `dismissFirstRunHint`. `src/content/schemas/ui-strings.ts` extended with `first_run_hint: z.string().min(1)`. Playwright Assertion B confirms the hint is visible after Begin click; Assertion C confirms it auto-dismisses after the first plantSeed lands. 6 unit tests pin behavior. |
|
||||
| **G3** dim tile grid | `src/render/garden/tile-renderer.ts` exports `OUTLINE_COLOR=0x5a5a60` (was 0x4d4d52) + `OUTLINE_HOVER=0x7a7a82` (was 0x6e6e75) + `HOVER_FILL_ALPHA=0.06` (new). 5 unit tests pin the constants and the pointerover behavior via Phaser-Scene-mock. |
|
||||
| **G4** floating gate | `src/render/garden/gate-renderer.ts` exports `WALL_BAND_X=880` + `WALL_BAND_HEIGHT=768` + `WALL_BAND_ALPHA=0.18` + `WALL_BAND_COLOR=0x6e6e75` + `WALL_BAND_WIDTH=44`. `drawGate` adds the wall as the first rectangle (z-order: behind body / glow / hit). `GateGameObjects` exposes the new `wall` handle. 4 unit tests pin constants in fix_shape range + first-rectangle geometry + 4-rectangle count + wall handle exposure. |
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
**None — plan executed exactly as written.**
|
||||
|
||||
The plan's 5 tasks landed in order with no Rule 1-4 deviations triggered. The plan's anticipated risks were all addressed by the plan's own structure:
|
||||
|
||||
- Phaser 4 / happy-dom incompatibility (G3 + G4 tests) — plan called out via SeedPicker analog reference; Phaser-mock pattern (`vi.mock('phaser', () => ({ default: {} }))`) landed cleanly first try.
|
||||
- Schema-strip mode silently dropping unknown keys (G2 plan Step 2) — plan called out as MANDATORY; schema edit landed first try, content/loader.test.ts continued green.
|
||||
- Garden.ts integration breakage from additive GateGameObjects.wall field — plan called out as risk; verified by reading Garden.ts line 110 (`this.gate = drawGate(this)`) which stores the whole returned object so the additive field is structurally safe; npm run ci confirmed end-to-end.
|
||||
|
||||
## Auth Gates
|
||||
|
||||
None — the plan introduces no auth surfaces; all 5 tasks ran fully autonomously.
|
||||
|
||||
## Decisions Made
|
||||
|
||||
(Captured in frontmatter `decisions:` block above — 02-06-D1 through 02-06-D5.)
|
||||
|
||||
## Handoff to Verifier
|
||||
|
||||
The 4 gap entries in `.planning/phases/02-season-1-vertical-slice-soil/02-VERIFICATION.md` frontmatter `gaps:` block are structurally closed. The verifier (`gsd-verifier`) consumes this SUMMARY + re-runs verification to flip status from `gaps_found` → `verified`.
|
||||
|
||||
**Out of scope for this plan (carried forward):**
|
||||
- 6 HUMAN-UAT.md tone items (Lura voice in the .ink files, letter cadence, Begin tonal feel, ≥5min absence flow, gate visual indicator + LuraDialogue overlay flow). These are inherently subjective and remain pending. They are addressed by the user's tone-review workflow at the next merge / playtest, not by code.
|
||||
- 3 INEFFECTIVE_DYNAMIC_IMPORT build warnings (inherited from Plan 02-02's eager-corpus + lazy-glob co-existence). Phase 4+ resolves these when consumers move to lazy-only.
|
||||
- gray-matter package.json cleanup (tracked in `.planning/phases/02-season-1-vertical-slice-soil/deferred-items.md`).
|
||||
|
||||
**REQ-IDs reinforced (not flipped — those were already structurally PASS in 02-VERIFICATION.md):**
|
||||
- GARD-01 (supplemental — first-frame legibility of the planting affordance)
|
||||
- AEST-07 (supplemental — tonal coherence between body and canvas; Begin dismissal lands on a guided rather than empty surface)
|
||||
- UX-01 (supplemental — first-run prompt presence honors the A-Dark-Room rule the bible cites)
|
||||
|
||||
The Phase-2 vertical slice that "could plausibly ship as a free standalone Season-1 prologue" now actually feels like one to a brand-new player on frame one.
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
All claimed files exist:
|
||||
- src/index.css ✓
|
||||
- src/index.css.test.ts ✓
|
||||
- src/ui/first-run/FirstRunHint.tsx ✓
|
||||
- src/ui/first-run/FirstRunHint.test.tsx ✓
|
||||
- src/ui/first-run/index.ts ✓
|
||||
- src/render/garden/tile-renderer.test.ts ✓
|
||||
- src/render/garden/gate-renderer.test.ts ✓
|
||||
|
||||
All claimed commits exist (verified via `git log --oneline -8`):
|
||||
- f52de0b fix(02-06,G1): add src/index.css and import from main.tsx ✓
|
||||
- c46fc75 fix(02-06,G2): first-run hint after Begin ✓
|
||||
- ab48c7e fix(02-06,G3): brighten tile outline and hover state ✓
|
||||
- 88adc4f fix(02-06,G4): add wall band primitive in gate-renderer ✓
|
||||
- 47b5b8d test(02-06): playwright e2e assertions for G1+G2 ✓
|
||||
|
||||
Final gates:
|
||||
- `npm run ci`: exit 0, 333/333 vitest green ✓
|
||||
- `npm run test:e2e`: exit 0, 1 passed in 4.7s ✓
|
||||
- No new npm deps: ✓
|
||||
- V1Payload unchanged: ✓
|
||||
- No painted assets: ✓
|
||||
Reference in New Issue
Block a user