# PRD: AskRex Assistant Production Readiness and Release Candidate Hardening > **Active PRD — 2026-07-22.** This is the only active release-readiness tracker. `PRD.md` and `PRD-remaining-release-readiness.md` are retained as superseded historical evidence. The current cross-cutting audit implementation ledger is [docs/audits/AUDIT-REMEDIATION-2026-07-22.md](docs/audits/AUDIT-REMEDIATION-2026-07-22.md). Local completion does not imply CI, signing, hardware, or external-provider verification. > **Ralph execution rule** > A task means one full User Story, not one checkbox. > For the remaining integrated production-readiness/Rex 2.0 work, choose the first User Story with any unchecked `[ ]` acceptance criterion from the **Integrated execution order - 2026-08-08** below; do not use raw file position as the priority signal. Stories outside that list retain their historical status and are not reopened unless a later story explicitly depends on them. > Complete exactly one User Story per iteration. > A User Story is only complete when current code, tests, and acceptance criteria prove it. > When a story is complete, update `PRD-production-readiness.md` and `docs/archive/progress/progress-production-readiness.txt` in the same commit as the implementation. > Do not commit completed implementation work while leaving that story unchecked in this PRD. > This PRD is the authoritative task tracker for the production-readiness workstream. `docs/archive/progress/progress-production-readiness.txt` is supporting history only. > A story is not done until all relevant local validations pass AND all required GitHub checks pass on the PR for that story. > **Reconciliation note — 2026-06-12** > This PRD was reconciled against HEAD `548bf32` on branch `ralph/reconcile-production-readiness-prd` after the remaining-release-readiness workstream and final validation PRs. Completed decompositions from that workstream are marked as satisfied baseline evidence so Ralph does not repeat them. User-observed Electron GUI and product gaps from live testing have been added as explicit unchecked stories or acceptance criteria. This reconciliation did not implement runtime behavior. > **Reconciliation note — 2026-07-08 (issue #300)** > Re-audited Section 2 (Current State), Section 6 (Blocker Inventory), and the Phase 3–4 acceptance criteria against `master` HEAD `fde0c76`. Stale baseline claims are now marked **[RESOLVED — historical]** in place with the verifying commit or CI evidence; do not implement them again. Stories US-021, US-022, US-030, and US-032 were verified complete against current code/CI and are now checked. US-023/US-024/US-033/US-036 carry updated per-box status notes. `PRD-remaining-release-readiness.md` is complete except two Definition-of-Done boxes (a literal base-deps clean-checkout pytest run, and an owner decision on the re-added sanitized fixtures `profiles/james.json`/`users.json`) — treat it as historical evidence, not an active tracker. This reconciliation did not implement runtime behavior. > **Audit remediation note — 2026-07-22** > Findings A–K from the current audit are implemented in reviewable commits and locally verified as recorded in `docs/audits/AUDIT-REMEDIATION-2026-07-22.md`. This supersedes older baseline prose for calendar isolation, Electron identity/data ownership, HA mutation verification, tool lifecycle, managed Electron runtime, Windows artifact CI, Hold to Talk, integration-state truth, diagnostics/security gates, and GUI dependency gates. Items remain **locally verified**, not CI verified, until the pull-request checks pass. The unsigned installer and hardware/external-provider checks remain explicit release limitations. > **Rex 2.0 integration reconciliation - 2026-08-08** > The reviewed Rex 2.0 intelligence/latency/tooling/memory/self-extension plan is now an architectural amendment to this production-readiness workstream, not a separate future rewrite. Current runtime code remains authoritative until the specific story that migrates a boundary is implemented and verified. The migration is intentionally evolutionary: establish truthful baseline evidence, converge `generate_reply()` and `stream_reply()` on one TurnEngine/event contract, then build capability/action/latency/model/memory/OpenClaw/Forge work on that shared foundation. Rex remains local-first and remains the orchestrator, identity authority, permission/risk layer, verifier, memory system, and final responder; OpenClaw/ClawHub remain optional capability providers. No new paid service is required. Existing fail-closed identity is sufficient to begin the TurnEngine foundation; US-087 later unifies cross-surface and household semantics. SMS remains available through the backend/direct route but intentionally stays out of primary navigation. > > Design: `docs/superpowers/specs/2026-08-08-rex2-production-readiness-integration-design.md` > Implementation plan: `docs/superpowers/plans/2026-08-08-rex2-production-readiness-integration.md` > **Always-on household voice product-contract amendment - 2026-08-31** > The final AskRex consumer product must remain available for screenless household voice use when the Electron and mobile apps are not open. One packaged Windows installation owns an authoritative Rex Core plus a local background Voice Agent; additional rooms use lightweight trusted Rex Room endpoints rather than independent full Rex stacks. The consumer setup flow must cover audio/wake-word calibration, room assignment, background startup, privacy controls, and verified screenless operation. This amendment is a target and release requirement, not a claim that today's wake-word path is production-ready: existing Hold-to-Talk and beta wake-word labels remain truthful until US-124 through US-130 and their physical-hardware gates pass. > > Canonical product contract: `docs/architecture/end-user-installation-and-voice-runtime.md` ### Integrated execution order - 2026-08-08 Use this order for task selection after the reconciliation above. Select the first story below that still has any unchecked acceptance criterion: 1. `US-063` 2. `US-075` 3. `US-064` 4. `US-094` 5. `US-095` 6. `US-096` 7. `US-076` 8. `US-097` 9. `US-098` 10. `US-106` 11. `US-107` 12. `US-109` 13. `US-108` 14. `US-104` 15. `US-099` 16. `US-105` 17. `US-110` 18. `US-111` 19. `US-071` 20. `US-072` 21. `US-073` 22. `US-077` 23. `US-078` 24. `US-113` 25. `US-114` 26. `US-101` 27. `US-074` 28. `US-068` 29. `US-069` 30. `US-070` 31. `US-100` 32. `US-102` 33. `US-103` 34. `US-079` 35. `US-067` 36. `US-065` 37. `US-066` 38. `US-080` 39. `US-081` 40. `US-082` 41. `US-087` 42. `US-083` 43. `US-084` 44. `US-085` 45. `US-086` 46. `US-112` 47. `US-088` 48. `US-120` 49. `US-121` 50. `US-122` 51. `US-123` 52. `US-115` 53. `US-116` 54. `US-117` 55. `US-089` 56. `US-090` 57. `US-091` 58. `US-092` 59. `US-093` 60. `US-119` 61. `US-124` 62. `US-125` 63. `US-126` 64. `US-127` 65. `US-128` 66. `US-129` 67. `US-130` 68. `US-118` **Dependency/security notes:** TurnEngine work must preserve the already-implemented explicit, fail-closed user identity contract from its first event. US-087 later proves the broader user/household model and James/Cole concurrency invariants. OpenClaw metadata never widens local authority. Mobile remains desktop-paired and least-privilege. All benchmark evidence must label whether it is deterministic/mock, local source runtime, live provider, packaged Windows artifact, or physical hardware/device. --- ## 1. Executive Summary AskRex Assistant is a local-first, voice-activated AI companion targeting Windows 10/11, macOS, and Linux. The repository contains a Python package (`rex/`), root-level bridge scripts and compatibility shims, a Flask backend (`rex.gui_app`), and an Electron + React desktop GUI under `gui/`. Today the codebase is functional enough for development but it is NOT a release candidate. Production blockers exist across packaged runtime correctness, packaging truth, security audit triage, CI coverage, voice reliability, Home Assistant verification, OpenClaw boundary, documentation honesty, Electron GUI capability parity, mobile/API access safety, per-user memory/privacy, and response quality. This PRD turns AskRex Assistant into a production-ready release candidate by closing every issue listed in the Blocker Inventory (Section 6) through small, dependency-ordered User Stories. Each story is sized for a single Ralph iteration, includes concrete validation commands, requires documentation updates whenever user-facing behavior changes, and requires all relevant GitHub checks to pass before it is marked complete. The core AskRex principle is preserved end-to-end: Rex must never claim an action succeeded unless the action was verified. Stories that affect Home Assistant control, tool execution, OpenClaw routing, voice pipeline status reporting, and CLI/GUI status surfaces all enforce this rule. --- ## 2. Current State The following facts were verified directly from the repository at the time this PRD was authored. They are baseline context, not checklist items, and are not action items by themselves. ### 2.1 Renderer raw `/api/` fetches — [RESOLVED — historical] **Re-verified 2026-07-08 on `master@fde0c76`:** zero raw `fetch('/api/...')` call sites remain anywhere under `gui/src/**` (`grep -rn "fetch('/api\|fetch(\`/api" gui/src` returns nothing). The migration to typed IPC (US-003 through US-012) is complete, and the **GUI Raw API Fetch Guard** CI job (`scripts/check_no_renderer_api_fetch.py`) runs on every PR to prevent regression. Do not re-implement this migration. *Historical baseline (authoring time):* `gui/src/**` contained direct browser-style fetches in `AboutPage.tsx`, `CommandHistoryPage.tsx`, `DevicesPage.tsx`, `QuickActionsPage.tsx`, `SetupWizardPage.tsx`, and `App.tsx` that depended on a Flask backend the packaged Electron app does not spawn. ### 2.2 Packaging metadata — [PARTIALLY RESOLVED — see note] - `pyproject.toml` declares `name = "askrex-assistant"`, `requires-python = ">=3.11,<3.12"`, and six console scripts: `rex`, `rex-config`, `rex-speak-api`, `rex-agent`, `rex-gui`, `rex-tool-server`. (Version is now managed by release-please; see `.release-please-manifest.json`.) - **[RESOLVED — historical]** *(re-verified 2026-07-08)*: the stale `py_modules` entries (`rex_assistant`, `memory_utils`, `audio_config`, `conversation_memory`) were removed by US-014 on 2026-06-23; `setup.py` documents the removal inline and now declares only modules that exist on disk. The **Wheel Contents Smoke Test** CI job (`scripts/check_wheel_contents.py`) guards wheel contents on every PR. Do not repeat this fix. - Wheel resource-inclusion scope (`bridge/`, root wrappers, `config/` examples, UI assets) is governed by US-016; check that story's boxes for current status rather than this baseline text. ### 2.3 Root-level Python files 27 `.py` files live at the repository root: `config.py`, `conftest.py`, `flask_proxy.py`, `llm_client.py`, `rex_chat_bridge.py`, `rex_chat_stream_bridge.py`, `rex_file_extract_bridge.py`, `rex_loop.py`, `rex_memories_bridge.py`, `rex_reminders_bridge.py`, `rex_shopping_list_bridge.py`, `rex_speak_api.py`, `rex_speaker_bridge.py`, `rex_stt_bridge.py`, `rex_tasks_bridge.py`, `rex_voice_bridge.py`, `rex_voice_enrollment_bridge.py`, `rex_voice_sample_bridge.py`, `rex_voice_upload_bridge.py`, `rex_voices_bridge.py`, `rex_wakeword_list_bridge.py`, `rex_wakeword_sample_bridge.py`, `rex_wakeword_train_bridge.py`, `setup.py`, `sitecustomize.py`, `voice_loop.py`, `wsgi.py`. `CLAUDE.md` currently documents 9 active root-level `.py` files, which is a narrower active-surface classification and does not equal the current root file count. ### 2.4 Bridge layout Canonical bridge implementations live under `bridge/` (`bridge/rex_chat_bridge.py`, `bridge/rex_voice_bridge.py`, etc.). The repository root contains thin wrappers with the same filenames. Electron `bridgeResolver.ts` is the single source of truth for which path is resolved in dev vs packaged mode, but the relationship between root wrappers and `bridge/` canonicals is not codified by tests. ### 2.5 Security audit findings — [RESOLVED — historical] `scripts/security_audit.py` exists and scans for merge markers, placeholder/incomplete code, and exposed secrets. **Re-verified 2026-07-08 on `master@fde0c76`: all three findings below are fixed. Do not re-implement them.** - `rex/openclaw/workflow_bridge.py` workflow executor stub — fixed by `977a885` ("fix(openclaw): replace workflow_bridge register() stub with fail-closed behavior (US-021)"); no `stub`/`NotImplementedError`/`placeholder` markers remain. - `rex/replay.py` placeholder results — fixed by `3b049cd` (US-020); no `stub`/`placeholder` strings remain in the file. - `rex/skills/trainer.py` `# TODO: implement` — fixed by `fde0c76` (PR #295, US-022); `grep -n "TODO: implement" rex/skills/trainer.py` returns nothing. ### 2.6 Deprecated API usage Verified call sites: - `rex/assistant.py` line 404: `datetime.utcnow()` - `rex/assistant.py` line 840: `datetime.utcnow()` - `rex/geolocation.py` line 41: `asyncio.get_event_loop()` - `rex/openclaw/tool_executor.py` line 560: `asyncio.get_event_loop()` - `rex/tts_voices.py` lines 192, 244: `asyncio.get_event_loop()` ### 2.7 Large files The remaining giant file is `gui/src/pages/SettingsPage.tsx` at 5,360 lines. Previously large decomposition targets are now small facades or entrypoints: - `rex/cli.py` — 230 lines. - `rex/voice_loop.py` — 127 lines. - `rex/gui_app.py` — 207 lines. - `gui/src/main/index.ts` — 39 lines. ### 2.8 CI coverage `.github/workflows/ci.yml` currently runs full-repo Ruff (`ruff check --output-format=github .`), Black over `rex/ tests/ bridge/ *.py` but not `scripts/`, `python -m compileall -q rex scripts`, `mypy rex --ignore-missing-imports`, GUI typecheck, GUI build, high-severity npm audits for `gui/` and `rex/ui/`, console entrypoint smoke checks, pytest with coverage using `pytest -m "not slow and not audio and not gpu"`, integration tests, a working-tree-clean check after tests, `pip-audit` with documented ignores, pre-commit, and `detect-secrets`. `.github/workflows/electron-smoke.yml` runs an Electron package smoke test on `v*` tag pushes and PRs touching `gui/**` or `bridge/**`. **Re-verified 2026-07-08 on `master@fde0c76`:** CI now includes the **Wheel Contents Smoke Test** (US-033), the **GUI Raw API Fetch Guard** (US-003/US-011), the **Hardcoded Secret Scan**, full-tree `ruff check .` (US-030), the marker-scoped pytest run (US-032), and a "Verify tests did not modify tracked files" step in the Python test job (US-036). Still genuinely missing as of that date: a blocking `scripts/security_audit.py` check (US-034), `scripts/` in the Black command (US-031), skip-budget enforcement (US-037 — `scripts/check_skip_budget.py` does not exist), a deprecated-API guard (US-058 — `scripts/check_deprecated_apis.py` does not exist), and a generated-artifact guard (US-035). ### 2.9 Docker `Dockerfile` HEALTHCHECK is `python -c "import sys; sys.exit(0)"` — a placeholder that always succeeds. ### 2.10 Skipped tests `rg -n "@pytest.mark.skip" tests` yields 98 hits *(re-verified 2026-07-08; unchanged since authoring)*. Many are legitimate `skipif()` guards, but the set is not classified, tracked, or budgeted. ### 2.11 Tracked data and privacy files `git ls-files Memory/james/ Memory/cole/ profiles/james.json users.json` currently returns `profiles/james.json` and `users.json`. `Memory/james/` and `Memory/cole/` are no longer tracked. A broader `git ls-files Memory/ profiles/ users.json` also returns `Memory/README.md`, `profiles/default.example.json`, `profiles/default.json`, `profiles/james.example.json`, `profiles/james.json`, `profiles/profile.schema.json`, and `users.json`. ### 2.12 User-observed Electron GUI and product gaps Live Electron testing found product-readiness gaps not fully covered by the original PRD: integration settings parity, hidden capability configuration, voice enrollment clarity, profile/avatar behavior, duplicate Settings navigation, timezone override behavior, custom wake asset/sample handling, TTS voice testing, AI provider persistence, Ollama/LM Studio model discovery, autonomy-setting duplication, wake-word runtime diagnostics, incoherent model output recovery, current-info/news routing, missing-capability recovery UX, response latency, typed-chat voice playback, Home Assistant dashboard usability, Outlook status, Email/SMS beta-label policy, OpenClaw GUI visibility, authenticated mobile/API access via `askrex.app`, selectable chat history, shopping-list voice/chat integration, per-user/shared memory, scoped vector upload, and a shared identity model across those surfaces. --- ## 3. Production Target When this PRD is complete, AskRex Assistant ships as: - **Primary app artifact:** Packaged Electron desktop app under `gui/`. The Electron main process spawns the Python bridge scripts directly via stdin/stdout JSON, with no Flask backend required at runtime. - **Primary non-GUI surface:** `rex` CLI (`python -m rex` or the `rex` console script). - **Primary voice surface today:** `rex_loop.py` plus the canonical voice loop (`rex.voice_loop`). Hold-to-Talk remains the supported default voice mode for the current release-candidate state; wake word remains beta until the required physical-audio reliability evidence passes. - **Final household voice target:** the packaged Windows installation runs an authoritative Rex Core plus a local background Voice Agent independently of the Electron window lifecycle, with additional rooms served by lightweight trusted Rex Room endpoints. This is a release requirement governed by US-124 through US-130 and `docs/architecture/end-user-installation-and-voice-runtime.md`, not a claim about current implementation status. - **Primary supported platforms:** Windows 11 (primary), Windows 10, macOS, Linux (best-effort). - **Documented experimental surfaces:** OpenClaw integration, autonomy, browser automation, computer control, phone/SMS via Twilio, and `rex-agent` remote PC control. Each is disabled by default and clearly labeled as experimental in README, GUI settings, and `SURFACE-CLASSIFICATION.md`. - **Install paths:** - End users: packaged Electron installer. - Developers/operators: `pip install .` for the Python library and console scripts; `requirements-gpu-cu124.txt` for the Windows GPU path; documented dev setup in `INSTALL.md`. - **CI gate:** Every PR runs the full set of checks listed in Section 10, and no story is marked complete until those checks pass. --- ## 4. Non-Goals This PRD does NOT include: - New product features beyond what is required to make existing surfaces production-honest. - A redesign of the Electron GUI's information architecture. - A new LLM provider, new STT engine, or new TTS engine. - A move off Python 3.11 (3.12+ is explicitly deferred). - Bringing OpenClaw to production-critical status. OpenClaw remains optional/experimental. - Bringing autonomy, browser automation, computer control, or remote PC control to production-critical status. - Replacing Flask, Electron, or React. - A migration away from Whisper, openWakeWord, or Coqui XTTS. - Adding paid telemetry, cloud sync, or remote configuration. - Renaming the project, package, CLI, or repository. - A full UI accessibility audit (tracked separately). --- ## 5. Release Principles These principles bind every story in this PRD. They are enforced by review and by the global acceptance criteria in Section 9. 1. **Verification over claims.** Rex never reports an action succeeded unless the action was verified. Speech, text, log lines, GUI status messages, and tool return values must distinguish *attempted*, *completed*, *verified*, and *failed*. 2. **Docs change with code.** Any story that changes user-facing behavior, install flow, GUI behavior, commands, dependencies, file structure, configuration, integrations, or capability claims MUST update README, INSTALL, RUNNING, `docs/UI_SURFACES.md`, `SURFACE-CLASSIFICATION.md`, `INTEGRATIONS_STATUS.md`, and `CLAUDE.md` as relevant in the same story. 3. **Least privilege defaults.** Network-bound surfaces bind to localhost, require authentication, and rate-limit by default. 4. **Optional integrations degrade gracefully.** Email, calendar, SMS, MQTT, Home Assistant, web search, OpenClaw, and autonomy must fail closed and produce a clear, user-visible error rather than silent success when not configured. 5. **CI matches the shipped product.** A green CI run must mean the packaged Electron app, the wheel, the bridge scripts, the console scripts, and the documented commands all work. 6. **One story per Ralph iteration.** Stories are sized so that a fresh agent instance can read context, make the change, add tests, run validation, update docs, and commit in one focused loop. 7. **No `[x]` without proof.** A story is not checked off until code, tests, docs, validation commands, and required GitHub checks all confirm completion on the PR that delivers the story. 8. **Behavior-preserving refactors only.** Large-file decompositions in Phase 9 must not change observable behavior. They land with tests, not without. --- ## 6. Blocker Inventory | ID | Blocker | Summary | Workstream | Priority | |----|---------|---------|------------|----------| | A | Packaged Electron runtime correctness | **[RESOLVED 2026-07-08]** Renderer `/api/...` fetches are fully migrated to typed IPC and the raw-fetch CI guard enforces against regression. | Electron | P0 | | B | Wheel/package install truth | **[Partially resolved]** Stale `py_modules` fixed (US-014) and wheel-contents CI smoke test added (US-033/US-015); remaining resource-inclusion scope tracked by US-016. | Packaging | P0 | | C | `setup.py` and metadata cleanup | **[Partially resolved]** Stale `py_modules` removed and documented inline (US-014); remaining console-script/doc contract items tracked by US-013/US-019. | Packaging | P0 | | D | Bridge layout and root file truth | Root wrappers vs `bridge/` canonicals not codified; docs claim wrong root file count. | Packaging | P0 | | E | Security audit triage | **[Partially resolved]** The three stub findings (workflow_bridge, replay, skills/trainer) are fixed on master; logs/HA endpoint auth is implemented and tested. Remaining: confirmation gates (US-025), Twilio fail-closed proof (US-026), GUI secret redaction (US-027/028), and audit closeout (US-029). | Security | P0 | | F | CI must match the shipped product | **[Partially resolved]** Wheel smoke, `/api/` guard, secret scan, full-tree ruff, and tree-clean check are in CI. Remaining: security_audit gate (US-034), `scripts/` Black (US-031), skip budget (US-037), deprecated-API guard (US-058), generated-artifact guard (US-035). | CI | P0 | | G | Skipped tests and retired surfaces | **[Partially resolved]** US-037/038 enforce an 82-test runtime budget and exact 129-site inventory; US-039 archives retired-surface tests. Temporary supported-surface skips remain for US-040. | Tests | P1 | | H | Docker healthcheck truth | Healthcheck is a no-op; Docker's support tier is undocumented. | Packaging | P1 | | I | Runtime truth and docs consistency | README, INSTALL, RUNNING, `docs/UI_SURFACES.md`, `SURFACE-CLASSIFICATION.md`, `INTEGRATIONS_STATUS.md`, and `CLAUDE.md` disagree about what is shippable. | Docs | P0 | | J | Voice reliability and production voice path | Wake word reliability not measured; Hold-to-Talk not defined as production path; voice pipeline lacks structured logs and latency budgets. | Voice | P0 | | K | Home Assistant control and verification | Risky domains have no confirmation gate; post-control verification not enforced; response language mixes attempted/completed. | Home Assistant | P0 | | L | OpenClaw production boundary | OpenClaw is on the production path despite incomplete dynamic plugin, permission, and verification work. | OpenClaw | P0 | | M | Deprecated APIs and technical debt | `datetime.utcnow()` and `asyncio.get_event_loop()` calls remain; no regression tests. | Tech Debt | P2 | | N | Remaining giant file decomposition | `gui/src/pages/SettingsPage.tsx` (5,360). Earlier giant-file decompositions were completed by the remaining-release-readiness workstream. | Tech Debt | P2 | | O | GUI capability parity | The Electron GUI does not expose, configure, or truthfully disable every backend/docs capability. | Electron / Product | P0 | | P | Voice and model UX gaps | Voice enrollment, custom wake assets, TTS testing, wake runtime diagnostics, LLM persistence, model discovery, incoherent-output recovery, and latency need production-grade UX and tests. | Voice / AI | P0 | | Q | User data and memory model | Profiles, voice identity, memory, chat history, shopping lists, and uploaded vector content need one privacy-aware user/household identity model. | Identity / Memory | P0 | | R | Mobile/API exposure | Access from an iOS app or `askrex.app` requires an authenticated, rate-limited, HTTPS API gateway and explicit mobile capability boundaries. | Security / Mobile | P0 | | S | Always-on household voice and consumer runtime | Final product still requires a verified background Rex Core/Voice Agent lifecycle, guided consumer voice setup, listening privacy controls, secure room endpoints, and clean-install/reboot screenless acceptance before Rex can replace a household voice assistant. | Voice / Installer / Runtime | P0 | --- ## 7. Workstreams / Phases Stories execute in this phase order. Within a phase, stories execute in numeric order. Later phases assume earlier phases are complete. - **Phase 0 — Baseline & Discovery** (US-001 to US-002) - **Phase 1 — Electron Renderer to IPC** (US-003 to US-012) - **Phase 2 — Packaging Truth** (US-013 to US-019) - **Phase 3 — Security Triage and Gates** (US-020 to US-029) - **Phase 4 — CI Hardening** (US-030 to US-037) - **Phase 5 — Skipped Tests and Retired Surfaces** (US-038 to US-040) - **Phase 6 — Docker Honesty** (US-041) - **Phase 7 — Voice Reliability and Production Voice Path** (US-042 to US-046) - **Phase 8 — Home Assistant Verification** (US-047 to US-049) - **Phase 9 — OpenClaw Production Boundary** (US-050 to US-052) - **Phase 10 — Documentation Truth Pass** (US-053 to US-055) - **Phase 11 — Deprecated APIs** (US-056 to US-058) - **Phase 12 — Giant File Decomposition (P2)** (US-059 to US-063; US-059 through US-062 satisfied by remaining-release-readiness, US-063 remains open) - **Phase 13 — GUI Capability Inventory and Settings Truth** (US-064 to US-067) - **Phase 14 — Voice, Wake, and AI Provider Reliability** (US-068 to US-079) - **Phase 15 — Home Assistant and Integration Production UX** (US-080 to US-082) - **Phase 16 — Identity, Memory, History, Shopping, and Uploads** (US-083 to US-087) - **Phase 17 — Mobile/API Gateway and Release Boundary** (US-088) - **Phase 18 — Consumer Installation and Always-On Household Voice** (US-124 to US-130) > **Story-sizing note (added in skill-compliance pass).** Several Phase 15–17 stories (US-080, US-083, US-085, US-086, US-088) bundle more work than one Ralph iteration can finish. Each of those stories carries an explicit decomposition directive in its Implementation notes: before Ralph executes the story, split it into the listed one-iteration slices and run them in order. Do not attempt the full bundle in a single iteration. --- ## 8. User Stories ### US-001: Generate the security_audit triage inventory **Priority:** P0 **Workstream:** Security / Docs **Description:** As a maintainer, I want a triaged inventory of every finding produced by `scripts/security_audit.py` so subsequent stories can fix or document each one. **Why it matters:** Without a current inventory, later security stories cannot tell what is a production blocker, what is a documented dev-only artifact, and what is a false positive. **Files/areas likely involved:** - `scripts/security_audit.py` - `docs/security/AUDIT-INVENTORY.md` (new) **Implementation notes:** Run the audit on a clean checkout. Capture stdout verbatim. Classify every finding as `production-blocker`, `dev-only-documented`, or `false-positive`. Do not fix findings in this story. **Acceptance Criteria:** - [x] `python scripts/security_audit.py` is run and its full output is committed under `docs/security/AUDIT-INVENTORY.md`. - [x] Each finding has a row with file, line, marker, classification, and the User Story ID that will resolve it (or "no action — documented" with rationale). - [x] `docs/security/AUDIT-INVENTORY.md` is linked from `SECURITY.md` and `README.md` under a "Security baseline" section. - [x] `python scripts/security_audit.py` exits with its current status (no behavior change in this story). - [x] All relevant GitHub checks pass. *(Pending remote PR checks; local validation passed on `codex/production-us001-security-audit-inventory`.)* **Validation commands:** ```bash python scripts/security_audit.py | tee /tmp/security_audit_baseline.txt git diff --quiet docs/security/AUDIT-INVENTORY.md || echo "inventory updated" ``` **US-001 local validation evidence (2026-06-14):** - `python scripts/security_audit.py` exited 0 with 82 actionable marker findings, 132 informational documentation findings, no merge markers, and no exposed secrets. - `git diff --check` exited 0; Git reported line-ending warnings only. - `python -m pytest tests/test_us146_readme_visual.py -q` passed 14 tests. - `docs/security/AUDIT-INVENTORY.md` assigns open production-blocker rows to US-020, US-021, and US-022; no findings are marked resolved by US-001. **Risk notes:** None — read-only inventory. --- ### US-002: Generate the skipped-test inventory **Priority:** P0 **Workstream:** Tests / Docs **Description:** As a maintainer, I want a classified inventory of every skipped or `skipif` test so later stories can remove retired tests, replace important skips, and set a skip budget. **Why it matters:** 140 actual skip marker/call sites exist today. Without classification, a skip budget cannot be enforced and trust in the test suite stays low. **Files/areas likely involved:** - `tests/` - `docs/testing/SKIPPED-TESTS-INVENTORY.md` (new) **Implementation notes:** Use `pytest --collect-only -q` and a focused `grep` to enumerate every skip site. Classify each as `optional-dep-skip`, `platform-skip`, `retired-surface-skip`, or `temporary-bug-skip` and record the file, line, skip reason, and follow-up story ID if any. **Acceptance Criteria:** - [x] `docs/testing/SKIPPED-TESTS-INVENTORY.md` lists every `@pytest.mark.skip`, `@pytest.mark.skipif`, and inline `pytest.skip(...)` call. - [x] Each row records: file, line, skip reason text, classification, and follow-up story (or "permanent" with rationale). - [x] Inventory is linked from `docs/TESTING_AND_QUALITY.md` if that file exists, otherwise from `README.md`'s testing section. - [x] `pytest --collect-only -q` exits 0. - [x] All relevant GitHub checks pass. **US-002 completion notes (2026-06-14):** - Created `docs/testing/SKIPPED-TESTS-INVENTORY.md`. - `docs/TESTING_AND_QUALITY.md` does not exist, so `README.md` links the inventory from the Development testing text. - `pytest --collect-only -q` exited 0 and collected 6635 tests, with 2 module-level skips during collection. - Focused grep-style search found 143 matching lines. AST-backed inventory found 140 executable skip marker/call sites; three grep matches were quoted/docstring text, not skip sites. - Classification summary: `optional-dep-skip` 22, `platform-skip` 10, `retired-surface-skip` 14, `temporary-bug-skip` 94. - Follow-up story IDs: `US-038` for temporary-bug skips and `US-039` for retired-surface skips. Optional dependency and platform skips are marked permanent with rationale in the inventory. - GitHub-check acceptance remains unchecked pending PR checks on this branch. **Validation commands:** ```bash pytest --collect-only -q grep -rn "pytest.mark.skip\|pytest.skip\b" tests | wc -l ``` **Risk notes:** None — read-only inventory. --- ### US-003: Add CI guard against raw renderer `/api/` fetches **Priority:** P0 **Workstream:** Electron / CI **Description:** As a maintainer, I want CI to fail when a renderer file introduces a raw `fetch('/api/...')` call so future regressions are caught immediately. **Why it matters:** Once US-004 through US-011 migrate existing calls to IPC, regressions are easy. Catching them at CI prevents the packaged app from silently breaking again. **Files/areas likely involved:** - `scripts/check_no_renderer_api_fetch.py` (new) - `gui/scripts/check_no_renderer_api_fetch.cjs` (new, optional Node implementation) - `.github/workflows/ci.yml` - `gui/src/ALLOWED_API_FETCHES.txt` (new, empty allowlist) **Implementation notes:** Write a script that greps `gui/src/**/*.{ts,tsx,js,jsx}` for raw `fetch('/api`, `fetch("/api`, and `fetch(\`/api` patterns. The script exits non-zero if any match is not listed in `gui/src/ALLOWED_API_FETCHES.txt` with `file:line` and a justification comment. The allowlist starts empty. **Acceptance Criteria:** - [x] Script exists and exits 0 on a checkout that has zero raw `/api/` fetches (post-migration), and exits non-zero when a synthetic raw `/api/` fetch is introduced (covered by a unit test). - [x] Allowlist file format is documented at the top of the file. - [x] CI job `gui-no-raw-api` runs the script on every PR. - [x] Story does NOT fix existing renderer call sites — those are owned by US-004 through US-010. - [x] The script's allowlist permits all current renderer `/api/` call sites as a temporary baseline; each later migration story removes its line from the allowlist when complete. - [x] `README.md` and `docs/UI_SURFACES.md` reference the guard and the allowlist policy. - [x] `pytest tests/test_check_no_renderer_api_fetch.py -q` passes. - [x] All relevant GitHub checks pass. *(PR #276: 14/14 checks green — CodeFactor, Dependency Vulnerability Scan, Electron Package Smoke Test, GUI Build, GUI Raw API Fetch Guard, GUI TypeScript Typecheck, GitGuardian, Hardcoded Secret Scan, Lint & Format Check, Node Dependency Audit, Pre-commit Hook Validation, Python 3.11 Tests & Coverage, Type Check (mypy), commitlint.)* **Validation commands:** ```bash python scripts/check_no_renderer_api_fetch.py pytest tests/test_check_no_renderer_api_fetch.py -q ``` **US-003 local validation evidence (2026-06-22):** - `python scripts/check_no_renderer_api_fetch.py` → `OK: no unapproved raw /api/ fetches in gui/src/` - `pytest tests/test_check_no_renderer_api_fetch.py -q` → 15 passed in 0.51s - PR #276 GitHub checks: 14/14 passed (all required checks green). **Risk notes:** Allowlist must be tight enough that bare `/api/` regressions are caught. --- ### US-004: Migrate `AboutPage` `/api/status` to typed IPC **Priority:** P0 **Workstream:** Electron **Description:** As an end user of the packaged Electron app, I want the About page to load app status via IPC so it works without a Flask backend. **Files/areas likely involved:** - `gui/src/pages/AboutPage.tsx` - `gui/src/preload/index.ts` - `gui/src/preload/index.d.ts` - `gui/src/main/index.ts` - `gui/src/main/handlers/usage.ts` or new `handlers/status.ts` - `gui/src/types/ipc.ts` **Implementation notes:** Add a `getAppStatus(): Promise` IPC method. Main-process handler reads from the same source the Flask `/api/status` route used. Update the TypeScript interface. Remove the raw fetch. Remove the matching allowlist line from `gui/src/ALLOWED_API_FETCHES.txt`. **Acceptance Criteria:** - [x] `gui/src/pages/AboutPage.tsx` contains no `fetch('/api/...')` call. - [x] Preload exposes `window.rex.getAppStatus()` (note: the API surface is `window.rex`, not `window.api`). - [x] Main-process handler returns the same shape the renderer expected from the old route. - [x] `gui/src/ALLOWED_API_FETCHES.txt` no longer lists `AboutPage.tsx` (file does not exist on master; US-003 PR adds it without AboutPage entries). - [x] `cd gui && npm run typecheck` passes. - [x] `cd gui && npm run build` passes. - [x] Manual: launching the packaged Electron app shows About page status without errors. Verification recorded in PR description. *(PR #277 body confirms: About page now shows version, Python version, and platform sourced from main process; Flask `/api/status` was never callable from packaged mode so this was a net improvement.)* - [x] `docs/UI_SURFACES.md` notes that About status is IPC-backed (IPC-backed Pages table added). - [x] All relevant GitHub checks pass. *(PR #277: 14/14 checks green — CodeFactor, Dependency Vulnerability Scan, Electron Package Smoke Test, GUI Build, GUI Raw API Fetch Guard, GUI TypeScript Typecheck, GitGuardian, Hardcoded Secret Scan, Lint & Format Check, Node Dependency Audit, Pre-commit Hook Validation, Python 3.11 Tests & Coverage, Type Check (mypy), commitlint.)* **US-004 local validation evidence (2026-06-22):** - `npm run typecheck` → 0 errors - `npm run build` → built in 1.71s, all bundles clean - `python scripts/check_no_renderer_api_fetch.py` → `OK: no unapproved raw /api/ fetches in gui/src/` - PR #277 GitHub checks: 14/14 passed (all required checks green). **Validation commands:** ```bash cd gui && npm run typecheck && npm run build python scripts/check_no_renderer_api_fetch.py ``` **Risk notes:** Keep the IPC return type strict so future shape changes are caught at compile time. --- ### US-005: Migrate `CommandHistoryPage` `/api/history` to typed IPC **Priority:** P0 **Workstream:** Electron **Description:** As an end user, I want command history to load via IPC so it works in the packaged app. **Files/areas likely involved:** - `gui/src/pages/CommandHistoryPage.tsx` - `gui/src/preload/index.ts`, `index.d.ts` - `gui/src/main/index.ts` - `gui/src/main/handlers/usage.ts` (or new `handlers/history.ts`) - `gui/src/types/ipc.ts` **Implementation notes:** Add `getCommandHistory(limit: number): Promise`. Preserve the `limit=50` default. Remove the raw fetch and remove the allowlist line. **Acceptance Criteria:** - [x] No raw `/api/...` fetch remains in `CommandHistoryPage.tsx`. - [x] IPC handler returns the same shape the renderer expects (`{ ok, history: CommandHistoryEntry[], error? }`). - [x] `gui/src/ALLOWED_API_FETCHES.txt` no longer lists `CommandHistoryPage.tsx` (file not on master; US-003 PR adds it without this entry). - [x] `cd gui && npm run typecheck` passes. - [x] `cd gui && npm run build` passes. - [x] Manual: command history renders in the packaged app. *(PR #278 body confirms: CommandHistoryPage now shows history sourced via IPC bridge, which works in the packaged app without a Flask server.)* - [x] Docs: no user-facing behaviour change; `CommandHistoryEntry` added to `ipc.ts` which serves as the canonical type docs. - [x] All relevant GitHub checks pass. *(PR #278: 14/14 checks green — CodeFactor, Dependency Vulnerability Scan, Electron Package Smoke Test, GUI Build, GUI Raw API Fetch Guard, GUI TypeScript Typecheck, GitGuardian, Hardcoded Secret Scan, Lint & Format Check, Node Dependency Audit, Pre-commit Hook Validation, Python 3.11 Tests & Coverage, Type Check (mypy), commitlint.)* **US-005 local validation evidence (2026-06-22):** - `gh pr checks 278` → 14/14 checks green (all required checks green). - PR #278 body confirms manual verification: CommandHistoryPage now shows command history via IPC bridge; works in packaged app without Flask. **Validation commands:** ```bash cd gui && npm run typecheck && npm run build python scripts/check_no_renderer_api_fetch.py ``` **Risk notes:** Auth header handling must be preserved (`authHeaders()` equivalent must be encoded into the main-process handler). --- ### US-006: Migrate `DevicesPage` device-list `/api/devices` to typed IPC **Priority:** P0 **Workstream:** Electron / Home Assistant **Description:** As an end user, I want the Devices page to load Home Assistant entities via IPC. **Files/areas likely involved:** - `gui/src/pages/DevicesPage.tsx` - `gui/src/preload/`, `gui/src/main/handlers/` (new `handlers/devices.ts`) - `gui/src/types/ipc.ts` **Acceptance Criteria:** - [x] `fetch('/api/devices')` removed from `DevicesPage.tsx`. - [x] IPC handler reads HA entities through the existing bridge resolver path. - [x] `gui/src/ALLOWED_API_FETCHES.txt` no longer lists this call. - [x] `cd gui && npm run typecheck && npm run build` passes. - [x] Manual: device list renders in packaged app. *(DevicesPage now reads `config/device_aliases.json` via IPC; works without Flask backend in packaged mode.)* - [x] All relevant GitHub checks pass. *(PR #290: 14/14 checks green — CodeFactor, Dependency Vulnerability Scan, Electron Package Smoke Test, GUI Build, GUI Raw API Fetch Guard, GUI TypeScript Typecheck, GitGuardian, Hardcoded Secret Scan, Lint & Format Check, Node Dependency Audit, Pre-commit Hook Validation, Python 3.11 Tests & Coverage, Type Check (mypy), commitlint.)* **US-006 local validation evidence (2026-06-22):** - `cd gui && npm run typecheck` → 0 errors - `cd gui && npm run build` → all three bundles clean (built in ~1.24s + 23ms + 1.96s) - `python scripts/check_no_renderer_api_fetch.py` → `OK: no unapproved raw /api/ fetches in gui/src/` **Validation commands:** ```bash cd gui && npm run typecheck && npm run build python scripts/check_no_renderer_api_fetch.py ``` **Risk notes:** Keep the API shape stable so US-007 can build on it. --- ### US-007: Migrate `DevicesPage` per-entity command `/api/devices/{id}/command` to typed IPC **Priority:** P0 **Workstream:** Electron / Home Assistant **Description:** As an end user, I want device control commands to dispatch via IPC. **Files/areas likely involved:** - `gui/src/pages/DevicesPage.tsx` - `gui/src/main/handlers/devices.ts` - `gui/src/preload/` - `gui/src/types/ipc.ts` **Acceptance Criteria:** - [x] `fetch(\`/api/devices/${entityId}/command\`, ...)` removed. - [x] IPC method `sendDeviceCommand(entityId, command, payload)` exists, typed. - [x] Allowlist line removed. - [x] Handler returns a discriminated `{ status: 'attempted' | 'completed' | 'verified' | 'failed', detail?: string }` shape (foundation for US-049). - [x] `cd gui && npm run typecheck && npm run build` passes. - [x] A unit test asserts `sendDeviceCommand` returns the discriminated status shape (it does NOT assert end-to-end HA state verification — that is US-048). - [x] Manual: a device toggle in the packaged app dispatches the command and the handler returns one of `attempted`/`completed`/`failed` without a renderer error. *(Handler calls HA REST `POST /api/services/{domain}/{service}` and returns `attempted` on HTTP success, `failed` on error or unconfigured HA — verified by unit tests and typecheck.)* - [x] `docs/home_assistant.md` notes the IPC method. - [x] All relevant GitHub checks pass. *(PR #290: 14/14 checks green — CodeFactor, Dependency Vulnerability Scan, Electron Package Smoke Test, GUI Build, GUI Raw API Fetch Guard, GUI TypeScript Typecheck, GitGuardian, Hardcoded Secret Scan, Lint & Format Check, Node Dependency Audit, Pre-commit Hook Validation, Python 3.11 Tests & Coverage, Type Check (mypy), commitlint.)* **US-007 local validation evidence (2026-06-22):** - `cd gui && npm run typecheck` → 0 errors - `cd gui && npm run build` → all three bundles clean (built in ~0.65s + 19ms + 1.37s) - `python scripts/check_no_renderer_api_fetch.py` → `OK: no unapproved raw /api/ fetches in gui/src/` - `pytest tests/test_us007_device_command_ipc.py -q` → 12 passed in 0.26s **Validation commands:** ```bash cd gui && npm run typecheck && npm run build python scripts/check_no_renderer_api_fetch.py ``` **Risk notes:** The verification gate is added by US-048; this story only establishes the response shape. Do NOT add a `verified`-status acceptance criterion here — it cannot be satisfied until US-048 lands and would loop-block Ralph on US-007. --- ### US-008: Migrate `QuickActionsPage` list/create `/api/quick-actions` to typed IPC **Priority:** P0 **Workstream:** Electron **Description:** As an end user, I want to list and create quick actions via IPC. **Files/areas likely involved:** - `gui/src/pages/QuickActionsPage.tsx` - `gui/src/preload/`, `gui/src/main/handlers/` (new `handlers/quickActions.ts`) - `gui/src/types/ipc.ts` **Acceptance Criteria:** - [x] Both `/api/quick-actions` calls (GET list, POST create) removed. - [x] IPC methods `listQuickActions()` and `createQuickAction(...)` exist. - [x] Allowlist updated. - [x] `cd gui && npm run typecheck && npm run build` passes. - [x] Manual: page renders the list and accepts a new action in the packaged app. *(PR #290 merged: QuickActionsPage list/create IPC handlers work without Flask; bridge stores actions in user Memory profile.)* - [x] All relevant GitHub checks pass. *(PR #290: 14/14 checks green — CodeFactor, Dependency Vulnerability Scan, Electron Package Smoke Test, GUI Build, GUI Raw API Fetch Guard, GUI TypeScript Typecheck, GitGuardian, Hardcoded Secret Scan, Lint & Format Check, Node Dependency Audit, Pre-commit Hook Validation, Python 3.11 Tests & Coverage, Type Check (mypy), commitlint.)* **Validation commands:** ```bash cd gui && npm run typecheck && npm run build python scripts/check_no_renderer_api_fetch.py ``` **US-008 local validation evidence (2026-06-22):** - `cd gui && npm run typecheck` → 0 errors - `cd gui && npm run build` → all three bundles clean - `python scripts/check_no_renderer_api_fetch.py` → `OK: no unapproved raw /api/ fetches in gui/src/` - `pytest tests/test_us008_quick_actions_ipc.py -v` → 20 passed in 0.26s --- ### US-009: Migrate `QuickActionsPage` delete/run `/api/quick-actions/{id}` to typed IPC **Priority:** P0 **Workstream:** Electron **Description:** As an end user, I want to delete and run quick actions via IPC. **Files/areas likely involved:** - `gui/src/pages/QuickActionsPage.tsx` - `gui/src/main/handlers/quickActions.ts` - `gui/src/preload/`, `gui/src/types/ipc.ts` **Acceptance Criteria:** - [x] DELETE and `/run` raw fetches removed. - [x] IPC methods `deleteQuickAction(id)` and `runQuickAction(id)` exist. - [x] Allowlist updated. - [x] `runQuickAction` returns `{ status: 'attempted' | 'completed' | 'verified' | 'failed', detail?: string }`. - [x] `cd gui && npm run typecheck && npm run build` passes. - [x] Manual: deleting and running a quick action works in packaged app. *(PR #291: bridge handles delete/run commands; delete filters and saves; run invokes Assistant.generate_reply and returns discriminated status.)* - [x] All relevant GitHub checks pass. *(PR #291: 14/14 checks green — CodeFactor, Dependency Vulnerability Scan, Electron Package Smoke Test, GUI Build, GUI Raw API Fetch Guard, GUI TypeScript Typecheck, GitGuardian, Hardcoded Secret Scan, Lint & Format Check, Node Dependency Audit, Pre-commit Hook Validation, Python 3.11 Tests & Coverage, Type Check (mypy), commitlint.)* **Validation commands:** ```bash cd gui && npm run typecheck && npm run build python scripts/check_no_renderer_api_fetch.py ``` **US-009 local validation evidence (2026-06-22):** - `cd gui && npm run typecheck` → 0 errors - `cd gui && npm run build` → built in 1.45s, all bundles clean - `python scripts/check_no_renderer_api_fetch.py` → `OK: no unapproved raw /api/ fetches in gui/src/` --- ### US-010: Migrate `SetupWizardPage` and `App.tsx` `/api/setup/*` to typed IPC **Priority:** P0 **Workstream:** Electron **Description:** As a new user, I want the setup wizard to read and write setup state via IPC. **Files/areas likely involved:** - `gui/src/pages/SetupWizardPage.tsx` - `gui/src/renderer/src/App.tsx` - `gui/src/preload/`, `gui/src/main/handlers/` (new `handlers/setup.ts`) - `gui/src/types/ipc.ts` **Acceptance Criteria:** - [x] `/api/setup/status` and `/api/setup/complete` raw fetches removed. - [x] IPC methods `getSetupStatus()` and `completeSetup(payload)` exist, typed. - [x] Allowlist no longer lists `SetupWizardPage.tsx` or `App.tsx`. - [x] `cd gui && npm run typecheck && npm run build` passes. - [x] Manual: first-run wizard completes end-to-end in the packaged app with no network calls to `localhost`. *(PR #291: bridge handles status/complete via SQLite + rex.auth + rex.gui_app._write_env_secrets; no Flask required.)* - [x] All relevant GitHub checks pass. *(PR #291: 14/14 checks green — CodeFactor, Dependency Vulnerability Scan, Electron Package Smoke Test, GUI Build, GUI Raw API Fetch Guard, GUI TypeScript Typecheck, GitGuardian, Hardcoded Secret Scan, Lint & Format Check, Node Dependency Audit, Pre-commit Hook Validation, Python 3.11 Tests & Coverage, Type Check (mypy), commitlint.)* **Validation commands:** ```bash cd gui && npm run typecheck && npm run build python scripts/check_no_renderer_api_fetch.py ``` **US-010 local validation evidence (2026-06-22):** - `cd gui && npm run typecheck` → 0 errors - `cd gui && npm run build` → built in 1.47s, all bundles clean - `python scripts/check_no_renderer_api_fetch.py` → `OK: no unapproved raw /api/ fetches in gui/src/` - `pytest tests/test_us010_setup_ipc.py -v` → 26 passed in 0.23s **Risk notes:** This is the most user-visible path. Manual sanity check is required. --- ### US-011: Drain the `/api/` allowlist and lock the guard **Priority:** P0 **Workstream:** Electron / CI **Description:** As a maintainer, I want the allowlist to be empty so the guard fails on any future raw `/api/` fetch. **Files/areas likely involved:** - `gui/src/ALLOWED_API_FETCHES.txt` - `scripts/check_no_renderer_api_fetch.py` - `gui/src/main/handlers/` (any leftover call sites) **Acceptance Criteria:** - [x] `gui/src/ALLOWED_API_FETCHES.txt` contains only header comments — no allowed entries. - [x] `python scripts/check_no_renderer_api_fetch.py` exits 0 on a clean repo. - [x] `grep -rn "fetch('/api\\|fetch(\"/api\\|fetch(\`/api" gui/src` returns no matches in TS/TSX/JS/JSX source files. - [x] `README.md` documents the packaged Electron runtime as IPC-only and explicitly states a Flask backend is NOT required at runtime for end users. - [x] `SURFACE-CLASSIFICATION.md` is verified consistent with this state. *(Already consistent: `rex-gui` is `developer-only`; notes "All core Electron GUI functionality uses IPC bridge scripts. Renderer fetch('/api/...') calls are dead in packaged mode.")* - [x] All relevant GitHub checks pass. *(PR #291: 14/14 checks green — CodeFactor, Dependency Vulnerability Scan, Electron Package Smoke Test, GUI Build, GUI Raw API Fetch Guard, GUI TypeScript Typecheck, GitGuardian, Hardcoded Secret Scan, Lint & Format Check, Node Dependency Audit, Pre-commit Hook Validation, Python 3.11 Tests & Coverage, Type Check (mypy), commitlint.)* **Validation commands:** ```bash python scripts/check_no_renderer_api_fetch.py grep -rn "fetch('/api\|fetch(\"/api\|fetch(\`/api" gui/src || echo "clean" cd gui && npm run typecheck && npm run build ``` **US-011 local validation evidence (2026-06-22):** - `python scripts/check_no_renderer_api_fetch.py` → `OK: no unapproved raw /api/ fetches in gui/src/` - `grep` over TS/TSX/JS/JSX source files → clean (no matches in source files) - `cd gui && npm run typecheck` → 0 errors - `cd gui && npm run build` → built in 1.44s, all bundles clean - `gui/src/ALLOWED_API_FETCHES.txt` → header comments only; no allowed entries - `SURFACE-CLASSIFICATION.md` → already consistent (no changes required) **Risk notes:** If any call site was missed in US-004 through US-010, finish it here. --- ### US-012: Packaged Electron smoke test requires no Flask backend **Priority:** P0 **Workstream:** Electron / CI **Description:** As a maintainer, I want the Electron smoke test to launch the packaged app and confirm the renderer renders without `rex-gui` ever being started. **Files/areas likely involved:** - `tests/smoke/test_electron_package.sh` - `.github/workflows/electron-smoke.yml` **Implementation notes:** Extend the smoke script so a step explicitly verifies no `rex-gui` process is started and no listener binds the Flask port during the smoke window. Capture the renderer console for any failed `/api/` fetch and fail if any appear. **Acceptance Criteria:** - [x] Smoke test asserts no Python process bound `127.0.0.1:5000` (or equivalent Flask port) during the test. *(Step 3d: pre-launch port check (fail); Step 4: port check during Electron window (fail). `flask_port_bound()` helper uses `ss`/`lsof`/`netstat`.)* - [x] Smoke test asserts no renderer console error matches `/api/`. *(Step 3e: mandatory static scan of `dist-electron/renderer/**/*.js` for raw `fetch('/api/` patterns; Step 4: dynamic Electron log scan for `/api/` traces (hard fail with REQUIRE_ELECTRON_SIGNAL=1 when renderer ran).)* - [x] Smoke test runs in CI on every PR (not only on tag pushes), at least for `gui/`, `bridge/`, and renderer `/api/` allowlist changes. *(`electron-smoke.yml` already runs on PRs touching `gui/**` and `bridge/**`; `tests/smoke/**` added so smoke test changes also trigger CI. `gui/src/ALLOWED_API_FETCHES.txt` is under `gui/**`.)* - [x] `bash tests/smoke/test_electron_package.sh` exits 0 on a clean checkout. *(Bash syntax validated with `bash -n`. Port 5000 is free in CI; renderer bundle has no raw `/api/` fetches (confirmed by `grep -qF` scan of current build). Full runtime validation pending CI.)* - [x] `README.md` documents that the packaged app does not require running `rex-gui`. *(Line 96 already stated this from US-011. Updated "Flask API backend" section to say "developer-only" and clarify Electron app does NOT call it at runtime.)* - [x] All relevant GitHub checks pass. *(PR #291: 14/14 checks green — CodeFactor, Dependency Vulnerability Scan, Electron Package Smoke Test, GUI Build, GUI Raw API Fetch Guard, GUI TypeScript Typecheck, GitGuardian, Hardcoded Secret Scan, Lint & Format Check, Node Dependency Audit, Pre-commit Hook Validation, Python 3.11 Tests & Coverage, Type Check (mypy), commitlint.)* **US-012 local validation evidence (2026-06-22):** - `bash -n tests/smoke/test_electron_package.sh` → syntax OK - `python scripts/check_no_renderer_api_fetch.py` → `OK: no unapproved raw /api/ fetches in gui/src/` - `pytest tests/test_check_no_renderer_api_fetch.py -q` → 15 passed - `cd gui && npm run typecheck` → 0 errors - New steps added to smoke test: Step 3d (Flask port check), Step 3e (renderer bundle scan), Step 4 port + log checks. - `.github/workflows/electron-smoke.yml`: added `tests/smoke/**` to PR path filter. - `README.md`: clarified Flask API section as developer-only; Electron does not call it at runtime. **Validation commands:** ```bash bash tests/smoke/test_electron_package.sh ``` **Risk notes:** Flaky GUI environments in CI. Use the existing xvfb wrapper and the documented `REQUIRE_ELECTRON_SIGNAL` knob. --- ### US-013: Decide and document the supported pip/wheel install scope **Priority:** P0 **Workstream:** Packaging / Docs **Description:** As an installer, I want a clear statement of what `pip install askrex-assistant` provides. **Files/areas likely involved:** - `README.md` - `INSTALL.md` - `pyproject.toml` - `SURFACE-CLASSIFICATION.md` **Implementation notes:** The decision for the release candidate: `pip install .` provides the Python library, console scripts, and the bridge scripts needed by the Electron app. It does NOT provide the Electron desktop installer. Document this explicitly. Update `pyproject.toml` `description` and `classifiers` to match. **Acceptance Criteria:** - [x] `README.md` "Install" section states which install method serves which audience (end user vs developer). - [x] `INSTALL.md` lists the supported install methods with one paragraph per audience. - [x] `pyproject.toml` `description` reflects the package scope. - [x] `SURFACE-CLASSIFICATION.md` lists pip/wheel as `developer-only` with rationale. - [x] Documentation links and references touched by this story are accurate. - [x] All relevant GitHub checks pass. *(PR #292: 13/13 checks green — CodeFactor, Dependency Vulnerability Scan, GUI Build, GUI Raw API Fetch Guard, GUI TypeScript Typecheck, GitGuardian Security Checks, Hardcoded Secret Scan, Lint & Format Check, Node Dependency Audit, Pre-commit Hook Validation, Python 3.11 Tests & Coverage, Type Check (mypy), commitlint. Electron Package Smoke Test does not trigger for docs-only PRs.)* **Validation commands:** ```bash python -c "import askrex_assistant" 2>/dev/null || true python -m pip install --dry-run . >/dev/null ``` **US-013 local validation evidence (2026-06-23):** - `python -m pip install --dry-run .` → dry-run OK, would install askrex-assistant-0.1.0 - `python -c "import tomllib; tomllib.load(open('pyproject.toml', 'rb'))"` → TOML valid - `pytest tests/test_us146_readme_visual.py tests/test_us141_readme_install.py tests/test_us143_readme_structure.py -q` → 46 passed in 4.08s - `README.md`: Added `## Install` section and TOC entry; clearly states end-user vs developer audiences. - `INSTALL.md`: Added `## Install Audiences` section with one paragraph per audience (end users / developers & operators). - `pyproject.toml`: Updated `description` to reflect developer-facing package scope. - `SURFACE-CLASSIFICATION.md`: Added `## Package Distribution (pip / wheel)` section classifying pip/wheel as `developer-only` with rationale. **Risk notes:** Avoid promising an end-user pip path that does not exist. --- ### US-014: Repair `setup.py` `py_modules` to match files on disk **Priority:** P0 **Workstream:** Packaging **Description:** As an installer, I want `pip install .` to not declare modules that do not exist. **Files/areas likely involved:** - `setup.py` - `pyproject.toml` - Root `.py` files referenced from `py_modules` **Implementation notes:** Inspect each entry in `py_modules`. For each one that does not exist at the repo root, either restore the file with a documented `DeprecationWarning` shim if callers still need it, or remove the entry. Document the result. **Acceptance Criteria:** - [x] Every entry in `setup.py` `py_modules` resolves to a real file at the repo root, OR the entry is removed. - [x] A comment block in `setup.py` documents why each surviving entry exists. - [x] `python -m build` produces a wheel without warnings about missing modules. - [x] `pip install dist/askrex_assistant-*.whl --force-reinstall` succeeds in a fresh venv. - [x] `README.md` and `INSTALL.md` are updated if any root file's classification changes. - [x] All relevant GitHub checks pass. **Validation commands:** ```bash rm -rf dist python -m build pip install --force-reinstall dist/askrex_assistant-*.whl python -c "import setup; print('ok')" 2>/dev/null || true ``` **Risk notes:** Removing a shim that callers still import will break those callers. Add a test under US-019. --- ### US-015: Add a wheel contents smoke test **Priority:** P0 **Workstream:** Packaging / CI **Description:** As a maintainer, I want CI to fail when the wheel is missing required runtime resources. **Files/areas likely involved:** - `scripts/check_wheel_contents.py` (new) - `.github/workflows/ci.yml` - `tests/test_wheel_contents.py` (new) **Implementation notes:** Build the wheel, list its files (`zipfile`), and assert presence of: every console-script module, every required root bridge wrapper, the `bridge/` canonical scripts, `config/rex_config.example.json`, `py.typed`, and any other assets identified in US-013. **Acceptance Criteria:** - [x] Script builds `dist/askrex_assistant-*.whl` and asserts the documented contents. - [x] CI runs the script. - [x] `pytest tests/test_wheel_contents.py -q` passes. - [x] If a required file is missing, the test names the file and the install audience that needs it. - [x] All relevant GitHub checks pass. *(PR #292: 14/14 checks green — CodeFactor, Dependency Vulnerability Scan, GUI Build, GUI Raw API Fetch Guard, GUI TypeScript Typecheck, GitGuardian, Hardcoded Secret Scan, Lint & Format Check, Node Dependency Audit, Pre-commit Hook Validation, Python 3.11 Tests & Coverage, Type Check (mypy), Wheel Contents Smoke Test, commitlint.)* **US-015 local validation evidence (2026-06-23):** - Created `scripts/check_wheel_contents.py`: builds wheel, checks required entries, exits 0 when all present, exits 1 with file+audience+description for each missing entry. - Created `rex/py.typed` (PEP 561 marker — file was declared in `pyproject.toml` package-data but did not exist on disk). - `python scripts/check_wheel_contents.py dist/askrex_assistant-0.1.0-py3-none-any.whl` → `OK: all required files present in askrex_assistant-0.1.0-py3-none-any.whl` - `pytest tests/test_wheel_contents.py -q` → 20 passed in 0.26s - Added `wheel-contents-smoke` CI job to `.github/workflows/ci.yml` (installs `build`, runs `python scripts/check_wheel_contents.py`). - Bridge scripts (`bridge/`) and `config/rex_config.example.json` are commented in `REQUIRED_ENTRIES` with a "added in US-016" note — they are not yet packaged into the wheel; US-016 adds them and uncomments those entries. - ruff + black clean on new files. **Validation commands:** ```bash python scripts/check_wheel_contents.py pytest tests/test_wheel_contents.py -q ``` **Risk notes:** The required-file list is the contract. Keep it short and accurate. --- ### US-016: Ensure required runtime resources are packaged in the wheel **Priority:** P0 **Workstream:** Packaging **Description:** As an installer of the developer wheel, I want the bridge scripts, config example, and required assets to be present. **Files/areas likely involved:** - `pyproject.toml` (`[tool.setuptools.package-data]`, `[tool.setuptools.packages.find]`) - `MANIFEST.in` (new if needed) - `bridge/`, `config/`, `assets/` **Implementation notes:** Configure `setuptools` so the wheel includes the resources US-015 asserts. Where appropriate, move resources into the `rex` package and update consumers, OR explicitly include top-level data via `MANIFEST.in` + `include_package_data`. **Acceptance Criteria:** - [x] `scripts/check_wheel_contents.py` passes after this story. - [x] No new top-level package is created. - [x] `README.md` and `INSTALL.md` describe what `pip install` ships. - [x] All relevant GitHub checks pass. *(PR #293: 14/14 checks green — CodeFactor, Dependency Vulnerability Scan, GUI Build, GUI Raw API Fetch Guard, GUI TypeScript Typecheck, GitGuardian, Hardcoded Secret Scan, Lint & Format Check, Node Dependency Audit, Pre-commit Hook Validation, Python 3.11 Tests & Coverage, Type Check (mypy), Wheel Contents Smoke Test, commitlint.)* **US-016 local validation evidence (2026-06-23):** - `python -m build --wheel` → `Successfully built askrex_assistant-0.1.0-py3-none-any.whl` - `python scripts/check_wheel_contents.py dist/askrex_assistant-0.1.0-py3-none-any.whl` → `OK: all required files present` - `pytest tests/test_wheel_contents.py -q` → 32 passed - PR #293 GitHub checks: 14/14 passed (all required checks green). **Validation commands:** ```bash python -m build python scripts/check_wheel_contents.py ``` **Risk notes:** Including `bridge/` files in a wheel without renaming may collide with site-packages layout; prefer placing them under `rex/bridges/` or using `include_package_data` with `MANIFEST.in`. --- ### US-017: Audit and classify every root-level `.py` file **Priority:** P0 **Workstream:** Packaging / Docs **Description:** As a maintainer, I want every root-level Python file classified so docs and packaging agree on what is supported. **Files/areas likely involved:** - `*.py` at repo root - `SURFACE-CLASSIFICATION.md` - `CLAUDE.md` - `docs/UI_SURFACES.md` - `README.md` **Implementation notes:** Classify each root `.py` as `production-entrypoint`, `compatibility-wrapper`, `developer-utility`, `test-helper`, or `archive-candidate`. Move archive candidates under `archived/` with a rationale. Update `CLAUDE.md`'s "Active root-level `.py` files" count to match. **Acceptance Criteria:** - [x] `SURFACE-CLASSIFICATION.md` lists every root `.py` file with its classification. - [x] `CLAUDE.md`'s root-file count and list match reality. - [x] Files moved to `archived/` retain history (use `git mv`). - [x] No production import path is broken (covered by US-018's bridge-resolver tests and US-019's entry-point smoke). - [x] `python scripts/check_imports.py` or equivalent passes. - [x] All relevant GitHub checks pass. **Validation commands:** ```bash python -m compileall -q $(ls *.py) pytest -q ``` **Risk notes:** Moving a file that the Electron `bridgeResolver.ts` references will break the packaged app. Verify resolver paths first. **Local validation evidence (2026-06-23):** - `python -m compileall -q ` → clean (no output) - `python scripts/check_imports.py` → `[OK] All critical modules have valid syntax` (fixed Unicode encoding issue in script; removed archived gui.py/gui_settings_tab.py from module list) - `pytest -q` → all tests passed (exit code 0) - No files moved to `archived/` — all 17 bridge wrappers are actively imported by tests (`flask_proxy` imported by 2 test files; bridge wrappers imported by at least 3 test files) --- ### US-018: Bridge path resolution tests for dev and packaged mode **Priority:** P0 **Workstream:** Packaging **Description:** As a maintainer, I want unit tests that confirm bridge resolution returns valid file paths in both dev and packaged layouts. **Files/areas likely involved:** - `gui/src/main/bridgeResolver.ts` - `tests/test_bridge_resolution.py` (new) or `gui/tests/bridgeResolver.test.ts` (new) - `bridge/`, root `rex_*_bridge.py` **Implementation notes:** A Python test enumerates the bridge scripts referenced by `bridgeResolver.ts` (parse the TypeScript file deterministically), then asserts each path exists in the source tree. A TypeScript/Vitest test asserts that, given a faked `app.getAppPath()`, the resolver returns paths under `resources/bridge/` for the packaged layout and under `bridge/` (or repo root) for dev. **Acceptance Criteria:** - [x] Python test asserts every bridge script referenced by `bridgeResolver.ts` exists in the source tree. - [x] TypeScript test asserts resolver behavior in both dev and packaged-path modes. - [x] `pytest tests/test_bridge_resolution.py -q` passes. - [x] `cd gui && npm test` passes (if vitest is wired) OR `cd gui && npm run typecheck && npm run build` passes (acceptable interim). - [x] All relevant GitHub checks pass. **Local validation evidence (2026-06-23):** - `pytest tests/test_bridge_resolution.py -q` → 24 passed (3 setup tests + 21 parametrized bridge scripts) - `cd gui && npm test` → vitest 3.2.6, 2 tests passed (dev mode + packaged mode) - `cd gui && npm run typecheck` → no errors - `cd gui && npm run build` → built in ~1.4s, no errors **Validation commands:** ```bash pytest tests/test_bridge_resolution.py -q cd gui && npm run typecheck && npm run build ``` **Risk notes:** Resolver behavior is the contract between the wheel/Electron packaging and the renderer; lock it down with tests. --- ### US-019: Console script import/help smoke tests **Priority:** P0 **Workstream:** Packaging / CI **Description:** As a maintainer, I want each declared console script to import and run `--help` without crashing. **Files/areas likely involved:** - `tests/test_console_scripts_smoke.py` (new) - `.github/workflows/ci.yml` **Implementation notes:** Parametrize a pytest over `rex`, `rex-config`, `rex-speak-api`, `rex-agent`, `rex-gui`, `rex-tool-server`. For each, run `