diff --git a/docs/IMPLEMENTATION_MASTERPLAN.md b/docs/IMPLEMENTATION_MASTERPLAN.md index fbb033987..3b5363116 100644 --- a/docs/IMPLEMENTATION_MASTERPLAN.md +++ b/docs/IMPLEMENTATION_MASTERPLAN.md @@ -1,6 +1,6 @@ # Taskdeck Implementation Masterplan -Last Updated: 2026-06-30 +Last Updated: 2026-07-02
Planning Horizon: the finite archive-pivot waves (Paper UI activation → easy local run → general quality → archive), then archival — _(historical: this was an open "Next 8 to 12 weeks" release horizon before the 2026-06-13 archive pivot)_ Companion Active Docs: @@ -54,6 +54,10 @@ Update this file at the end of each meaningful delivery cycle or when new work i Delivered in the latest cycle: +Security + a11y quality slices (2026-07-02, **2 PRs merged** — `#1263` (`#1241`), `#1265` (`#1218`); full review gate per PR — independent adversarial reviews, all-severity findings fixed or tracked, Gemini/Copilot bot rounds resolved (+Codex rounds on `#1263`), fresh green CI + aging): +- **Windows secrets-at-rest ACL:** `#1263` (`#1241`) locks `appsettings.local.json` (JWT secret + connector encryption key) to the current user — `RestrictFileToCurrentUser` (Unix `0600` / Windows protected owner-only DACL, dependency-free on net8.0) runs create→restrict→write in `PersistValue`, fail-closed (an unrestrictable file is never written; callers fall back in-memory), with startup forward remediation for pre-`#1241` installs and a locked-down `.corrupt-*` backup. Review rounds also hardened the **MCP launch paths**: both MCP modes now load the local config via the same hardened path as the web API (absolute exe-adjacent path — MCP clients launch stdio servers from arbitrary CWDs; corrupt-file quarantine; env-vars keep priority over the file). Seeded: `#1262` (CLI bootstrapper sibling), `#1264` (atomic create-with-ACL — in flight as `#1267`). +- **WCAG focus-ring contrast sweep:** `#1265` (`#1218`) resolves all 19 remaining `ring-primary/50` sites (0 left repo-wide): 13 rendered focus rings + the selected-label state ring lifted to the full-opacity treatment (`#1216` precedent) — from a marginal 3.0–3.5:1 to 8.4–10.1:1 on every adjacent surface across all shipped themes — and 5 compile-proven dead checkbox `focus:ring-primary` classes removed (no ring-width utility, so they never painted; the global `*:focus-visible` rule already covers those checkboxes at 4.52:1). Seeded: `#1266` (pre-existing white ring-offset halo on the selected-label state). + Wave-3 default-theme flip — Paper is now the DEFAULT UI (2026-06-27, `#1252`): `paperThemeStore` default `'off'`→`'paper'` (Paper canonical per ADR-0038), with the storage key bumped to `td.paper.mode.v2` and a one-time migration (a deliberate pre-flip `paper`/`paper-night`/`auto` choice carries over and the legacy key is cleared; a stored `'off'` — the old default / never-opted-in — or absent/invalid resolves to the new `'paper'` default). Legacy stays reachable through the Appearance toggle and is pinned in the test suites: the E2E `authSession` helper and a global vitest `setup.ts` hook both pin `td.paper.mode.v2='off'` so the ~19 legacy `.td-*` E2E specs and the Legacy-DOM unit specs keep asserting Legacy, while Paper-variant specs opt in explicitly. Review: a 2-lens adversarial sweep (0 confirmed) + Gemini round (migration inlined into `readStoredMode`); CI caught a 112-spec blast radius (the view shells render Paper by default) → fixed with the global off-pin; full FE suite green (3,752 tests). Paper-review de-stubs — Wave-2 completion (2026-06-27, 1 PR; built design-first): the last two stubbed Paper deep-Review handlers were wired to net-new backend, **unblocking the Wave-3 default-theme flip** (now shipped, above): diff --git a/docs/STATUS.md b/docs/STATUS.md index 2c075916f..ee9511a0b 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -1,6 +1,7 @@ # Taskdeck Status (Source of Truth) -Last Updated: 2026-06-30 +Last Updated: 2026-07-02 + @@ -12,7 +13,7 @@ Wave-6 backend + run-story delivery (2026-06-26, **3 PRs merged**; full review g - **`#1238` (`#1193`) — paged `CaptureService.ListAsync` from the database.** New capture-only `GetCapturesByUserAsync(userId, limit, offset)` (newest-first `ORDER BY CreatedAt DESC, Id`, SQLite raw + EF) replaces loading the user's entire `LlmRequest` history then filtering/paging in memory; a fetch-until-enough loop with a `seenIds` dedup guard keeps filtered queries correctly filled across OFFSET page boundaries. `GetByUserAsync` untouched → GDPR-safe. Seeded `#1239` (push board/status filters into SQL). - **`#1240` (`#1131`) — made the self-contained desktop exe runnable without manually supplying a connector key.** `ShouldAutoGenerateConnectorKey(isProd, isHeadless) => !isProd || !isHeadless`: a desktop install (Production, not headless) auto-generates + persists the connector encryption key to `appsettings.local.json`; **headless Production (CI / container / Terraform) still hard-fails** without a supplied stable key (`backend.Dockerfile` sets `TASKDECK_HEADLESS=true` so every container image is classified headless). The AWS single-node Terraform `user_data` generates+persists the key onto the durable EBS data volume (refusing to regenerate when a DB already exists without a key), `scripts/backup.sh`/`restore.sh`/`restore.ps1` keep the key paired with the database, and a deep review loop hardened the persistence path against silent key loss (reuse a masked persisted key instead of overwriting it; self-heal a corrupt local config; case-insensitive + provider-lenient reads; read-vs-parse error separation; owner-only ACL on the restored key). **`ADR-0041`** records the decision. ~15 distinct review findings (1 HIGH + many P2) across 6 Codex rounds + a 2-lens adversarial sweep, all fixed with tests. - **ADR added on main:** `ADR-0041` (desktop connector-key auto-generation; headless Production excluded). -- **Seeded follow-ups:** `#1237` (bound remaining unbounded Pending reads) **— shipped (`#1250`)**; `#1239` (push capture board/status filters into SQL) **— board pre-filter shipped 2026-06-30 (`#1254`); the status filter stays in-service (provenance-derived), so `#1239` remains open for that portion**. Still open from earlier: `#1241` (Windows ACL on the desktop key file), `#1242` (relocate persisted secrets to the durable app-data location). +- **Seeded follow-ups:** `#1237` (bound remaining unbounded Pending reads) **— shipped (`#1250`)**; `#1239` (push capture board/status filters into SQL) **— board pre-filter shipped 2026-06-30 (`#1254`); the status filter stays in-service (provenance-derived), so `#1239` remains open for that portion**. Shipped from earlier: `#1241` (Windows ACL on the desktop key file) **— 2026-07-02 (`#1263`)**. Still open from earlier: `#1242` (relocate persisted secrets to the durable app-data location). Direction + canonical UI (2026-06-13, maintainer-decided): - **Project direction is finish-for-personal-use, then archive.** Taskdeck will not be distributed; the goals are to finish and activate the Paper UI, make the app trivially easy to run locally, land general quality improvements, and archive cleanly. This supersedes the 2026-06-05 ship-first framing; distribution-era tracks (code-signing, GTM, cloud, mobile) are de-scoped. @@ -23,7 +24,7 @@ Archive-pivot delivery wave (2026-06-13, **17 PRs merged** across Waves 0–2, i - **Wave 1 — decision + cheap foundations (3 PRs):** **ADR-0038 ratified — Paper is the canonical UI, Legacy frozen `#1207`** (STATUS + masterplan now state the canonical stack; storage-key migration deferred to the Wave-3 flip); `#1139` AC1 compose-secret quickstart docs `#1205` (README + `docs/ops/DEPLOYMENT_CONTAINERS.md` now name BOTH required secrets, since compose aborts on a missing `TASKDECK_CONNECTORS_ENCRYPTION_KEY`); `*.migrate.lock` gitignored + `.dockerignore` mirror `#1204` (the SerializedMigrator sidecar no longer dirties `git status` on every startup). - **Wave 2/6 — Paper activation prerequisites + backend quality (5 PRs):** paper-night straggler tokenization `#1216` (`#1135` — KeyboardShortcutsHelp border + full-opacity WCAG focus ring; seeded `#1218` for the repo-wide `focus:ring-primary/50` contrast sweep); **shared review-actionability composable `#1217`** — extracted `isProposalApplyActionable` / `isProposalRejectActionable` / `isProposalApproveActionable` / `isProposalDismissable` / `isProposalStale` as pure functions in `useReviewProposals` so Paper and Legacy can never drift at the 24h-stale or Approved+expired boundaries (the `#1124` bug class is now fixed once, not twice), and de-stubbed the fabricated `4s · 1.2k tokens` author metadata in favour of the real `/confidence` value; dead-code removal `#1198`/`#1214` (see below); Redis lock-starvation fix `#1213` (`#1189` — dropped the in-lock retry loop and the 3s blocking Connect inside the lock; single attempt per throttle window → null/no-cache fallthrough, proven by deterministic regression guards); **one-command dev-up + clean-workspace scripts `#1208` (`#1140`)** — `dev-up.ps1/.sh` (dependency check, `%LOCALAPPDATA%` DB path to fix the CWD-dependent `taskdeck.db`, port-bound API via `--no-launch-profile --urls`, `/health/ready` poll, npm dev, optional `-Seed demo/demo123`) and `clean-workspace.ps1/.sh` (stray DBs/migrate-locks/logs, process-held-DB refusal), with recursive process-tree kill, live-PID-file refusal, and a `.migrate.lock` guard against deletion during an active migration; the dev-up DB-pinning path was live-smoke-verified before merge. - **ADRs added on main:** `ADR-0038` (Paper UI canonical / Legacy frozen), `ADR-0039` (Central Package Management, SDK pin, 8.x dependency alignment), `ADR-0040` (global UTC DateTime materialization for SQLite). -- **Seeded follow-ups:** `#1209` (no sweeper recovers non-capture `LlmRequests` stuck in Processing) **— shipped 2026-06-30 (`#1256`)**; `#1215` (`FieldVerifier`/`DeterministicPreExtractor` registered-but-unconsumed after V1 removal — keep-for-V2 decision), `#1218` (repo-wide focus-ring contrast sweep). +- **Seeded follow-ups:** `#1209` (no sweeper recovers non-capture `LlmRequests` stuck in Processing) **— shipped 2026-06-30 (`#1256`)**; `#1215` (`FieldVerifier`/`DeterministicPreExtractor` registered-but-unconsumed after V1 removal — keep-for-V2 decision), `#1218` (repo-wide focus-ring contrast sweep) **— shipped 2026-07-02 (`#1265`)**. - **Merged 2026-06-19** (maintainer lifted the merge hold; all four shipped to `main` after 2 independent adversarial reviews, all-severity findings fixed, fresh green CI): - `#1219` (`#1161`) — Paper review "File away" dismiss affordance built on the `#1217` shared-actionability foundation (per-proposal filing rail in terminal states + bulk "File away N settled" + dual-purpose ⌫). Closes `#1161`. - `#1221` — reachable in-app **Appearance** theme toggle (`AppearanceSettingsView` at `/workspace/settings/appearance`; off / paper / paper-night / auto), the reachable Legacy escape hatch that replaces the unlinked `/styleguide/paper` route — a Paper-activation prerequisite.