From 1c47c84d94e6099647f005326a160c653a7ff09a Mon Sep 17 00:00:00 2001 From: TurtleWolfe Date: Sun, 26 Apr 2026 22:50:47 +0000 Subject: [PATCH] docs(stability): record post-#44 state, add STABILITY-TRACKING work order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit STATUS.md changes: - Snapshot date 2026-04-25 → 2026-04-26. - 042 Payment RLS moves [!] → [x] (closed via #44). - Stability table re-verified against current code: * ConversationView regression — RESOLVED. createClient() in conversation hooks is now wrapped in useMemo; comments name the prior revert. * GDPR Firefox focus — RESOLVED. PaymentConsentModal uses requestAnimationFrame; comment names the prior revert. * ProtectedRoute auth-race — still latent in admin/layout.tsx; tracked #51. * Offline-queue cross-tab tx — still open in base-queue.ts; tracked #52. - Family-B activation list updated: RLS step removed, replaced with #53 (the test-skip index that absorbs the "84 test.skip" tracking). - Summary count adjusted: shipped 17 → 18, backend-only 3 → 2. New: docs/STABILITY-TRACKING.md — cross-issue work order grouped by Family A/B/C/D with rationale for ordering. STATUS.md describes WHAT; this doc describes WHICH ORDER and WHY. Issues filed in this round (parallel to this commit): - #51 — admin/layout.tsx stale-closure latent risk (P1) - #52 — base-queue.ts process+complete not in single tx (P1) - #53 — tests/e2e/payment/ 84 test.skip index by blocker (P2) Co-Authored-By: Claude Opus 4.7 (1M context) --- STATUS.md | 29 +++++----- docs/STABILITY-TRACKING.md | 110 +++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 14 deletions(-) create mode 100644 docs/STABILITY-TRACKING.md diff --git a/STATUS.md b/STATUS.md index 6019b9e9..85a2c4ea 100644 --- a/STATUS.md +++ b/STATUS.md @@ -1,9 +1,10 @@ # ScriptHammer Status -**Snapshot**: 2026-04-25 · **Version**: v0.0.1 · **Stability**: Beta — post-remake stabilization in progress +**Snapshot**: 2026-04-26 · **Version**: v0.0.1 · **Stability**: Beta — post-remake stabilization in progress This is the single screen-scan view of "what's planned, what's shipped, what's broken." For the deeper per-feature audit see [`docs/prp-docs/PRP-STATUS.md`](docs/prp-docs/PRP-STATUS.md). +For the cross-issue work-order see [`docs/STABILITY-TRACKING.md`](docs/STABILITY-TRACKING.md). Raw machine-readable data: [`scripts/audit/truth-table.json`](scripts/audit/truth-table.json). --- @@ -70,7 +71,7 @@ Raw machine-readable data: [`scripts/audit/truth-table.json`](scripts/audit/trut - [~] **039 Payment Offline Queue** — logic built; status indicator UI + `/payment/history` missing (#4) - [!] **040 Payment Retry UI** — retry logic in service; `/payment/result` page + retry surface missing - [~] **041 PayPal Subscriptions** — backend ready; `/payment/subscriptions` page + grace-period banner + duplicate prevention + 4 edge functions missing (#5) -- [!] **042 Payment RLS Policies** — 20+ policies written; **25 E2E test stubs awaiting un-skip + verify** +- [x] **042 Payment RLS Policies** — 20+ policies verified by `pnpm test:rls` (55/55 across 5 files, both local + cloud) — #44 closed 2026-04-26 ## Tier 6 — Polish (4 features) @@ -100,10 +101,10 @@ Raw machine-readable data: [`scripts/audit/truth-table.json`](scripts/audit/trut | Status | Count | Features | | --------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------- | -| Shipped `[x]` | 17 | 000-brand, 000-landing, 000-rls, 002, 003, 007, 008, 009, 017, 018, 022, 025, 031, 032, 034, 036, 046 | +| Shipped `[x]` | 18 | 000-brand, 000-landing, 000-rls, 002, 003, 007, 008, 009, 017, 018, 022, 025, 031, 032, 034, 036, 042, 046 | | Mostly Shipped (config gap) | 6 | 004, 006, 011, 019, 024, 030 | | Partial `[~]` | 19 | Most active backlog lives here (010, 012, 015, 020, 021, 023, 026, 027, 029, 033, 035, 037, 038, 039, 041, 043, 045, plus 001 and 005) | -| Backend Only `[!]` | 3 | 014, 040, 042 | +| Backend Only `[!]` | 2 | 014, 040 | | Not Started `[ ]` | 4 | 013, 016, 028, 044 | | **Total** | **49** | (3 features — 000-brand, 000-landing, 046-admin — lack `spec.md` and are tracked via `*_feature.md` only) | @@ -117,27 +118,27 @@ If we want a stable v0.1.0, three families of work close it: The `feat/repo-overhaul-merge` of 2026-03-04 introduced patterns that have caused **18+ reverts in 3 months** and a 5x increase in fix-rate. The same shapes repeat in code that wasn't reverted yet: -| Hotspot | Status | Evidence | -| --------------------------------- | ------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | -| **ProtectedRoute auth race** | Open | 3 reverts: 6b4c13a, 2c97e67, 259b38d. **Now duplicated in `src/app/admin/layout.tsx`** (regression re-introduced). | -| **ConversationView regression** | Open | revert adae629. Root cause: `createClient()` at hook top level in `useConversationRealtime.ts:42` and `useTypingIndicator.ts:31`. | -| **GDPR consent Firefox** | Resolved by revert; same shape in `PaymentConsentModal.tsx:46-57` (focus-after-showModal timing). | -| **Offline-queue IndexedDB drift** | Resolved (40f0d0e) but `base-queue.ts:216-242` lacks transactions; cross-tab sync still racey. | -| **E2E flake mitigation** | Ongoing | 9 rounds. Cause: stale closures, unstable hook refs, hydration timing. | +| Hotspot | Status | Evidence | +| --------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **ProtectedRoute auth race** | Open | 3 reverts: 6b4c13a, 2c97e67, 259b38d. Now mitigated in `src/app/admin/layout.tsx` via a `cancelled` flag, but stale-closure on `user` inside the async still latent. Tracked in [#51](https://github.com/TortoiseWolfe/ScriptHammer/issues/51). | +| **ConversationView regression** | Resolved | `createClient()` calls in `useConversationRealtime.ts:46` and `useTypingIndicator.ts:32` are now wrapped in `useMemo(() => createClient(), [])`. Comment in code names the prior revert (adae629). | +| **GDPR consent Firefox** | Resolved | `PaymentConsentModal.tsx:46-59` defers `acceptButtonRef.focus()` via `requestAnimationFrame()` after `dialog.showModal()`. Comment names the prior revert (3e67772). | +| **Offline-queue IndexedDB drift** | Open | `base-queue.ts:214-247` does atomic claim via Dexie's implicit tx, but `processItem()` + completion update span tabs without a single transaction. Tracked in [#52](https://github.com/TortoiseWolfe/ScriptHammer/issues/52). | +| **E2E flake mitigation** | Ongoing | 9 rounds. Cause: stale closures, unstable hook refs, hydration timing. | The full code-review findings (35 high-confidence items) live in [`scripts/audit/code-review-findings.json`](scripts/audit/code-review-findings.json). The pattern is consistent: stale closures after async auth, unstabilized context providers, hooks creating new Supabase clients every render. ### B. Payment activation — small effort, big unlock -024/038/039/040/041/042 are ~75% built. To take them green: +024/038/039/040/041 are ~75% built. 042 RLS shipped (#44). To take the rest green: 1. Create Stripe sandbox + PayPal developer accounts (~30-60 min external setup) 2. Populate 6 keys in `.env` + Supabase Vault 3. Wire 4 missing routes (`/payment/dashboard`, `/payment/subscriptions`, `/payment/history`, `/payment/result`) 4. Build offline-queue UI affordances (status indicator, sync pill, retry button) -5. Un-skip 25 RLS test stubs and verify policies enforce what they claim +5. As each route lands, remove the corresponding skips from `tests/e2e/payment/` per [#53](https://github.com/TortoiseWolfe/ScriptHammer/issues/53) -GitHub issues #3, #4, #5 already track the bigger pieces. +GitHub issues #3, #4, #5, #43 track the route work; #53 is the test-skip index. ### C. Test coverage — known gaps diff --git a/docs/STABILITY-TRACKING.md b/docs/STABILITY-TRACKING.md new file mode 100644 index 00000000..fa6933a4 --- /dev/null +++ b/docs/STABILITY-TRACKING.md @@ -0,0 +1,110 @@ +# Stability Tracking — post-#44 work order + +**Updated**: 2026-04-26 · **Audit baseline**: 2026-04-25 (see [STATUS.md](../STATUS.md)) + +This document is the cross-issue work-order. STATUS.md describes _what_ the gaps are; this describes _which order_ to close them in and _why_. New issues land here first, then graduate into PRs. + +For raw issue lists: `gh issue list --label gap-audit --repo TortoiseWolfe/ScriptHammer` + +--- + +## How this is organized + +Work groups by **Family** (from STATUS.md "What Closes the v0.0.x → v0.1.0 Gap"). Within each family, issues run **highest leverage first** — fix a thing that unblocks 3+ other things before fixing a leaf-node thing. + +| Family | Theme | Why it goes first/last | +| ------ | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | +| **A** | Stability — fix the post-remake regression patterns | Every other family is more reliable once Family A lands. Bug-fix dollars compound. | +| **B** | Payment activation — wire the missing routes that block 84 e2e tests | One-shot deliverables that move 18 features from `[~]` to `[x]`. | +| **C** | Test coverage — known untested LOC in production-critical paths | Defensive. Doesn't unblock features but prevents the next regression family. | +| **D** | Audit-trail / fixture follow-ups from #44 | Small, recently-discovered. Knocking these out keeps the audit-trail story coherent. | + +Priority labels (`priority:p0`/`p1`/`p2`/`p3`) are orthogonal to family. A P1 in Family A gets the same urgency as a P1 in Family B; the Family ordering only matters when picking from a tie. + +--- + +## Family A — Stability + +The `feat/repo-overhaul-merge` of 2026-03-04 introduced patterns that have caused 18+ reverts in 3 months. Two of the four originally-flagged hotspots have already been fixed (see "Resolved" below). Two remain: + +| Order | Issue | Severity | One-line | +| ----- | -------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| A1 | [#51](https://github.com/TortoiseWolfe/ScriptHammer/issues/51) | P1 | `admin/layout.tsx` async still has stale-closure on `user`; `cancelled` flag is partial. Land the regression test first, then hoist into a shared `useAuthGate`. | +| A2 | [#52](https://github.com/TortoiseWolfe/ScriptHammer/issues/52) | P1 | `base-queue.ts` claims atomically but `processItem`+complete spans tabs without a tx. Fix via watchdog reclaim + idempotency keys, not by chasing atomicity that can't exist for network calls. | + +**Resolved (no work needed):** + +- ConversationView regression — `useMemo(() => createClient(), [])` is in place at `useConversationRealtime.ts:46` and `useTypingIndicator.ts:32`, with comments naming the prior revert (adae629). +- GDPR Firefox focus timing — `requestAnimationFrame()` deferral is in place at `PaymentConsentModal.tsx:46-59`, with comment naming the prior revert (3e67772). + +**Why A1 before A2:** A1 is auth — every user touches it. A2 is the offline queue, which only wedges when the user is actually offline mid-action. Auth correctness rarely; queue correctness sometimes. + +--- + +## Family B — Payment activation + +20+ payment RLS policies are verified (#44, closed). The remaining work is route + UI: + +| Order | Issue | Severity | Unblocks | +| ----- | -------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| B1 | [#43](https://github.com/TortoiseWolfe/ScriptHammer/issues/43) | P2 | `/payment/result` page + retry surface. Smallest of the four routes. Unblocks ~5 skips in `03-failed-payment-retry.spec.ts` per [#53](https://github.com/TortoiseWolfe/ScriptHammer/issues/53). | +| B2 | [#3](https://github.com/TortoiseWolfe/ScriptHammer/issues/3) | P2 | `/payment/dashboard`. Unblocks ~6 skips in `01-stripe-onetime`, `06-realtime-dashboard`, `07-performance`. | +| B3 | [#4](https://github.com/TortoiseWolfe/ScriptHammer/issues/4) | P2 | `/payment/history` + offline-queue UI affordances. Unblocks ~12 skips in `05-offline-queue` (whole file). Depends on A2 being landed cleanly so the UI describes a correct state machine. | +| B4 | [#5](https://github.com/TortoiseWolfe/ScriptHammer/issues/5) | P2 | `/payment/subscriptions` + grace period + duplicate prevention + 4 edge functions. Largest of the four; unblocks ~10 skips. | +| B5 | [#53](https://github.com/TortoiseWolfe/ScriptHammer/issues/53) | P2 | The test-skip index. Closes incrementally as B1–B4 land. | + +**Why B1 first:** smallest, lowest-risk, highest information density. Lets you exercise the "ship a route + remove its skips + close part of #53" loop on a tight feedback cycle before doing the harder routes. + +**B3 depends on A2.** Don't wire offline-queue UI to a state machine that we know has a bug. + +--- + +## Family C — Test coverage + +Defensive only. Each item maps to a STATUS.md "Tier 7" feature. + +| Order | Issue | Severity | What | +| ----- | -------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------- | +| C1 | [#38](https://github.com/TortoiseWolfe/ScriptHammer/issues/38) | P2 | `src/lib/seo/technical.ts` (429 LOC, 0 tests) + 029 SEO Editorial Assistant import-bundle UX. | +| C2 | [#41](https://github.com/TortoiseWolfe/ScriptHammer/issues/41) | P3 | `message-service.ts` (1200+ LOC), `key-service.ts`, `group-key-service.ts`, `audit-logger.ts`. | +| C3 | (no issue yet) | P3 | Visual a11y for game components — STATUS.md feature 037. File when picked up. | + +**Why C1 before C2:** SEO is a single-file/single-purpose module — tests can be added in 1 day. Messaging is 4 services, one of which is the largest in the repo. C2 is a multi-day project and likely needs its own breakdown. + +--- + +## Family D — Audit-trail follow-ups (from #44) + +| Order | Issue | Severity | What | +| ----- | -------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | +| D1 | [#50](https://github.com/TortoiseWolfe/ScriptHammer/issues/50) | P2 | RLS test fixture `globalSetup` to scrub stale `*@scripthammer.test` users + orphan FKs. ~1-2 hours. | +| D2 | [#49](https://github.com/TortoiseWolfe/ScriptHammer/issues/49) | P2 | Add `sign_up` audit log emission to the existing `on_auth_user_created` trigger so `get_security_metrics()` reports a real `signups_this_month`. ~half-day. | + +**Why D1 before D2:** D1 fixes a wedge (RLS suite can't run on cloud after a killed prior run). D2 fixes a metric (admin dashboard underreports). Wedges before metrics. + +--- + +## Active branches + +| Branch | Purpose | Status | +| ------------------------- | ------------------------------------------------------- | ------------------------------ | +| `044/payment-rls-verify` | #44 — RLS test suite verification (55/55 local + cloud) | Pushed; awaiting merge to main | +| `chore/post-044-tracking` | This document + STATUS.md updates | In progress | + +--- + +## How to use this doc + +1. **Picking the next thing to work on:** scan top-down. The first non-`[done]` row in Family A wins. If A is empty, drop to B. If you're picking up something out of order, write a one-line note here explaining why. +2. **Filing a new issue:** check whether it fits an existing Family. If yes, add a row in the right place. If no, ask whether you've discovered a new Family or whether the issue belongs in a different doc. +3. **Closing an issue:** strike the row through (`~~~`) but leave it visible for one snapshot cycle so the work history is readable. Remove the next time STATUS.md is regenerated. +4. **Re-running the audit:** see the bottom of [STATUS.md](../STATUS.md). The truth-table (`scripts/audit/truth-table.json`) is the source of truth for spec-vs-code reality; this doc is the source of truth for _order_. + +--- + +## Conventions + +- Every gap-audit issue body links back to STATUS.md and any prior reverts by SHA. +- Stability hotspots cite file:line ranges, not paraphrases. +- Tracker issues (#53, this doc) get one row per blocker, not one row per skip — ten skips in one file under one cause is one item, not ten. +- "Resolved" entries stay visible for at least one snapshot so the next reader can see what was already done.