Spaces:
Running on Zero
Running on Zero
docs(01-02): complete local foundations plan
Browse files- .planning/ROADMAP.md +2 -2
- .planning/STATE.md +40 -14
- .planning/config.json +2 -1
- .planning/phases/01-voice-avatar-loop-skeleton/01-02-SUMMARY.md +248 -0
.planning/ROADMAP.md
CHANGED
|
@@ -32,7 +32,7 @@ Decimal phases appear between their surrounding integers in numeric order.
|
|
| 32 |
4. p50/p95 turn latency is measured and recorded on the deployed Space (cold and warm), and the full loop still completes with the GPU path forcibly disabled.
|
| 33 |
5. LICENSES.md documents verified licenses for the exact VRM character and TTS voice that ship, including any per-character credit requirement.
|
| 34 |
**Plans**: 10 plans in 7 waves
|
| 35 |
-
- [
|
| 36 |
- [ ] 01-01-PLAN.md β Hosting decision + Space creation + VRM sourcing (user-gated) [wave 2]
|
| 37 |
- [ ] 01-04-PLAN.md β VOICEVOX TTS, requirements.txt, ground-truth AudioQuery fixtures [wave 2]
|
| 38 |
- [ ] 01-03-PLAN.md β Avatar stage, shared facade + turn loop, both transports [wave 3]
|
|
@@ -109,7 +109,7 @@ Phases execute in numeric order: 1 β 2 β 3 β 4 β 5 β 6
|
|
| 109 |
|
| 110 |
| Phase | Plans Complete | Status | Completed |
|
| 111 |
|-------|----------------|--------|-----------|
|
| 112 |
-
| 1. Voice + Avatar Loop Skeleton |
|
| 113 |
| 2. Japanese Language Core | 0/TBD | Not started | - |
|
| 114 |
| 3. Tutoring Brain | 0/TBD | Not started | - |
|
| 115 |
| 4. Accounts & Persistence | 0/TBD | Not started | - |
|
|
|
|
| 32 |
4. p50/p95 turn latency is measured and recorded on the deployed Space (cold and warm), and the full loop still completes with the GPU path forcibly disabled.
|
| 33 |
5. LICENSES.md documents verified licenses for the exact VRM character and TTS voice that ship, including any per-character credit requirement.
|
| 34 |
**Plans**: 10 plans in 7 waves
|
| 35 |
+
- [x] 01-02-PLAN.md β Toolchain, LFS arming, package skeleton, test scaffolding (local-only) [wave 1]
|
| 36 |
- [ ] 01-01-PLAN.md β Hosting decision + Space creation + VRM sourcing (user-gated) [wave 2]
|
| 37 |
- [ ] 01-04-PLAN.md β VOICEVOX TTS, requirements.txt, ground-truth AudioQuery fixtures [wave 2]
|
| 38 |
- [ ] 01-03-PLAN.md β Avatar stage, shared facade + turn loop, both transports [wave 3]
|
|
|
|
| 109 |
|
| 110 |
| Phase | Plans Complete | Status | Completed |
|
| 111 |
|-------|----------------|--------|-----------|
|
| 112 |
+
| 1. Voice + Avatar Loop Skeleton | 1/10 | In Progress | - |
|
| 113 |
| 2. Japanese Language Core | 0/TBD | Not started | - |
|
| 114 |
| 3. Tutoring Brain | 0/TBD | Not started | - |
|
| 115 |
| 4. Accounts & Persistence | 0/TBD | Not started | - |
|
.planning/STATE.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# Project State
|
| 2 |
|
| 3 |
## Project Reference
|
|
@@ -5,33 +19,41 @@
|
|
| 5 |
See: .planning/PROJECT.md (updated 2026-08-08)
|
| 6 |
|
| 7 |
**Core value:** A learner can hold a real, level-appropriate spoken Japanese conversation with an animated avatar that talks back β and measurably improve over time because the avatar remembers them.
|
| 8 |
-
**Current focus:** Phase
|
| 9 |
|
| 10 |
## Current Position
|
| 11 |
|
| 12 |
-
Phase:
|
| 13 |
-
Plan:
|
| 14 |
-
Status: Ready to plan
|
| 15 |
-
Last activity: 2026-08-08 β Roadmap created (6 phases, 33/33 v1 requirements mapped)
|
| 16 |
|
| 17 |
-
|
|
|
|
|
|
|
| 18 |
|
| 19 |
## Performance Metrics
|
| 20 |
|
| 21 |
**Velocity:**
|
| 22 |
-
|
| 23 |
-
-
|
| 24 |
-
-
|
|
|
|
| 25 |
|
| 26 |
**By Phase:**
|
| 27 |
|
| 28 |
| Phase | Plans | Total | Avg/Plan |
|
| 29 |
|-------|-------|-------|----------|
|
| 30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
|
| 32 |
**Recent Trend:**
|
| 33 |
-
|
| 34 |
-
-
|
|
|
|
| 35 |
|
| 36 |
*Updated after each plan completion*
|
| 37 |
|
|
@@ -46,6 +68,9 @@ Recent decisions affecting current work:
|
|
| 46 |
- [Roadmap]: SudachiPy tokenization (Phase 2) lands before any level gating or grammar grounding β furigana, lookup, level gating, and vocab tracking all collapse without it.
|
| 47 |
- [Roadmap]: Persistence (Phase 4) is deliberately after the tutor core so the event-sourced schema reflects what the assessment engine actually emits, avoiding a Phase 5 migration.
|
| 48 |
- [Roadmap]: BYOK (LLMB-02) is owned by Phase 4, not Phase 3 β its session-only, never-leaked guarantee is verified by the same concurrent-session isolation gate as account data.
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
### Pending Todos
|
| 51 |
|
|
@@ -59,9 +84,10 @@ None yet.
|
|
| 59 |
- **Asset licensing gates a design branch.** VOICEVOX character terms need a human read (third-party web synthesis, not just generated audio) before TTS is built around it β the fallback loses free mora timings and changes the lip-sync design. VRM model licenses vary per author; self-authored VRoid Studio character removes the question.
|
| 60 |
- **Per-turn GPU-second cost is unmeasured.** The entire free-tier UX budget depends on this number β measure in Phase 1/3, do not assume.
|
| 61 |
- **REQUIREMENTS.md originally miscounted v1 as 31.** Actual count is 33; traceability and coverage corrected during roadmap creation.
|
|
|
|
| 62 |
|
| 63 |
## Session Continuity
|
| 64 |
|
| 65 |
-
Last session: 2026-08-
|
| 66 |
-
Stopped at:
|
| 67 |
Resume file: None
|
|
|
|
| 1 |
+
---
|
| 2 |
+
gsd_state_version: 1.0
|
| 3 |
+
milestone: v1.0
|
| 4 |
+
milestone_name: milestone
|
| 5 |
+
status: unknown
|
| 6 |
+
stopped_at: Completed 01-02-PLAN.md (local foundations). Plan 01-01 still gated on the human hosting decision.
|
| 7 |
+
last_updated: "2026-08-27T00:02:37.063Z"
|
| 8 |
+
progress:
|
| 9 |
+
total_phases: 6
|
| 10 |
+
completed_phases: 0
|
| 11 |
+
total_plans: 10
|
| 12 |
+
completed_plans: 1
|
| 13 |
+
---
|
| 14 |
+
|
| 15 |
# Project State
|
| 16 |
|
| 17 |
## Project Reference
|
|
|
|
| 19 |
See: .planning/PROJECT.md (updated 2026-08-08)
|
| 20 |
|
| 21 |
**Core value:** A learner can hold a real, level-appropriate spoken Japanese conversation with an animated avatar that talks back β and measurably improve over time because the avatar remembers them.
|
| 22 |
+
**Current focus:** Phase 01 β voice-avatar-loop-skeleton
|
| 23 |
|
| 24 |
## Current Position
|
| 25 |
|
| 26 |
+
Phase: 01 (voice-avatar-loop-skeleton) β EXECUTING
|
| 27 |
+
Plan: 2 of 10 (1 complete)
|
|
|
|
|
|
|
| 28 |
|
| 29 |
+
**Completed:** 01-02 (local foundations β pytest/ruff on Python 3.12.12, Git LFS armed, `--space-url` plumbing, audio fixtures).
|
| 30 |
+
**Not started:** 01-01 β it is deliberately out of order. 01-02 is local-only and network-free precisely so it could run in parallel with 01-01's **human hosting checkpoint, which has NOT cleared**. Do not treat "Plan 2" as meaning 01-01 is done.
|
| 31 |
+
**Next actionable:** 01-03 (avatar transport seam) is unblocked β its dependencies are the test loop and package skeleton, both of which now exist. 01-01, 01-04 and 01-05 remain gated on the hosting decision and the VRM/VOICEVOX asset choices.
|
| 32 |
|
| 33 |
## Performance Metrics
|
| 34 |
|
| 35 |
**Velocity:**
|
| 36 |
+
|
| 37 |
+
- Total plans completed: 1
|
| 38 |
+
- Average duration: 21 min
|
| 39 |
+
- Total execution time: 0.35 hours
|
| 40 |
|
| 41 |
**By Phase:**
|
| 42 |
|
| 43 |
| Phase | Plans | Total | Avg/Plan |
|
| 44 |
|-------|-------|-------|----------|
|
| 45 |
+
| 01 | 1 | 21min | 21min |
|
| 46 |
+
|
| 47 |
+
**Per-plan detail:**
|
| 48 |
+
|
| 49 |
+
| Plan | Duration | Tasks | Files |
|
| 50 |
+
|------|----------|-------|-------|
|
| 51 |
+
| Phase 01 P02 | 21min | 3 tasks | 16 files |
|
| 52 |
|
| 53 |
**Recent Trend:**
|
| 54 |
+
|
| 55 |
+
- Last 5 plans: 01-02 (21min)
|
| 56 |
+
- Trend: β (single data point)
|
| 57 |
|
| 58 |
*Updated after each plan completion*
|
| 59 |
|
|
|
|
| 68 |
- [Roadmap]: SudachiPy tokenization (Phase 2) lands before any level gating or grammar grounding β furigana, lookup, level gating, and vocab tracking all collapse without it.
|
| 69 |
- [Roadmap]: Persistence (Phase 4) is deliberately after the tutor core so the event-sourced schema reflects what the assessment engine actually emits, avoiding a Phase 5 migration.
|
| 70 |
- [Roadmap]: BYOK (LLMB-02) is owned by Phase 4, not Phase 3 β its session-only, never-leaked guarantee is verified by the same concurrent-session isolation gate as account data.
|
| 71 |
+
- [Phase 01]: Ruff excludes *.md: ruff 0.16 formats Python blocks embedded in Markdown, which made the phase's own planning docs fail the lint gate. Lint governs shipped Python, not prose.
|
| 72 |
+
- [Phase 01]: uv.lock is committed so a Space rebuild resolves the same dependency set that passed locally; requirements.txt (plan 01-04) remains the Space's contract.
|
| 73 |
+
- [Phase 01]: Git LFS armed for .vrm/.vvm/.wav/.onnx in Wave 1, before any binary exists - retires the 10 MiB non-LFS push rejection ahead of plans 01-01 and 01-04.
|
| 74 |
|
| 75 |
### Pending Todos
|
| 76 |
|
|
|
|
| 84 |
- **Asset licensing gates a design branch.** VOICEVOX character terms need a human read (third-party web synthesis, not just generated audio) before TTS is built around it β the fallback loses free mora timings and changes the lip-sync design. VRM model licenses vary per author; self-authored VRoid Studio character removes the question.
|
| 85 |
- **Per-turn GPU-second cost is unmeasured.** The entire free-tier UX budget depends on this number β measure in Phase 1/3, do not assume.
|
| 86 |
- **REQUIREMENTS.md originally miscounted v1 as 31.** Actual count is 33; traceability and coverage corrected during roadmap creation.
|
| 87 |
+
- **Phase 1 plan frontmatter over-claims shared requirements β do not blind-run `requirements mark-complete`.** DPLY-01 appears in the `requirements:` field of plans 01-01, 01-02, 01-05, 01-09 and 01-10, but it is only *satisfied* by 01-05 (`test_space_reachable`). Executing 01-02 marked it Complete; this was reverted, and DPLY-01 is correctly `Pending`. The same over-claiming applies to AVTR-01/02, VOIC-02/03/04/05 and DPLY-04 across plans 01-09 and 01-10. Verify a requirement's actual acceptance test has run before checking it off.
|
| 88 |
|
| 89 |
## Session Continuity
|
| 90 |
|
| 91 |
+
Last session: 2026-08-27T00:02:37.058Z
|
| 92 |
+
Stopped at: Completed 01-02-PLAN.md (local foundations). Plan 01-01 still gated on the human hosting decision.
|
| 93 |
Resume file: None
|
.planning/config.json
CHANGED
|
@@ -22,7 +22,8 @@
|
|
| 22 |
"node_repair_budget": 2,
|
| 23 |
"ui_phase": true,
|
| 24 |
"ui_safety_gate": true,
|
| 25 |
-
"text_mode": false
|
|
|
|
| 26 |
},
|
| 27 |
"hooks": {
|
| 28 |
"context_warnings": true
|
|
|
|
| 22 |
"node_repair_budget": 2,
|
| 23 |
"ui_phase": true,
|
| 24 |
"ui_safety_gate": true,
|
| 25 |
+
"text_mode": false,
|
| 26 |
+
"_auto_chain_active": false
|
| 27 |
},
|
| 28 |
"hooks": {
|
| 29 |
"context_warnings": true
|
.planning/phases/01-voice-avatar-loop-skeleton/01-02-SUMMARY.md
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
phase: 01-voice-avatar-loop-skeleton
|
| 3 |
+
plan: 02
|
| 4 |
+
subsystem: testing
|
| 5 |
+
tags: [pytest, ruff, uv, playwright, git-lfs, python-3.12, numpy, wav-fixtures]
|
| 6 |
+
|
| 7 |
+
# Dependency graph
|
| 8 |
+
requires: []
|
| 9 |
+
provides:
|
| 10 |
+
- "pytest + ruff toolchain on Python 3.12.12, quick loop measured at ~1.0s"
|
| 11 |
+
- "Git LFS armed for .vrm / .vvm / .wav / .onnx before any binary exists in the repo"
|
| 12 |
+
- "src/japanese_avatar package skeleton (ui, voice, telemetry) every later plan writes into"
|
| 13 |
+
- "tests/conftest.py with the single --space-url option and deployed-marker skip behaviour"
|
| 14 |
+
- "Deterministic 30s silence and 30s cafe-noise WAV fixtures for VOIC-02"
|
| 15 |
+
- "uv.lock pinning the resolved dependency set for reproducible Space rebuilds"
|
| 16 |
+
affects: [01-01, 01-03, 01-04, 01-05, 01-06, 01-07, 01-08, 01-09, 01-10]
|
| 17 |
+
|
| 18 |
+
# Tech tracking
|
| 19 |
+
tech-stack:
|
| 20 |
+
added: [pytest 9.1.1, pytest-playwright 0.9.0, playwright 1.62.0, ruff 0.16.4, numpy 2.5.2, gradio 6.22.0, spaces 0.51.1, huggingface_hub 1.28.0]
|
| 21 |
+
patterns:
|
| 22 |
+
- "pythonpath = [\"src\", \".\"] so `import japanese_avatar` and `import app` both work under pytest with no editable install"
|
| 23 |
+
- "Deployed tests skip, never fail, when --space-url is absent"
|
| 24 |
+
- "Fixtures for later plans (speech_ja.wav, synth_meta.json) skip rather than error until those plans land"
|
| 25 |
+
- "Binary fixtures are generated by a committed deterministic script, not hand-placed"
|
| 26 |
+
|
| 27 |
+
key-files:
|
| 28 |
+
created:
|
| 29 |
+
- pyproject.toml
|
| 30 |
+
- .python-version
|
| 31 |
+
- .gitattributes
|
| 32 |
+
- .gitignore
|
| 33 |
+
- uv.lock
|
| 34 |
+
- src/japanese_avatar/__init__.py
|
| 35 |
+
- tests/conftest.py
|
| 36 |
+
- tests/test_scaffold.py
|
| 37 |
+
- tests/fixtures/make_fixtures.py
|
| 38 |
+
- tests/fixtures/silence_30s.wav
|
| 39 |
+
- tests/fixtures/cafe_noise_30s.wav
|
| 40 |
+
modified: []
|
| 41 |
+
|
| 42 |
+
key-decisions:
|
| 43 |
+
- "Excluded *.md from ruff: ruff 0.16 formats Python blocks embedded in Markdown, which made the phase's own planning docs fail the lint gate"
|
| 44 |
+
- "Committed uv.lock so a Space rebuild resolves the same dependency set that passed locally"
|
| 45 |
+
- "Recorded the cafe-noise fixture's measured RMS (0.0577) in the generator docstring so plan 01-07 tunes against a real number"
|
| 46 |
+
|
| 47 |
+
patterns-established:
|
| 48 |
+
- "Lint gate governs shipped Python only; prose and design snippets are out of ruff's scope"
|
| 49 |
+
- "Every E2E test reaches the Space through one --space-url option; no test hardcodes a URL"
|
| 50 |
+
- "LFS patterns are armed ahead of the binaries they protect, and asserted by a test that runs before those files exist"
|
| 51 |
+
|
| 52 |
+
requirements-completed: [] # DPLY-01 is listed in this plan's frontmatter but is NOT satisfied here β see "Requirement Status" below
|
| 53 |
+
requirements-advanced: [DPLY-01]
|
| 54 |
+
|
| 55 |
+
# Metrics
|
| 56 |
+
duration: 21min
|
| 57 |
+
completed: 2026-08-26
|
| 58 |
+
---
|
| 59 |
+
|
| 60 |
+
# Phase 01 Plan 02: Local Foundations Summary
|
| 61 |
+
|
| 62 |
+
**A repo that lints and tests green on Python 3.12.12 in ~1.0s, with Git LFS armed for `.vrm`/`.vvm`/`.wav`/`.onnx` before the first binary lands and deterministic 30s silence/noise fixtures already committed as LFS pointers.**
|
| 63 |
+
|
| 64 |
+
## Performance
|
| 65 |
+
|
| 66 |
+
- **Duration:** ~21 min
|
| 67 |
+
- **Started:** 2026-08-26T23:47Z
|
| 68 |
+
- **Completed:** 2026-08-27T00:08Z
|
| 69 |
+
- **Tasks:** 3 of 3
|
| 70 |
+
- **Files created:** 16 tracked (13 source/config + `uv.lock` + 2 LFS binaries), verified by `git diff --name-only 84055d7 HEAD`
|
| 71 |
+
|
| 72 |
+
## Accomplishments
|
| 73 |
+
|
| 74 |
+
- Python pinned to **3.12.12** and actually installed via `uv python install`; `uv run python -c "import sys; assert sys.version_info[:2]==(3,12)"` reports `3.12.12 (main, Feb 12 2026)`. The machine's PATH Python is 3.11.0 and is now irrelevant to this project. This closes RESEARCH Pitfall 9 (the habit of copying `3.11` from the account's eight existing Spaces, which is valid on `cpu-basic` and invalid on ZeroGPU).
|
| 75 |
+
- **Git LFS armed before any binary existed anywhere in the repo.** `.gitattributes` was committed in Task 1; the first binaries arrived in Task 3 and landed as pointers automatically.
|
| 76 |
+
- Quick loop and lint gate both green and fast β the 15s Nyquist feedback budget from `01-VALIDATION.md` is met with ~14s of headroom.
|
| 77 |
+
- Package skeleton created at every location `01-RESEARCH.md` "Recommended Project Structure" specifies, so no later plan has to invent a path.
|
| 78 |
+
- `--space-url` plumbing verified end-to-end, including the skip path.
|
| 79 |
+
- Silence and cafe-noise fixtures generated, proven byte-reproducible, and committed through LFS.
|
| 80 |
+
|
| 81 |
+
### Measured numbers required by the plan's `<output>` block
|
| 82 |
+
|
| 83 |
+
| Measurement | Value |
|
| 84 |
+
|---|---|
|
| 85 |
+
| **Quick-loop runtime** (`pytest tests/ -x -q --ignore=tests/e2e`) | **0.956 s** (three timed runs: 1151 ms, 1114 ms, 956 ms) β budget is 15 s |
|
| 86 |
+
| **Cafe-noise fixture RMS** | **0.057699** (= **-24.8 dBFS**); peak 0.135712 β plan 01-07 tunes its modulation threshold against this |
|
| 87 |
+
| **`git check-attr filter -- avatar/assets/tutor.vrm`** | `filter: lfs` β **confirmed while the file does not exist** |
|
| 88 |
+
| **`git check-attr filter -- voicevox/model/zundamon.vvm`** | `filter: lfs` β **confirmed while the file does not exist** |
|
| 89 |
+
|
| 90 |
+
Both fixtures: 24000 Hz, mono, 16-bit PCM, 720000 frames, **30.000000 s** exactly, 1 440 044 bytes each.
|
| 91 |
+
|
| 92 |
+
Regeneration is byte-identical. SHA-256 before and after a second `make_fixtures.py` run:
|
| 93 |
+
|
| 94 |
+
- `silence_30s.wav` β `22a4da1b6841f7db580ce7f434cb659e7f7d4b0ec326c8ce3b0b8c333bc05e26`
|
| 95 |
+
- `cafe_noise_30s.wav` β `fdaae2c7791b7b714e1da1f21dd4c46b8391a62e7adc86e98111f85e5dc0a797`
|
| 96 |
+
|
| 97 |
+
The LFS pointer's `oid sha256` for `cafe_noise_30s.wav` matches that hash exactly, confirming the clean filter ran rather than the raw blob being stored.
|
| 98 |
+
|
| 99 |
+
## Task Commits
|
| 100 |
+
|
| 101 |
+
Each task was committed atomically:
|
| 102 |
+
|
| 103 |
+
1. **Task 1: Python toolchain, LFS config, package skeleton, lint and test config** β `b0821c5` (chore)
|
| 104 |
+
2. **Task 2: Shared fixtures and the `--space-url` plumbing** β `ccf5848` (test)
|
| 105 |
+
3. **Task 3: Deterministic silence and noise fixtures** β `4a095fc` (test)
|
| 106 |
+
|
| 107 |
+
## Files Created/Modified
|
| 108 |
+
|
| 109 |
+
- `.python-version` β `3.12.12`, the ZeroGPU-legal interpreter
|
| 110 |
+
- `.gitattributes` β LFS patterns for `.vrm`, `.vvm`, `.wav`, `.onnx` (4 lines, all `filter=lfs`)
|
| 111 |
+
- `.gitignore` β `.venv/`, `__pycache__/`, `*.pyc`, `.pytest_cache/`, `.ruff_cache/`, `node_modules/`, `.env`, `voicevox_runtime/`, `test-results/`
|
| 112 |
+
- `pyproject.toml` β pytest ini options (`testpaths`, `pythonpath`, `--strict-markers`, `deployed`/`slow` markers), ruff config, dev extra, hatchling wheel targeting `src/japanese_avatar`
|
| 113 |
+
- `uv.lock` β resolved dependency set
|
| 114 |
+
- `src/japanese_avatar/__init__.py` β `__version__ = "0.1.0"`
|
| 115 |
+
- `src/japanese_avatar/{ui,voice,telemetry}/__init__.py` β empty package markers for plans 01-03/04/06/08
|
| 116 |
+
- `tests/__init__.py`, `tests/e2e/__init__.py` β package markers
|
| 117 |
+
- `tests/test_scaffold.py` β 6 tests: interpreter version, package importability, config shape, LFS arming, fixture durations, fixture loudness
|
| 118 |
+
- `tests/conftest.py` β `--space-url` option, `deployed` skip hook, `space_url` / `fixtures_dir` / `silence_wav` / `cafe_noise_wav` / `speech_wav` / `synth_meta` fixtures, `wav_duration_seconds` helper
|
| 119 |
+
- `tests/fixtures/make_fixtures.py` β deterministic generator (seed `20260826`)
|
| 120 |
+
- `tests/fixtures/silence_30s.wav`, `tests/fixtures/cafe_noise_30s.wav` β LFS-tracked
|
| 121 |
+
|
| 122 |
+
## Decisions Made
|
| 123 |
+
|
| 124 |
+
- **Ruff governs Python, not prose.** Ruff 0.16 lints and formats Python code blocks embedded in Markdown. `ruff format --check .` therefore wanted to reformat seven `.planning/**/*.md` files (design snippets in `01-03-PLAN.md`, `01-04-PLAN.md`, `01-06-PLAN.md`, `01-08-PLAN.md`, `01-RESEARCH.md`, `research/ARCHITECTURE.md`, `research/STACK.md`). Adding `*.md` to `extend-exclude` keeps the gate meaningful for shipped code and stops future `docs/*.md` (plans 01-01/04/05/07/10 all write one) from breaking it.
|
| 125 |
+
- **`uv.lock` is committed.** `CLAUDE.md` calls the lockfile the reason to use uv at all β it makes "works locally, breaks on Space rebuild" reproducible. Leaving it untracked would have discarded that. The Space still consumes `requirements.txt` (plan 01-04 owns it); the lock is the local source of truth.
|
| 126 |
+
- **The cafe-noise docstring now states the measured level.** It claimed `~-16 dBFS`; the fixture measures `-24.8 dBFS`. Since plan 01-07 reads this file to calibrate its gate, a 9 dB error in the comment was worth correcting. The generator's arithmetic was not touched, so the WAVs are unchanged.
|
| 127 |
+
|
| 128 |
+
## Deviations from Plan
|
| 129 |
+
|
| 130 |
+
### Auto-fixed Issues
|
| 131 |
+
|
| 132 |
+
**1. [Rule 3 - Blocking] `ruff format --check .` failed on Markdown planning documents**
|
| 133 |
+
|
| 134 |
+
- **Found during:** Task 1 (lint gate verification)
|
| 135 |
+
- **Issue:** Ruff 0.16.4 formats Python code fences inside Markdown. `ruff format --check .` exited 1 with "7 files would be reformatted", all of them `.planning/` docs and research notes. The plan's acceptance criterion requires exit 0, and the plan's `extend-exclude` only listed `avatar/vendor`. Left unfixed this would have blocked every subsequent plan's lint gate, exactly the "accumulated ruff debt" failure mode `CLAUDE.md` warns about.
|
| 136 |
+
- **Fix:** `extend-exclude = ["avatar/vendor", "*.md"]` in `[tool.ruff]`, with a comment explaining why.
|
| 137 |
+
- **Files modified:** `pyproject.toml`
|
| 138 |
+
- **Verification:** `uv run ruff check .` β "All checks passed!" (exit 0); `uv run ruff format --check .` β "9 files already formatted" (exit 0). No `.planning/` file was modified.
|
| 139 |
+
- **Committed in:** `b0821c5` (Task 1 commit)
|
| 140 |
+
|
| 141 |
+
**2. [Rule 2 - Missing Critical] `uv.lock` was not in the plan's `files_modified`**
|
| 142 |
+
|
| 143 |
+
- **Found during:** Task 1 (dependency install)
|
| 144 |
+
- **Issue:** `uv sync --extra dev` generates `uv.lock`. The plan neither listed it nor gitignored it, so it would have been left untracked β discarding the reproducibility guarantee that is `CLAUDE.md`'s stated reason for choosing uv.
|
| 145 |
+
- **Fix:** Committed `uv.lock` alongside `pyproject.toml`.
|
| 146 |
+
- **Files modified:** `uv.lock` (new)
|
| 147 |
+
- **Verification:** `git status --short` shows no untracked files.
|
| 148 |
+
- **Committed in:** `b0821c5` (Task 1 commit)
|
| 149 |
+
|
| 150 |
+
**3. [Rule 1 - Doc bug] Cafe-noise docstring overstated the fixture's level by ~9 dB**
|
| 151 |
+
|
| 152 |
+
- **Found during:** Task 3 (fixture measurement)
|
| 153 |
+
- **Issue:** The generator docstring supplied by the plan claims `~-16 dBFS`. Measured RMS is 0.057699 = -24.8 dBFS. Plan 01-07 reads this file to calibrate its speech/noise gate against the fixture, so the wrong number is actively misleading.
|
| 154 |
+
- **Fix:** Docstring now states the measured RMS and peak. Signal math untouched β fixtures are byte-identical to the first generation.
|
| 155 |
+
- **Files modified:** `tests/fixtures/make_fixtures.py`
|
| 156 |
+
- **Verification:** SHA-256 of both WAVs identical across regeneration; RMS assertion (`> 0.02`) passes at 0.0577.
|
| 157 |
+
- **Committed in:** `4a095fc` (Task 3 commit)
|
| 158 |
+
|
| 159 |
+
### Acceptance criteria restated rather than skipped
|
| 160 |
+
|
| 161 |
+
Two of Task 2's acceptance criteria were literal `grep -c` counts that contradict the code the plan itself specifies. `grep -c` counts *matching lines*, not occurrences:
|
| 162 |
+
|
| 163 |
+
- `grep -c "addoption" tests/conftest.py` expected `1`, returns **`2`** β because the hook's own name, `def pytest_addoption(parser):`, contains the substring, in addition to the `parser.addoption(` call.
|
| 164 |
+
- `grep -c '"--space-url"' tests/conftest.py` expected `1`, returns **`3`** β the option is registered once and then read in `pytest_collection_modifyitems` and in the `space_url` fixture, exactly as the plan's own code listing does it.
|
| 165 |
+
|
| 166 |
+
The substantive property both criteria are reaching for β **one option, registered exactly once** β was verified directly: `grep -c 'parser\.addoption' tests/conftest.py` returns **`1`**. No code was contorted to satisfy a miscounted grep. The third criterion (`6` fixture/helper definitions) matched exactly as written.
|
| 167 |
+
|
| 168 |
+
---
|
| 169 |
+
|
| 170 |
+
**Total deviations:** 3 auto-fixed (1 blocking, 1 missing-critical, 1 doc bug) + 2 acceptance criteria restated
|
| 171 |
+
**Impact on plan:** No scope creep. Deviation 1 was required for the plan's own lint criterion to be satisfiable at all; 2 and 3 protect later plans from the failure modes this plan exists to prevent.
|
| 172 |
+
|
| 173 |
+
## Issues Encountered
|
| 174 |
+
|
| 175 |
+
- **The `deployed` skip path needed a temporary test to prove.** The plan asks for a throwaway `@pytest.mark.deployed` test. Created, exercised both ways, deleted. Observed output, as required for the record:
|
| 176 |
+
- Without the option: `SKIPPED [1] tests\test_tmp_deployed_probe.py:4: needs --space-url (deployed Space)` β **skipped, not failed**.
|
| 177 |
+
- With `--space-url=https://example.invalid`: `1 passed`. No network request is made; the fixture only normalises the string.
|
| 178 |
+
- `git status --short` confirms the probe left no trace.
|
| 179 |
+
- One transient `Failed to write cache file ... .ruff_cache ... Access is denied (os error 5)` warning on Windows during a concurrent ruff invocation. Cosmetic; the run itself reported "All checks passed!" and subsequent runs are clean.
|
| 180 |
+
|
| 181 |
+
## Requirement Status
|
| 182 |
+
|
| 183 |
+
**DPLY-01 remains `Pending`. It was deliberately NOT marked complete.**
|
| 184 |
+
|
| 185 |
+
This plan's frontmatter carries `requirements: [DPLY-01]`, but DPLY-01 is *"App is live as a public Hugging Face Space on the WolfDavid profile"*, and `01-VALIDATION.md` binds it to `tests/e2e/test_avatar_loop.py::test_space_reachable`, which **plan 01-05 creates**. DPLY-01 is shared across plans 01-01, 01-02, 01-05, 01-09 and 01-10; this plan contributes the test infrastructure that requirement will eventually be verified through, and nothing more. A local-only plan that creates no Space cannot satisfy "the Space is live".
|
| 186 |
+
|
| 187 |
+
`requirements mark-complete DPLY-01` was run as part of the standard state-update sequence, flipped the checkbox and the traceability row, and was **reverted** (`git checkout -- .planning/REQUIREMENTS.md`). `REQUIREMENTS.md` line 60 reads `- [ ] **DPLY-01**` and line 131 reads `| DPLY-01 | Phase 1 | Pending |`, both verified after the revert. Marking it complete would have told the phase verifier a deployed Space exists when none does.
|
| 188 |
+
|
| 189 |
+
## Constraint Compliance
|
| 190 |
+
|
| 191 |
+
The plan is local-only and parallel-safe with the un-cleared human hosting gate in plan 01-01. Verified:
|
| 192 |
+
|
| 193 |
+
- **No Space was created and no Hugging Face API was contacted.** No `hf` CLI call, no `huggingface_hub` call, no `README.md` front-matter written. Space manifest and deploy remain with plans 01-04 and 01-05, where the plan assigns them.
|
| 194 |
+
- **No `git push` occurred β and could not have.** `git remote -v` returns empty; this repo has **no remote configured at all**. `git reflog` shows only the three task commits.
|
| 195 |
+
- **No money was spent.** No PRO subscription, no paid resource.
|
| 196 |
+
- Network egress was limited to package/toolchain acquisition explicitly instructed by the plan's own `<action>` blocks: `uv python install 3.12.12` (20.8 MiB), `uv sync --extra dev` (PyPI), `uv run playwright install chromium`. These are the "Framework install" line item in `01-VALIDATION.md` Wave 0 Requirements. The prohibition is on HF/Space network dependency, which was fully honoured.
|
| 197 |
+
- **Zero AI tutoring in scope.** No LLM, no level gating, no grammar database, no accounts, no database.
|
| 198 |
+
|
| 199 |
+
## Environment Note
|
| 200 |
+
|
| 201 |
+
Playwright's cached Chromium (`chromium-1223`, `chromium-1228`) was present, but Playwright 1.62.0 requires **build 1234**, so `playwright install chromium` did download (~114.5 MiB) into `chromium-1234` and `chromium_headless_shell-1234`. The pre-existing cache did not save the download. `uv run playwright --version` β `Version 1.62.0`.
|
| 202 |
+
|
| 203 |
+
Resolved dev toolchain: pytest **9.1.1**, pytest-playwright 0.9.0, playwright 1.62.0, ruff 0.16.4, numpy **2.5.2**. Runtime pins resolved exactly as specified: gradio 6.22.0, spaces 0.51.1, huggingface_hub 1.28.0.
|
| 204 |
+
|
| 205 |
+
## Known Stubs
|
| 206 |
+
|
| 207 |
+
The empty `__init__.py` files at `src/japanese_avatar/{ui,voice,telemetry}/` are intentional package markers, not stubs β the plan's `<interfaces>` block assigns each module to a specific later plan (`ui/blocks.py` β 01-08, `ui/avatar_component.py` β 01-03, `voice/tts.py` β 01-04, `voice/visemes.py` β 01-06, `voice/models.py` β 01-04, `telemetry/timings.py` β 01-08). Nothing renders from them and no data path depends on them yet.
|
| 208 |
+
|
| 209 |
+
`tests/conftest.py`'s `speech_wav` and `synth_meta` fixtures deliberately `pytest.skip` until plan 01-04 generates `speech_ja.wav` and `synth_meta.json`. This is the plan's explicit design: a Wave 1 plan must not leave the suite red for plans that have not run yet.
|
| 210 |
+
|
| 211 |
+
## User Setup Required
|
| 212 |
+
|
| 213 |
+
None β no external service configuration required by this plan. The hosting decision and Space creation remain gated behind the human checkpoint in plan 01-01.
|
| 214 |
+
|
| 215 |
+
## Next Phase Readiness
|
| 216 |
+
|
| 217 |
+
Ready for the rest of Phase 1:
|
| 218 |
+
|
| 219 |
+
- **Plan 01-01** can commit `avatar/assets/tutor.vrm` the moment the VRM exists β LFS is armed and verified for that exact path.
|
| 220 |
+
- **Plan 01-04** can commit the ~60 MB `.vvm` and the Open JTalk dictionary; `voicevox/model/*.vvm` already resolves to `filter: lfs`. This is RESEARCH Pitfall 6's "10 MiB non-LFS push rejection" retired before it could occur.
|
| 221 |
+
- **Plans 01-03/05/07/09/10** can write `tests/e2e/*` against `--space-url` with no further plumbing.
|
| 222 |
+
- **Plan 01-06** has a working pytest loop for `test_visemes.py`, the densest test file in the phase.
|
| 223 |
+
- **Plan 01-07** has both non-speech fixtures and the measured noise RMS (0.0577) to calibrate against.
|
| 224 |
+
|
| 225 |
+
Carried forward, unchanged by this plan:
|
| 226 |
+
|
| 227 |
+
- The hosting model is still unresolved (ZeroGPU eligibility vs PRO) β plan 01-01's human gate.
|
| 228 |
+
- VOICEVOX character terms still need a human read before TTS is built around them.
|
| 229 |
+
- Per-turn GPU-second cost remains unmeasured.
|
| 230 |
+
|
| 231 |
+
## Self-Check: PASSED
|
| 232 |
+
|
| 233 |
+
All 16 files claimed created exist on disk. All 3 task commit hashes (`b0821c5`, `ccf5848`, `4a095fc`) resolve in `git log --all`. Dependency versions in the frontmatter were corrected against `importlib.metadata` (pytest 9.0.2 β **9.1.1**, numpy 2.4.1 β **2.5.2**) and the Playwright browser-build note was corrected against the on-disk cache (**1234**, not 1235) rather than left as an unverified assertion. File count corrected 17 β **16** against `git diff --name-only`.
|
| 234 |
+
|
| 235 |
+
Full plan verification block re-run after the final task commit:
|
| 236 |
+
|
| 237 |
+
| Check | Result |
|
| 238 |
+
|---|---|
|
| 239 |
+
| `pytest tests/ -x -q --ignore=tests/e2e` | 6 passed, **0.956 s** |
|
| 240 |
+
| `ruff check . && ruff format --check .` | "All checks passed!" / "9 files already formatted", exit 0 |
|
| 241 |
+
| `git check-attr filter -- avatar/assets/tutor.vrm voicevox/model/zundamon.vvm` | both `filter: lfs` |
|
| 242 |
+
| `git lfs ls-files` | both WAV fixtures listed |
|
| 243 |
+
| `pytest tests/ -q --space-url=https://example.invalid --collect-only` | exit 0 |
|
| 244 |
+
| `git remote -v` | empty β no push was possible |
|
| 245 |
+
|
| 246 |
+
---
|
| 247 |
+
*Phase: 01-voice-avatar-loop-skeleton*
|
| 248 |
+
*Completed: 2026-08-26*
|