diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index a50bc66..8337f5f 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -24,7 +24,7 @@ Before any phase is marked complete: | Phase | Name | Goal | Requirements | |------:|------|------|--------------| | 12 | 6/6 | Complete | 2026-06-21 | -| 13 | 1/11 | In Progress| | +| 13 | 2/11 | In Progress| | | 14 | Selective Analysis and Byte Cache | Analyze selected cloud scopes through cancellable jobs backed by bounded, private, on-demand byte caching | ANALYZE-01..07, CACHE-03..05 | | 15 | Unified Smart Search | Search local and analyzed cloud documents by exact text or semantic ideas without downloading files during queries | SEARCH-01..07 | | 16 | Change Tracking and Reliability | Detect external provider changes, mark stale indexes, remove deleted items, and harden refresh behavior | SYNC-02..04 | @@ -80,13 +80,13 @@ Plans: **Depends on:** Phase 12 **Requirements:** CONN-01, CONN-02, CONN-03, CLOUD-02, CLOUD-03, CLOUD-04, CLOUD-05, CLOUD-06, CLOUD-07, CLOUD-09 -**Plans:** 1/11 plans executed +**Plans:** 2/11 plans executed **Execution waves:** Wave 0: 13-01 and 13-02 in parallel; Wave 1: 13-03 after 13-01; Wave 2: 13-04 after 13-01 and 13-03; Wave 3: 13-05 after 13-01, 13-03, and 13-04; Wave 4: 13-06 after 13-05; Wave 5: 13-07 and 13-08 in parallel (13-07 after 13-02, 13-04, and 13-06; 13-08 after 13-03, 13-04, and 13-06); Wave 6: 13-09 after 13-08; Wave 7: 13-10 after 13-02, 13-04, 13-07, and 13-09; Wave 8: 13-11 after 13-03 through 13-10. Plans: - [x] 13-01-PLAN.md — Create red backend and provider-contract suites for reconnect, content, mutations, and audit secrecy. -- [ ] 13-02-PLAN.md — Create red frontend/store suites for queue, preview, health UX, broader Drive consent, and no-probe-on-navigation. +- [x] 13-02-PLAN.md — Create red frontend/store suites for queue, preview, health UX, broader Drive consent, and no-probe-on-navigation. - [ ] 13-03-PLAN.md — Build the mutable cloud contract and orchestration seam without breaking centralized reconciliation. - [ ] 13-04-PLAN.md — Implement connection-ID reconnect, explicit health test, broader Drive scope handling, and authorized content routes. - [ ] 13-05-PLAN.md — Implement backend upload provider mechanics, typed route results, and refreshed-credential handoff. diff --git a/.planning/STATE.md b/.planning/STATE.md index b5a2ae7..177dcf9 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -6,14 +6,14 @@ current_phase: 13 current_phase_name: virtual-local-cloud-operations status: executing stopped_at: Phase 13 context gathered -last_updated: "2026-06-22T16:02:44.490Z" +last_updated: "2026-06-22T16:16:29.154Z" last_activity: 2026-06-22 last_activity_desc: Phase 13 execution started progress: total_phases: 6 completed_phases: 2 total_plans: 21 - completed_plans: 11 + completed_plans: 12 percent: 33 --- @@ -26,7 +26,7 @@ progress: ## Current Position Phase: 13 (virtual-local-cloud-operations) — EXECUTING -Plan: 2 of 11 +Plan: 3 of 11 Status: Ready to execute Last activity: 2026-06-22 — Phase 13 execution started @@ -53,6 +53,7 @@ Last activity: 2026-06-22 — Phase 13 execution started | Phase 12.1 P02 | 2100 | 3 tasks | 13 files | | Phase 12.1 P03 | 677 | 4 tasks | 11 files | | Phase 12.1 P04 | 15m | 4 tasks | 10 files | +| Phase 13 P02 | 30m | 2 tasks | 6 files | ## Accumulated Context @@ -96,7 +97,7 @@ _Updated at each phase transition._ | Field | Value | |---|---| -| Last session | 2026-06-22T16:02:44.485Z | +| Last session | 2026-06-22T16:16:29.149Z | | Next action | Execute Phase 12.1 Plan 01 | | Pending decisions | None | | Resume file | None | @@ -109,3 +110,7 @@ _Updated at each phase transition._ - [Phase 12.1 P03]: Named route objects used for all cloud folder navigation — Vue Router handles opaque ref encoding - [Phase 12.1 P03]: Breadcrumb lineage maintained as explicit visited-node list — never reconstructed from provider_item_id - [Phase 12.1 P03]: provider_item_id is canonical navigation reference; DocuVault id is row identity for Vue keys and metadata only +- [Phase ?]: Backend-typed bodies required; frontend never guesses +- [Phase ?]: file-open must call openCloudFile API; window.open() to provider URL is forbidden (D-02/T-13-07) +- [Phase ?]: connectionHealth store translation is single source for browser compact status and Settings diagnostics (D-12) +- [Phase ?]: testCloudConnection never called as side effect of folder browse navigation (D-13) diff --git a/.planning/phases/13-virtual-local-cloud-operations/13-02-SUMMARY.md b/.planning/phases/13-virtual-local-cloud-operations/13-02-SUMMARY.md new file mode 100644 index 0000000..e01845e --- /dev/null +++ b/.planning/phases/13-virtual-local-cloud-operations/13-02-SUMMARY.md @@ -0,0 +1,167 @@ +--- +phase: "13" +plan: "02" +subsystem: frontend-tests +tags: [tdd, red, frontend, cloud, queue, health, preview, store] +depends_on: + requires: + - "13-01" + provides: + - "13-02" + affects: + - "frontend/src/components/storage/StorageBrowser.vue" + - "frontend/src/views/CloudFolderView.vue" + - "frontend/src/stores/cloudConnections.js" + - "frontend/src/components/settings/SettingsCloudTab.vue" +tech_stack: + added: [] + patterns: + - "Red-test-first: failing tests define D-01..D-18 behavior before implementation" + - "Backend-typed conflict/error bodies: frontend never guesses conflict kind" + - "No window.open() invariant: all cloud open/preview routes through authorized backend" + - "No-probe-on-navigation: health checks fire after failures, not on browse" + - "Health-state store centralization: single translation for browser and Settings" +key_files: + created: + - "frontend/src/components/storage/__tests__/StorageBrowser.cloud-queue.test.js" + - "frontend/src/views/__tests__/CloudFolderOpenPreview.test.js" + - "frontend/src/components/settings/__tests__/SettingsCloudTab.health.test.js" + modified: + - "frontend/src/views/__tests__/CloudFolderView.test.js" + - "frontend/src/stores/__tests__/cloudConnections.test.js" + - "frontend/src/views/__tests__/CloudFolderRenderedFlow.test.js" +decisions: + - "Backend-authored conflict/error bodies (kind + reason codes) rather than Vue-side guessing" + - "file-open event must trigger authorized API call, never window.open() to provider URL" + - "Upload queue is array of typed queue items; conflicts/errors pause whole queue explicitly" + - "Health state map in store is single truth for browser compact status and Settings diagnostics" + - "no-probe-on-navigation is a hard invariant: testCloudConnection not called during browse" + - "Google Drive broader scope consent copy is a test-locked requirement (T-13-09)" +metrics: + duration: "~30 minutes" + completed: "2026-06-22" + tasks_completed: 2 + tasks_total: 2 + files_created: 3 + files_modified: 3 +status: complete +--- + +# Phase 13 Plan 02: Frontend Red Tests for Cloud Queue, Health, and Preview Summary + +**One-liner:** Created 42 red frontend tests covering shared cloud upload queue with backend-typed conflict/error dialogs, authorized open/preview with no raw provider URLs, health-state store centralization, reconnect-preserves-stale-metadata, and no-probe-on-navigation invariant. + +## Tasks Completed + +| Task | Name | Commit | Files | +|------|------|--------|-------| +| 1 | Add red shared-browser tests for queue, preview, and fallback download | 514925b | StorageBrowser.cloud-queue.test.js (new), CloudFolderOpenPreview.test.js (new), CloudFolderView.test.js (extended) | +| 2 | Add red store and health-flow tests for reconnect, broader Google consent, and no navigation probe | 8923ed5 | SettingsCloudTab.health.test.js (new), cloudConnections.test.js (extended), CloudFolderRenderedFlow.test.js (extended) | + +## Test Results (RED State Confirmed) + +All 42 new tests fail against the current implementation as required for TDD: + +| Suite | New Tests | Failing (RED) | Passing | +|-------|-----------|---------------|---------| +| StorageBrowser.cloud-queue.test.js | 18 | 13 | 5 | +| CloudFolderOpenPreview.test.js | 8 | 7 | 1 | +| CloudFolderView.test.js (extensions) | 3 | 1 | 2 | +| SettingsCloudTab.health.test.js | 12 | 10 | 2 | +| cloudConnections.test.js (extensions) | 14 | 7 | 7 | +| CloudFolderRenderedFlow.test.js (extensions) | 4 | 4 | 0 | +| **Total** | **59** | **42** | **17** | + +Existing 54 passing tests (Phase 12.1 suites) remain unaffected. + +## What These Tests Lock + +### Task 1: Queue and preview behavior (D-01, D-02, D-03, D-04, D-18, T-13-07, T-13-08) + +**StorageBrowser.cloud-queue.test.js:** +- Sequential upload queue emits array (not single File), forwarded via `uploadQueue` prop +- `paused_conflict` state renders conflict dialog with exactly 4 actions: Keep both / Replace / Skip / Cancel all +- Conflict dialog shows backend-authored `existing_name`, not frontend-guessed text +- Each conflict action emits `upload-queue-resolve` with typed `action` field +- `paused_error` state renders error dialog with Retry / Skip / Cancel all (no conflict choices) +- Error dialog shows backend error message verbatim +- Remaining queued items remain visible in `upload-queue-list` while dialog is shown +- No `window.open()` for cloud file open — must emit `file-open` event +- `file-open` payload carries `provider_item_id`, no raw `https://` URLs +- Unsupported formats emit `file-download-fallback` or `file-open` (never `window.open`) +- No parallel `data-test="cloud-only-grid"` in the browser component + +**CloudFolderOpenPreview.test.js:** +- `file-open` event triggers `api.openCloudFile(connectionId, provider_item_id)` — not `window.open()` +- `openCloudFile` arguments must not contain raw `https://` provider URLs +- Office/docx and Google Workspace files route to authorized backend (not native preview) +- No Google Docs/OneDrive URL opened via `window.open()` +- Backend `preview_url` is DocuVault-relative; no provider URLs in rendered HTML +- View handles `file-open` itself; must NOT re-emit it to parent router +- No anchor element click hack during PDF preview + +**CloudFolderView.test.js extensions:** +- No HTML table or `cloud-only-grid` in thin view +- `uploadQueue` prop forwarded to StorageBrowser as array +- Upload event from browser handled as queue operation (not immediate single-file upload) + +### Task 2: Health-state, reconnect, consent, and no-probe (D-12..D-17, T-13-06, T-13-09) + +**SettingsCloudTab.health.test.js:** +- Renders a Test connection button for active connections +- Renders a Reconnect button for REQUIRES_REAUTH connections +- Shows error detail beyond a generic status badge +- Clicking Test calls `testConnection(connectionId)` +- DEGRADED connection shows actionable warning without triggering disconnect confirmation +- Disconnect confirmation dialog does not appear automatically on mount +- Disconnect button click does NOT immediately call `store.disconnect()` — confirmation required +- Disconnect confirmation copy states provider files are untouched +- Google Drive connect/reconnect copy explicitly mentions broader storage access (not just `drive.file`) +- `gdrive-scope-notice` or `gdrive-consent-copy` data-test element must exist +- `credentials_enc`, `access_token`, `refresh_token` never appear in rendered HTML + +**cloudConnections.test.js extensions:** +- Store exposes `connectionHealth` or `healthState` field +- `setConnectionHealth('conn-1', {state: 'requires_reauth'})` stores actionable health state +- `setConnectionHealth` distinguishes `degraded` from `requires_reauth` +- Ordinary browse does NOT call `testCloudConnection` (no-probe-on-navigation) +- `handleHealthFailure` schedules a health retest (sets `pendingHealthRetest` flag) +- `markReconnectRefreshPending` sets a pending folder refresh flag +- `markReconnecting` preserves `browseItems` and sets freshness to `stale`/`reconnecting` +- `fetchConnections` marks connections with null health for testing + +**CloudFolderRenderedFlow.test.js extensions:** +- Warning freshness renders both cached items AND a health/reconnect banner +- A Reconnect button is accessible inside the browser (not only in Settings) +- `requires_reauth` freshness renders reauthentication prompt; cached items remain visible +- Folder-navigate does not call `testCloudConnection` as a side effect + +## Deviations from Plan + +None — plan executed exactly as written. The test failures are the intended RED state for a TDD plan. + +## Threat Mitigations Locked by Tests + +| Threat ID | Category | Mitigation | +|-----------|----------|------------| +| T-13-06 | Tampering | `cloudConnections.test.js` requires no background health probe on navigation | +| T-13-07 | Information Disclosure | `CloudFolderOpenPreview.test.js` forbids `window.open()` and raw provider URLs | +| T-13-08 | Repudiation | `StorageBrowser.cloud-queue.test.js` requires explicit pause/resume and backend-typed choices | +| T-13-09 | Spoofing | `SettingsCloudTab.health.test.js` requires explicit broader Google scope consent copy | + +## Stub Inventory + +No stubs that prevent plan goals: all test files are pure red test specifications. No implementation code was created in this plan. + +## Self-Check: PASSED + +| Check | Result | +|-------|--------| +| frontend/src/components/storage/__tests__/StorageBrowser.cloud-queue.test.js | FOUND | +| frontend/src/views/__tests__/CloudFolderOpenPreview.test.js | FOUND | +| frontend/src/components/settings/__tests__/SettingsCloudTab.health.test.js | FOUND | +| .planning/phases/13-virtual-local-cloud-operations/13-02-SUMMARY.md | FOUND | +| Commit 514925b (task 1) | FOUND | +| Commit 8923ed5 (task 2) | FOUND | +| 42 red tests confirmed | VERIFIED | +| 54 existing tests still passing | VERIFIED |