docs(phase-14): plan selective analysis and byte cache

This commit is contained in:
curo1305
2026-06-23 14:24:43 +02:00
parent 3514fdcf3a
commit b528b51881
13 changed files with 1117 additions and 16 deletions
+14
View File
@@ -111,6 +111,20 @@ Plans:
**Depends on:** Phase 13
**Requirements:** ANALYZE-01, ANALYZE-02, ANALYZE-03, ANALYZE-04, ANALYZE-05, ANALYZE-06, ANALYZE-07, CACHE-03, CACHE-04, CACHE-05
**Plans:** 0/9 plans complete
**Execution waves:** Wave 0: 14-01; Wave 1: 14-02 after 14-01; Wave 2: 14-03 after 14-02; Wave 3: 14-04 after 14-02 and 14-03; Wave 4: 14-05 after 14-03 and 14-04; Wave 5: 14-06 after 14-03 and 14-05; Wave 6: 14-07 after 14-04 and 14-05; Wave 7: 14-08 after 14-03 and 14-07; Wave 8: 14-09 after 14-01 through 14-08.
Plans:
- [ ] 14-01-PLAN.md — Create red backend/frontend tests for analysis scopes, estimates, cache invariants, queue states, and security negatives.
- [ ] 14-02-PLAN.md — Add durable cache/job/settings schema plus version-key and settings helpers.
- [ ] 14-03-PLAN.md — Implement owner-scoped byte cache service, quota accounting, pinning, eviction, and cache settings/status API.
- [ ] 14-04-PLAN.md — Implement estimate/enqueue/status/cancel/skip/retry analysis APIs with idempotent job creation.
- [ ] 14-05-PLAN.md — Implement Celery-backed cloud analysis processing, cache hydration, extraction, classification, and cancellation.
- [ ] 14-06-PLAN.md — Route existing cloud open/preview/download byte hydration through the bounded cache lifecycle.
- [ ] 14-07-PLAN.md — Wire shared-browser analysis actions, estimates, aggregate progress, expandable queue, and controls.
- [ ] 14-08-PLAN.md — Add Settings controls for cache limit, progress detail, and failure behavior.
- [ ] 14-09-PLAN.md — Run closeout docs, versions, full test/security gates, validation, commit, and push.
**Success Criteria:**
+16 -16
View File
@@ -2,17 +2,17 @@
gsd_state_version: 1.0
milestone: v0.3
milestone_name: Reimagining Cloud Storage integration
current_phase: 13
current_phase_name: virtual-local-cloud-operations
status: complete
stopped_at: Phase 14 context gathered
last_updated: "2026-06-23T12:04:31.598Z"
current_phase: 14
current_phase_name: selective-analysis-and-byte-cache
status: planned
stopped_at: Phase 14 planned
last_updated: "2026-06-23T00:00:00.000Z"
last_activity: 2026-06-23
last_activity_desc: Phase 13 complete, v0.3.0 shipped
progress:
total_phases: 6
completed_phases: 3
total_plans: 21
total_plans: 30
completed_plans: 21
percent: 50
---
@@ -20,15 +20,15 @@ progress:
# Project State
**Project:** DocuVault
**Status:** Phase 13 complete — ready to begin Phase 14
**Status:** Phase 14 planned — ready to execute Plan 14-01
**Last Updated:** 2026-06-23
## Current Position
Phase: 13 (virtual-local-cloud-operations) — COMPLETE
Plan: 11 of 11
Status: Phase 13 complete. Next: Phase 14 (Selective Analysis and Byte Cache)
Last activity: 2026-06-23 — Phase 13 complete, v0.3.0 shipped
Phase: 14 (selective-analysis-and-byte-cache) — PLANNED
Plan: 0 of 9
Status: Phase 14 planned. Next: execute 14-01 red contract tests
Last activity: 2026-06-23 — Phase 14 plan files created
## Phase Status
@@ -37,7 +37,7 @@ Last activity: 2026-06-23 — Phase 13 complete, v0.3.0 shipped
| 12. Cloud Resource Foundation | CONN-04, CLOUD-01, CLOUD-08, CACHE-01, CACHE-02, SYNC-01 | **Complete** |
| 12.1 Fix Nextcloud Root Listing and Sync Visibility | CONN-04, CLOUD-01, CACHE-01, SYNC-01 | **Complete** |
| 13. Virtual-Local Cloud Operations | CONN-01..03, CLOUD-02..07, CLOUD-09 | **Complete** |
| 14. Selective Analysis and Byte Cache | ANALYZE-01..07, CACHE-03..05 | **Not started** |
| 14. Selective Analysis and Byte Cache | ANALYZE-01..07, CACHE-03..05 | **Planned** |
| 15. Unified Smart Search | SEARCH-01..07 | **Not started** |
| 16. Change Tracking and Reliability | SYNC-02..04 | **Not started** |
@@ -91,7 +91,7 @@ Last activity: 2026-06-23 — Phase 13 complete, v0.3.0 shipped
- v0.2 completed: UI overhaul, admin panel rearchitecture, responsive layout, codebase quality (2026-06-17)
- v0.2 archived to `.planning/milestones/v0.2-ROADMAP.md`
- v0.3 in progress: Phase 12 (cloud resource foundation) complete 2026-06-21; Phase 12.1 (Nextcloud fix) complete; Phase 13 (virtual-local cloud operations) complete 2026-06-23 — v0.3.0 shipped
- Phase 14 (selective analysis and byte cache) is next
- Phase 14 (selective analysis and byte cache) planned 2026-06-23
### Open Questions
@@ -103,16 +103,16 @@ None.
## Session Continuity
**Stopped at:** Phase 14 context gathered
**Stopped at:** Phase 14 planned
_Updated at each phase transition._
| Field | Value |
|---|---|
| Last session | 2026-06-23T12:04:31.592Z |
| Next action | Begin Phase 14 (Selective Analysis and Byte Cache) |
| Next action | Execute 14-01 red contract tests |
| Pending decisions | None |
| Resume file | .planning/phases/14-selective-analysis-and-byte-cache/14-CONTEXT.md |
| Resume file | .planning/phases/14-selective-analysis-and-byte-cache/14-01-PLAN.md |
## Decisions
@@ -0,0 +1,106 @@
---
phase: "14"
plan: "01"
type: execute
wave: 0
depends_on: []
files_modified:
- backend/tests/test_cloud_analysis_contract.py
- backend/tests/test_cloud_cache.py
- backend/tests/test_cloud_analysis_api.py
- frontend/src/components/storage/__tests__/StorageBrowser.analysis-queue.test.js
- frontend/src/stores/__tests__/cloudConnections.analysis.test.js
autonomous: true
requirements:
- ANALYZE-01
- ANALYZE-02
- ANALYZE-03
- ANALYZE-04
- ANALYZE-05
- ANALYZE-06
- ANALYZE-07
- CACHE-03
- CACHE-04
- CACHE-05
---
<objective>
Create the Phase 14 executable test contract before implementation. Establish red backend and frontend tests for analysis scope selection, estimates, duplicate-version skips, cache ownership/quota semantics, cancellation/retry controls, and the shared-browser queue surface.
Scope fence: add tests and fixtures only. Do not implement production code in this plan except minimal test helpers/fakes.
</objective>
<context>
@.planning/ROADMAP.md
@.planning/REQUIREMENTS.md
@.planning/phases/14-selective-analysis-and-byte-cache/14-CONTEXT.md
@.planning/phases/14-selective-analysis-and-byte-cache/14-RESEARCH.md
@.planning/phases/14-selective-analysis-and-byte-cache/14-PATTERNS.md
@backend/tests/test_cloud_items.py
@backend/tests/test_cloud_security.py
@frontend/src/components/storage/__tests__/StorageBrowser.cloud-queue.test.js
</context>
<tasks>
<task type="auto">
<name>Task 1: Add backend red tests for analysis and cache contracts</name>
<files>backend/tests/test_cloud_analysis_contract.py, backend/tests/test_cloud_cache.py, backend/tests/test_cloud_analysis_api.py</files>
<read_first>
- backend/tests/test_cloud_items.py
- backend/tests/test_cloud_security.py
- backend/tests/test_cloud_mutations.py
- backend/db/models.py
</read_first>
<action>
Add focused tests using fake cloud items/connections and fake provider adapters. Cover individual-file, selection, folder, and connection estimate/enqueue requests; whole-connection estimate requirement; recursive folder choice; unsupported item reporting; duplicate unchanged version skip without provider byte fetch; owner/admin-negative access; cache entry ownership; cache object key secrecy; quota increment/decrement expectations; active pin eviction protection; retry and cancel status transitions. Mark these tests red against missing modules/endpoints rather than weakening assertions.
</action>
<acceptance_criteria>
- Tests name the exact ANALYZE/CACHE requirements they protect.
- Tests assert provider bytes are not downloaded during estimate or duplicate-current checks.
- Tests assert provider mutation methods are never invoked by analysis paths.
- Running the new backend tests fails for missing Phase 14 implementation, not syntax/import errors in the tests themselves once modules exist.
</acceptance_criteria>
<verify><automated>cd backend && pytest -q tests/test_cloud_analysis_contract.py tests/test_cloud_cache.py tests/test_cloud_analysis_api.py</automated></verify>
</task>
<task type="auto">
<name>Task 2: Add frontend red tests for shared-browser analysis UX</name>
<files>frontend/src/components/storage/__tests__/StorageBrowser.analysis-queue.test.js, frontend/src/stores/__tests__/cloudConnections.analysis.test.js</files>
<read_first>
- frontend/src/components/storage/StorageBrowser.vue
- frontend/src/views/CloudFolderView.vue
- frontend/src/stores/cloudConnections.js
- frontend/src/components/storage/__tests__/StorageBrowser.cloud-queue.test.js
</read_first>
<action>
Add tests proving row-level file analysis action, toolbar analysis for multi-select/folder/current connection, estimate modal thresholds, aggregate progress, expandable item list, simplified vs detailed labels, retry/skip/cancel controls, and Settings-backed default failure behavior. Tests must assert that `CloudFolderView` passes props and handles emits without owning layout, and that no parallel file grid is introduced.
</action>
<acceptance_criteria>
- Tests fail because analysis UI/store code is absent, not because of brittle selectors.
- Shared browser remains the component under test for browser layout and controls.
- Store tests cover status translation and API client calls without using localStorage/sessionStorage for credentials.
</acceptance_criteria>
<verify><automated>cd frontend && npm run test -- StorageBrowser.analysis-queue.test.js cloudConnections.analysis.test.js</automated></verify>
</task>
</tasks>
<threat_model>
| Threat ID | Threat | Required test evidence |
|-----------|--------|------------------------|
| T-14-01 | Analysis IDOR | Foreign user cannot estimate/enqueue/status/cancel/retry another user's connection or item |
| T-14-02 | Credential/object-key disclosure | API/audit responses never include credentials, raw provider URLs, or MinIO object keys |
| T-14-03 | Hidden provider mutation | Fake adapter mutation method counters remain zero during analysis |
| T-14-04 | Hidden byte download | Estimate and already-current checks do not call provider byte fetch |
| T-14-05 | Cache quota corruption | Tests require atomic quota increment on retain and decrement on eviction |
</threat_model>
<verification>
1. `cd backend && pytest -q tests/test_cloud_analysis_contract.py tests/test_cloud_cache.py tests/test_cloud_analysis_api.py`
2. `cd frontend && npm run test -- StorageBrowser.analysis-queue.test.js cloudConnections.analysis.test.js`
3. Confirm failures are expected missing-implementation failures only.
</verification>
<output>Create `.planning/phases/14-selective-analysis-and-byte-cache/14-01-SUMMARY.md` when complete.</output>
@@ -0,0 +1,87 @@
---
phase: "14"
plan: "02"
type: execute
wave: 1
depends_on:
- "14-01"
files_modified:
- backend/migrations/versions/0007_cloud_analysis_cache.py
- backend/db/models.py
- backend/services/cloud_analysis_versioning.py
- backend/services/cloud_analysis_settings.py
- backend/tests/test_cloud_analysis_contract.py
- backend/tests/test_cloud_cache.py
autonomous: true
requirements:
- ANALYZE-04
- ANALYZE-06
- CACHE-04
- CACHE-05
---
<objective>
Add durable Phase 14 schema and shared helpers for cache entries, analysis jobs, per-item status, version-key idempotency, and user/tier-ready analysis settings.
Scope fence: no provider byte download, Celery processing, or frontend UI in this plan.
</objective>
<context>
@.planning/phases/14-selective-analysis-and-byte-cache/14-RESEARCH.md
@.planning/phases/14-selective-analysis-and-byte-cache/14-PATTERNS.md
@backend/db/models.py
@backend/migrations/versions/0006_cloud_resource_foundation.py
@backend/services/cloud_items.py
</context>
<tasks>
<task type="auto">
<name>Task 1: Add migration and ORM models</name>
<files>backend/migrations/versions/0007_cloud_analysis_cache.py, backend/db/models.py</files>
<read_first>
- backend/migrations/versions/0006_cloud_resource_foundation.py
- backend/db/models.py
</read_first>
<action>
Create the next Alembic revision for `cloud_byte_cache_entries`, `cloud_analysis_jobs`, `cloud_analysis_job_items`, and either owner-scoped analysis settings or extensions to the existing settings model. Include strict user/connection/item foreign keys, unique cache version key constraints, LRU eviction indexes, status fields, controlled error fields, aggregate counters, and reversible downgrade. Models must mirror the migration and preserve the existing `CloudItem` identity model.
</action>
<acceptance_criteria>
- Cache entries are scoped by user, connection, cloud item, and version key.
- Job and job-item rows can represent file, selection, folder, and connection analysis.
- Settings support progress detail, failure behavior, and tier-capped cache limit preference.
- Downgrade drops only Phase 14 objects.
</acceptance_criteria>
<verify><automated>cd backend && pytest -q tests/test_cloud_cache.py -k "schema or model"</automated></verify>
</task>
<task type="auto">
<name>Task 2: Add version-key and settings helpers</name>
<files>backend/services/cloud_analysis_versioning.py, backend/services/cloud_analysis_settings.py, backend/tests/test_cloud_analysis_contract.py, backend/tests/test_cloud_cache.py</files>
<read_first>
- backend/services/cloud_items.py
- backend/db/models.py
- .planning/phases/14-selective-analysis-and-byte-cache/14-PATTERNS.md
</read_first>
<action>
Implement one shared version-key helper using version, etag, fallback metadata fingerprint, and optional post-hydration content hash. Implement settings helpers that return defaults, validate enum values, enforce cache limit bounds, and leave a clean tier/admin maximum seam. Services raise `ValueError` or domain exceptions only.
</action>
<acceptance_criteria>
- Duplicate-current and cache lookup code can consume one canonical version key.
- Content hash is never required before bytes are hydrated.
- Invalid setting values are rejected by service validation.
- `rg "HTTPException" backend/services/cloud_analysis_versioning.py backend/services/cloud_analysis_settings.py` returns no matches.
</acceptance_criteria>
<verify><automated>cd backend && pytest -q tests/test_cloud_analysis_contract.py tests/test_cloud_cache.py -k "version_key or settings"</automated></verify>
</task>
</tasks>
<verification>
1. `cd backend && pytest -q tests/test_cloud_analysis_contract.py tests/test_cloud_cache.py`
2. Run migration upgrade/downgrade against the PostgreSQL integration environment.
3. `rg "HTTPException" backend/services/cloud_analysis_versioning.py backend/services/cloud_analysis_settings.py`
</verification>
<output>Create `.planning/phases/14-selective-analysis-and-byte-cache/14-02-SUMMARY.md` when complete.</output>
@@ -0,0 +1,99 @@
---
phase: "14"
plan: "03"
type: execute
wave: 2
depends_on:
- "14-02"
files_modified:
- backend/services/cloud_byte_cache.py
- backend/api/cloud/cache.py
- backend/api/cloud/schemas.py
- backend/api/cloud/__init__.py
- backend/tests/test_cloud_cache.py
- backend/tests/test_cloud_security.py
autonomous: true
requirements:
- CACHE-03
- CACHE-04
- CACHE-05
---
<objective>
Implement the owner-scoped byte cache service and read/control API: cache lookup, retain, pin/release, per-user LRU eviction, quota accounting, settings update, and metadata-safe cache status responses.
Scope fence: do not wire analysis workers or open/preview hydration yet. This plan builds the cache primitive those paths will call.
</objective>
<context>
@.planning/phases/14-selective-analysis-and-byte-cache/14-RESEARCH.md
@.planning/phases/14-selective-analysis-and-byte-cache/14-PATTERNS.md
@backend/storage/minio_backend.py
@backend/services/cloud_items.py
@backend/db/models.py
@backend/api/cloud/schemas.py
</context>
<tasks>
<task type="auto">
<name>Task 1: Build cache service with quota and pinning semantics</name>
<files>backend/services/cloud_byte_cache.py, backend/tests/test_cloud_cache.py</files>
<read_first>
- backend/storage/minio_backend.py
- backend/services/quota.py
- backend/db/models.py
- backend/tests/test_quota.py
</read_first>
<action>
Add cache service functions to resolve owned cache entries, reserve quota atomically before retaining bytes, store bytes using UUID/private object keys, record metadata, reuse matching non-evicted version entries, pin/release active job or preview use, update last access, evict inactive LRU entries per user limit, decrement quota when retained bytes are evicted, and delete MinIO objects best-effort after DB state is consistent. Protect entries with `pin_count > 0` or `active_job_count > 0`.
</action>
<acceptance_criteria>
- Cache retention increments quota and eviction decrements quota with atomic quota helpers.
- Eviction never selects another user's entry and never evicts pinned/active entries.
- Object keys are generated UUID/private keys and never include provider filenames.
- Service functions raise domain errors or `ValueError`, never `HTTPException`.
</acceptance_criteria>
<verify><automated>cd backend && pytest -q tests/test_cloud_cache.py</automated></verify>
</task>
<task type="auto">
<name>Task 2: Add cache settings/status API</name>
<files>backend/api/cloud/cache.py, backend/api/cloud/schemas.py, backend/api/cloud/__init__.py, backend/tests/test_cloud_cache.py, backend/tests/test_cloud_security.py</files>
<read_first>
- backend/api/cloud/connections.py
- backend/api/cloud/operations.py
- backend/api/cloud/schemas.py
- backend/tests/test_cloud_security.py
</read_first>
<action>
Add credential-free endpoints for current cache usage/settings and updating the user's preferred cache limit/progress/failure settings. Use explicit Pydantic fields only. Return aggregate bytes/counts and tier cap, not object keys. Enforce `get_regular_user`, owner scope, and rate limiting consistent with existing cloud routes.
</action>
<acceptance_criteria>
- Admin users are blocked.
- Responses contain no `object_key`, credentials, raw provider URLs, or extracted text.
- Invalid cache limits above the tier/admin cap return a controlled validation response.
- Security tests cover foreign user and admin-negative cases.
</acceptance_criteria>
<verify><automated>cd backend && pytest -q tests/test_cloud_cache.py tests/test_cloud_security.py -k "cache"</automated></verify>
</task>
</tasks>
<threat_model>
| Threat ID | Threat | Mitigation |
|-----------|--------|------------|
| T-14-06 | Cross-user cache access | All cache entry queries include user_id and connection_id; negative tests |
| T-14-07 | Quota race | Existing atomic quota update helpers required for retain/evict deltas |
| T-14-08 | Object key leakage | API schemas omit object_key and tests assert absence |
| T-14-09 | Active work eviction | Pin/active counters in selection predicate and regression tests |
</threat_model>
<verification>
1. `cd backend && pytest -q tests/test_cloud_cache.py`
2. `cd backend && pytest -q tests/test_cloud_security.py -k "cache"`
3. `rg "object_key|credentials_enc" backend/api/cloud/cache.py backend/api/cloud/schemas.py`
</verification>
<output>Create `.planning/phases/14-selective-analysis-and-byte-cache/14-03-SUMMARY.md` when complete.</output>
@@ -0,0 +1,93 @@
---
phase: "14"
plan: "04"
type: execute
wave: 3
depends_on:
- "14-02"
- "14-03"
files_modified:
- backend/services/cloud_analysis.py
- backend/api/cloud/analysis.py
- backend/api/cloud/schemas.py
- backend/api/cloud/__init__.py
- backend/tests/test_cloud_analysis_api.py
- backend/tests/test_cloud_analysis_contract.py
- backend/tests/test_cloud_security.py
autonomous: true
requirements:
- ANALYZE-01
- ANALYZE-02
- ANALYZE-03
- ANALYZE-05
- ANALYZE-06
- ANALYZE-07
---
<objective>
Implement Phase 14 analysis estimate, enqueue, status, cancellation, skip, and retry APIs backed by durable job rows and idempotency checks.
Scope fence: enqueue and control jobs only. Actual provider byte hydration/extraction/classification is Plan 05.
</objective>
<context>
@.planning/phases/14-selective-analysis-and-byte-cache/14-CONTEXT.md
@.planning/phases/14-selective-analysis-and-byte-cache/14-PATTERNS.md
@backend/services/cloud_items.py
@backend/services/cloud_analysis_versioning.py
@backend/services/cloud_analysis_settings.py
@backend/api/cloud/operations.py
</context>
<tasks>
<task type="auto">
<name>Task 1: Add analysis orchestration service</name>
<files>backend/services/cloud_analysis.py, backend/tests/test_cloud_analysis_contract.py</files>
<read_first>
- backend/services/cloud_items.py
- backend/services/cloud_analysis_versioning.py
- backend/db/models.py
</read_first>
<action>
Implement owner-scoped functions for estimating file/selection/folder/connection scopes, expanding known folder descendants from metadata where available, reporting partial estimates when provider expansion is incomplete, creating analysis jobs and job items, skipping unsupported/current items, and rejecting duplicate active jobs for the same user/item/version. Folder analysis must preserve current-only vs recursive choice; whole-connection analysis is recursive. Estimates never download bytes.
</action>
<acceptance_criteria>
- File, selection, folder, and connection scope requests create correct job metadata.
- Whole-connection jobs require estimate acknowledgement unless trivially small by configured thresholds.
- Current unchanged items are marked `already_current` and do not enqueue byte work.
- Provider mutation methods are never called.
</acceptance_criteria>
<verify><automated>cd backend && pytest -q tests/test_cloud_analysis_contract.py</automated></verify>
</task>
<task type="auto">
<name>Task 2: Add analysis API routes and typed schemas</name>
<files>backend/api/cloud/analysis.py, backend/api/cloud/schemas.py, backend/api/cloud/__init__.py, backend/tests/test_cloud_analysis_api.py, backend/tests/test_cloud_security.py</files>
<read_first>
- backend/api/cloud/operations.py
- backend/api/cloud/schemas.py
- backend/tests/test_cloud_security.py
</read_first>
<action>
Add routes under `/api/cloud/connections/{connection_id}/analysis` for estimate, enqueue/start, job status/list, cancel item, cancel batch, skip failed/queued item, and retry failed item. Use explicit request schemas and credential-free response schemas. Convert service domain errors into typed JSON bodies with stable `kind`/`reason` fields.
</action>
<acceptance_criteria>
- Routes use `get_regular_user` and owner-scoped connection/item resolution.
- Status responses expose aggregate and per-item state without credentials, object keys, provider URLs, or raw provider errors.
- Retry creates a fresh item attempt from the beginning.
- Cancel queued work immediately and marks running work cancellation-requested for worker cooperation.
</acceptance_criteria>
<verify><automated>cd backend && pytest -q tests/test_cloud_analysis_api.py tests/test_cloud_security.py -k "analysis"</automated></verify>
</task>
</tasks>
<verification>
1. `cd backend && pytest -q tests/test_cloud_analysis_contract.py tests/test_cloud_analysis_api.py`
2. `cd backend && pytest -q tests/test_cloud_security.py -k "analysis"`
3. Confirm `rg "download|get_object|put_object" backend/services/cloud_analysis.py backend/api/cloud/analysis.py` has no estimate-time byte fetch.
</verification>
<output>Create `.planning/phases/14-selective-analysis-and-byte-cache/14-04-SUMMARY.md` when complete.</output>
@@ -0,0 +1,104 @@
---
phase: "14"
plan: "05"
type: execute
wave: 4
depends_on:
- "14-03"
- "14-04"
files_modified:
- backend/tasks/cloud_analysis_tasks.py
- backend/celery_app.py
- backend/services/cloud_analysis_processing.py
- backend/services/cloud_byte_cache.py
- backend/services/classifier.py
- backend/tests/test_cloud_analysis_contract.py
- backend/tests/test_cloud_cache.py
autonomous: true
requirements:
- ANALYZE-04
- ANALYZE-05
- ANALYZE-06
- ANALYZE-07
- CACHE-03
- CACHE-04
---
<objective>
Implement Celery-backed cloud analysis processing: hydrate bytes on demand, retain/reuse cache entries, extract text, classify topics onto `CloudItem`, update per-item and aggregate states, and honor cancellation/retry semantics.
Scope fence: do not build frontend controls in this plan.
</objective>
<context>
@.planning/phases/14-selective-analysis-and-byte-cache/14-PATTERNS.md
@backend/tasks/cloud_tasks.py
@backend/tasks/document_tasks.py
@backend/services/extractor.py
@backend/services/classifier.py
@backend/storage/cloud_backend_factory.py
@backend/services/cloud_byte_cache.py
</context>
<tasks>
<task type="auto">
<name>Task 1: Add processing service for one job item</name>
<files>backend/services/cloud_analysis_processing.py, backend/services/cloud_byte_cache.py, backend/tests/test_cloud_analysis_contract.py, backend/tests/test_cloud_cache.py</files>
<read_first>
- backend/services/extractor.py
- backend/services/classifier.py
- backend/services/cloud_byte_cache.py
- backend/services/cloud_analysis_versioning.py
</read_first>
<action>
Implement a service that processes a single job item by revalidating owner/connection/item, checking cancellation, checking version-key currentness, reusing or hydrating cache bytes, extracting text, persisting `CloudItem.extracted_text`, classifying topics through existing classifier logic adapted for cloud items, updating status to indexed/failed/cancelled/stale, and releasing cache pins. Compute content hash only while bytes are already available. Never create a local `Document` row and never call provider mutation methods.
</action>
<acceptance_criteria>
- Status transitions include downloading, extracting, classifying, indexed, cancelled, failed, stale.
- Unchanged version skips processing before provider byte fetch.
- Provider byte fetch occurs only for actionable analysis/open/preview work.
- Cache pins are released on success, failure, and cancellation.
</acceptance_criteria>
<verify><automated>cd backend && pytest -q tests/test_cloud_analysis_contract.py tests/test_cloud_cache.py -k "processing or idempotent or cancellation"</automated></verify>
</task>
<task type="auto">
<name>Task 2: Add Celery task and retry harness</name>
<files>backend/tasks/cloud_analysis_tasks.py, backend/celery_app.py, backend/tests/test_cloud_analysis_contract.py</files>
<read_first>
- backend/tasks/cloud_tasks.py
- backend/tasks/document_tasks.py
- backend/celery_app.py
</read_first>
<action>
Add sync Celery tasks that bridge to async processing with the existing sentinel retry pattern. Task payloads include job id/item id only. Decrypt credentials inside the worker after owner revalidation. Support bounded transient provider/classifier retry, terminal auth failures, max-retry final failure status, and cooperative cancellation checks between stages.
</action>
<acceptance_criteria>
- Celery broker payload contains no credentials, provider URLs, filenames, or bytes.
- `self.retry()` is raised only in the outer sync task layer.
- Max retry writes controlled failure status.
- Aggregate job counters update after item transitions.
</acceptance_criteria>
<verify><automated>cd backend && pytest -q tests/test_cloud_analysis_contract.py -k "celery or retry or broker"</automated></verify>
</task>
</tasks>
<threat_model>
| Threat ID | Threat | Mitigation |
|-----------|--------|------------|
| T-14-10 | Credentials in broker payload | IDs only in Celery task args; decrypt in worker |
| T-14-11 | Provider file mutation | Processing service uses content-read adapter path only and tests fake mutation counters |
| T-14-12 | Cache pin leak | finally block releases pins; tests cover failure/cancel paths |
| T-14-13 | Stale result presented as current | Final version/fingerprint comparison marks item stale if provider metadata changed |
</threat_model>
<verification>
1. `cd backend && pytest -q tests/test_cloud_analysis_contract.py tests/test_cloud_cache.py`
2. `rg "credentials|credentials_enc|file_bytes" backend/tasks/cloud_analysis_tasks.py` and confirm no broker payload exposure.
3. `rg "Document\\(" backend/services/cloud_analysis_processing.py backend/tasks/cloud_analysis_tasks.py` returns no local import creation.
</verification>
<output>Create `.planning/phases/14-selective-analysis-and-byte-cache/14-05-SUMMARY.md` when complete.</output>
@@ -0,0 +1,87 @@
---
phase: "14"
plan: "06"
type: execute
wave: 5
depends_on:
- "14-03"
- "14-05"
files_modified:
- backend/api/cloud/operations.py
- backend/services/cloud_byte_cache.py
- backend/api/cloud/schemas.py
- backend/tests/test_cloud_cache.py
- backend/tests/test_cloud_security.py
- frontend/src/views/__tests__/CloudFolderOpenPreview.test.js
autonomous: true
requirements:
- CACHE-03
- CACHE-04
- CACHE-05
---
<objective>
Route cloud open/preview byte hydration through the Phase 14 byte cache so opening and previewing use the same bounded, owner-scoped, quota-counted cache lifecycle as analysis.
Scope fence: do not change the shared browser analysis queue; this plan only updates existing content routes and their tests.
</objective>
<context>
@.planning/phases/13-virtual-local-cloud-operations/13-CONTEXT.md
@.planning/phases/14-selective-analysis-and-byte-cache/14-PATTERNS.md
@backend/api/cloud/operations.py
@backend/services/cloud_byte_cache.py
@frontend/src/views/CloudFolderView.vue
</context>
<tasks>
<task type="auto">
<name>Task 1: Update backend open/preview/download routes to use cache leases</name>
<files>backend/api/cloud/operations.py, backend/services/cloud_byte_cache.py, backend/tests/test_cloud_cache.py, backend/tests/test_cloud_security.py</files>
<read_first>
- backend/api/cloud/operations.py
- backend/services/cloud_byte_cache.py
- backend/storage/cloud_backend_factory.py
</read_first>
<action>
Modify authorized cloud content routes so provider bytes are hydrated into the cache on demand, pinned during active streaming/preview, last-accessed timestamp is updated, and eviction runs after release when needed. Preserve binary-only preview enforcement and no raw provider URL exposure. Existing download fallback remains authorized through DocuVault, not a provider URL.
</action>
<acceptance_criteria>
- Preview/open/download never serve bytes without owner-scoped connection/item resolution.
- Cache hits avoid provider byte fetch.
- Active preview/download cache entries are not evicted mid-response.
- Responses still omit object keys, credentials, and raw provider URLs.
</acceptance_criteria>
<verify><automated>cd backend && pytest -q tests/test_cloud_cache.py tests/test_cloud_security.py -k "preview or download or cache"</automated></verify>
</task>
<task type="auto">
<name>Task 2: Preserve frontend open/preview behavior against cached backend</name>
<files>frontend/src/views/__tests__/CloudFolderOpenPreview.test.js</files>
<read_first>
- frontend/src/views/CloudFolderView.vue
- frontend/src/api/cloud.js
- frontend/src/views/__tests__/CloudFolderOpenPreview.test.js
</read_first>
<action>
Update frontend tests only if route response metadata changes. Preserve the invariant that `CloudFolderView` calls `api.openCloudFile`/`previewCloudFile` and never opens provider URLs directly. Add assertions that cache-related response fields, if any, do not leak object keys.
</action>
<acceptance_criteria>
- Existing open/preview tests remain green.
- No browser-to-provider URL path is introduced.
- Cache semantics remain backend-owned and do not require frontend object-key knowledge.
</acceptance_criteria>
<verify><automated>cd frontend && npm run test -- CloudFolderOpenPreview.test.js</automated></verify>
</task>
</tasks>
<verification>
1. `cd backend && pytest -q tests/test_cloud_cache.py tests/test_cloud_security.py -k "cache or preview or download"`
2. `cd frontend && npm run test -- CloudFolderOpenPreview.test.js`
3. `rg "window.open|provider_url|object_key" frontend/src/views/CloudFolderView.vue frontend/src/api/cloud.js backend/api/cloud/operations.py`
</verification>
<output>Create `.planning/phases/14-selective-analysis-and-byte-cache/14-06-SUMMARY.md` when complete.</output>
@@ -0,0 +1,93 @@
---
phase: "14"
plan: "07"
type: execute
wave: 6
depends_on:
- "14-04"
- "14-05"
files_modified:
- frontend/src/api/cloud.js
- frontend/src/stores/cloudConnections.js
- frontend/src/views/CloudFolderView.vue
- frontend/src/components/storage/StorageBrowser.vue
- frontend/src/components/storage/__tests__/StorageBrowser.analysis-queue.test.js
- frontend/src/stores/__tests__/cloudConnections.analysis.test.js
- frontend/src/views/__tests__/CloudFolderRenderedFlow.test.js
autonomous: true
requirements:
- ANALYZE-01
- ANALYZE-02
- ANALYZE-03
- ANALYZE-04
- ANALYZE-05
- ANALYZE-06
---
<objective>
Implement the shared-browser Phase 14 analysis experience: row action, toolbar actions, estimate dialog, aggregate progress, expandable queue, and per-item/batch controls using the backend analysis API.
Scope fence: do not build Settings controls in this plan beyond consuming already-returned settings values.
</objective>
<context>
@.planning/phases/14-selective-analysis-and-byte-cache/14-CONTEXT.md
@.planning/phases/14-selective-analysis-and-byte-cache/14-PATTERNS.md
@frontend/src/components/storage/StorageBrowser.vue
@frontend/src/views/CloudFolderView.vue
@frontend/src/stores/cloudConnections.js
@frontend/src/api/cloud.js
</context>
<tasks>
<task type="auto">
<name>Task 1: Add API/store analysis queue surface</name>
<files>frontend/src/api/cloud.js, frontend/src/stores/cloudConnections.js, frontend/src/stores/__tests__/cloudConnections.analysis.test.js</files>
<read_first>
- frontend/src/api/cloud.js
- frontend/src/stores/cloudConnections.js
- frontend/src/stores/__tests__/cloudConnections.test.js
</read_first>
<action>
Add API helpers for estimate, start, list/status, cancel batch, cancel item, skip item, and retry item. Extend the store with analysis jobs, aggregate queue state, status label mapping, simplified/detailed progress mode, and failure behavior. Keep tokens in Pinia memory only and never persist queue credentials or provider refs outside route/session semantics already allowed.
</action>
<acceptance_criteria>
- Store translates backend statuses in one place.
- API helpers use connection UUID and opaque provider item ids.
- Tests cover current/already-indexed, failed, cancelled, retry, and aggregate states.
</acceptance_criteria>
<verify><automated>cd frontend && npm run test -- cloudConnections.analysis.test.js</automated></verify>
</task>
<task type="auto">
<name>Task 2: Extend StorageBrowser and CloudFolderView</name>
<files>frontend/src/components/storage/StorageBrowser.vue, frontend/src/views/CloudFolderView.vue, frontend/src/components/storage/__tests__/StorageBrowser.analysis-queue.test.js, frontend/src/views/__tests__/CloudFolderRenderedFlow.test.js</files>
<read_first>
- frontend/src/components/storage/StorageBrowser.vue
- frontend/src/views/CloudFolderView.vue
- frontend/src/components/storage/__tests__/StorageBrowser.cloud-queue.test.js
- frontend/src/views/__tests__/CloudFolderRenderedFlow.test.js
</read_first>
<action>
Add file-row analyze action, toolbar actions for selected items/current folder/current connection, folder current-only vs recursive prompt, estimate review dialog, aggregate analysis progress, expandable item queue, retry/skip/cancel controls, and cancel-all. `StorageBrowser` emits actions; `CloudFolderView` handles API/store calls and refresh behavior. Use icons/tooltips consistent with existing AppIcon patterns and keep text compact enough for mobile.
</action>
<acceptance_criteria>
- No parallel file grid or cloud-only browser component is introduced.
- Individual file, multi-select, folder, and connection analysis can be initiated.
- Whole connection and thresholded large scopes show estimate before start.
- Aggregate and per-item statuses render with accessible controls.
</acceptance_criteria>
<verify><automated>cd frontend && npm run test -- StorageBrowser.analysis-queue.test.js CloudFolderRenderedFlow.test.js</automated></verify>
</task>
</tasks>
<verification>
1. `cd frontend && npm run test -- StorageBrowser.analysis-queue.test.js cloudConnections.analysis.test.js CloudFolderRenderedFlow.test.js`
2. `rg "analysis" frontend/src/components/storage frontend/src/views/CloudFolderView.vue frontend/src/stores/cloudConnections.js`
3. Rendered smoke check in browser if the dev server is available.
</verification>
<output>Create `.planning/phases/14-selective-analysis-and-byte-cache/14-07-SUMMARY.md` when complete.</output>
@@ -0,0 +1,87 @@
---
phase: "14"
plan: "08"
type: execute
wave: 7
depends_on:
- "14-03"
- "14-07"
files_modified:
- frontend/src/views/SettingsView.vue
- frontend/src/components/settings/SettingsCloudTab.vue
- frontend/src/components/settings/__tests__/SettingsCloudTab.test.js
- frontend/src/components/settings/__tests__/SettingsCloudTab.health.test.js
- frontend/src/stores/cloudConnections.js
- frontend/src/api/cloud.js
- backend/tests/test_cloud_cache.py
autonomous: true
requirements:
- ANALYZE-04
- ANALYZE-05
- CACHE-04
---
<objective>
Expose Phase 14 user settings for cache limit, progress detail, and default failure behavior in Settings, backed by the cache/settings API and tier-bound validation.
Scope fence: do not change backend cache internals except fixing issues found by Settings integration tests.
</objective>
<context>
@.planning/phases/14-selective-analysis-and-byte-cache/14-CONTEXT.md
@frontend/src/views/SettingsView.vue
@frontend/src/components/settings/SettingsCloudTab.vue
@frontend/src/stores/cloudConnections.js
@backend/api/cloud/cache.py
</context>
<tasks>
<task type="auto">
<name>Task 1: Add Settings API/store wiring</name>
<files>frontend/src/api/cloud.js, frontend/src/stores/cloudConnections.js, frontend/src/stores/__tests__/cloudConnections.analysis.test.js</files>
<read_first>
- frontend/src/api/cloud.js
- frontend/src/stores/cloudConnections.js
- backend/api/cloud/cache.py
</read_first>
<action>
Add client/store methods to load and update cache/settings state. Store tier cap, current usage, preferred limit, progress detail mode, and default failure behavior. Handle validation errors without clearing existing settings.
</action>
<acceptance_criteria>
- Store keeps settings in memory and never browser-stores credentials.
- Invalid cache limit responses surface controlled messages.
- Updated progress/failure settings affect analysis queue label/control behavior.
</acceptance_criteria>
<verify><automated>cd frontend && npm run test -- cloudConnections.analysis.test.js</automated></verify>
</task>
<task type="auto">
<name>Task 2: Add Settings Cloud tab controls</name>
<files>frontend/src/components/settings/SettingsCloudTab.vue, frontend/src/components/settings/__tests__/SettingsCloudTab.test.js, frontend/src/components/settings/__tests__/SettingsCloudTab.health.test.js</files>
<read_first>
- frontend/src/components/settings/SettingsCloudTab.vue
- frontend/src/components/settings/__tests__/SettingsCloudTab.test.js
</read_first>
<action>
Add compact controls for cache limit up to tier maximum, simplified vs detailed analysis progress, and pause-batch vs continue-item failure behavior. Keep the existing connection health/test/reconnect UX intact. Use form controls appropriate to settings: slider/number for bytes, segmented/select controls for modes, and clear validation text.
</action>
<acceptance_criteria>
- Settings fit existing Cloud tab layout without nested cards.
- Existing health/reconnect tests still pass.
- Accessibility labels identify each control.
- No visible explanatory tutorial copy is added beyond concise labels and validation messages.
</acceptance_criteria>
<verify><automated>cd frontend && npm run test -- SettingsCloudTab.test.js SettingsCloudTab.health.test.js</automated></verify>
</task>
</tasks>
<verification>
1. `cd frontend && npm run test -- SettingsCloudTab.test.js SettingsCloudTab.health.test.js cloudConnections.analysis.test.js`
2. `cd backend && pytest -q tests/test_cloud_cache.py -k "settings"`
3. Render Settings at mobile and desktop widths if a dev server is available.
</verification>
<output>Create `.planning/phases/14-selective-analysis-and-byte-cache/14-08-SUMMARY.md` when complete.</output>
@@ -0,0 +1,109 @@
---
phase: "14"
plan: "09"
type: execute
wave: 8
depends_on:
- "14-01"
- "14-02"
- "14-03"
- "14-04"
- "14-05"
- "14-06"
- "14-07"
- "14-08"
files_modified:
- AGENTS.md
- README.md
- SECURITY.md
- backend/main.py
- frontend/package.json
- .planning/ROADMAP.md
- .planning/STATE.md
- .planning/phases/14-selective-analysis-and-byte-cache/14-VALIDATION.md
- .planning/phases/14-selective-analysis-and-byte-cache/14-SECURITY.md
autonomous: true
requirements:
- ANALYZE-01
- ANALYZE-02
- ANALYZE-03
- ANALYZE-04
- ANALYZE-05
- ANALYZE-06
- ANALYZE-07
- CACHE-03
- CACHE-04
- CACHE-05
---
<objective>
Close Phase 14 with documentation, version bump, full verification gates, security evidence, and an atomic commit/push once all implementation plans pass.
Scope fence: do not add new feature behavior here except small fixes required by gate failures.
</objective>
<context>
@AGENTS.md
@README.md
@SECURITY.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/14-selective-analysis-and-byte-cache/14-CONTEXT.md
@.planning/phases/14-selective-analysis-and-byte-cache/14-PATTERNS.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Update docs, versions, roadmap, and closeout artifacts</name>
<files>AGENTS.md, README.md, SECURITY.md, backend/main.py, frontend/package.json, .planning/ROADMAP.md, .planning/STATE.md, .planning/phases/14-selective-analysis-and-byte-cache/14-VALIDATION.md, .planning/phases/14-selective-analysis-and-byte-cache/14-SECURITY.md</files>
<read_first>
- AGENTS.md
- README.md
- SECURITY.md
- backend/main.py
- frontend/package.json
</read_first>
<action>
Update current-state docs for Phase 14 completion, shared module maps for new analysis/cache services and routes, README feature/API/settings documentation, SECURITY threat register and gate evidence, ROADMAP plan checkboxes, and STATE next action. Apply the project version bump rule after Phase 14 completion using `backend/main.py` and `frontend/package.json` as sources of truth.
</action>
<acceptance_criteria>
- Docs describe selective analysis, byte cache, settings, API surface, and alpha/non-public status accurately.
- No secrets or provider item names from live data are included.
- ROADMAP marks Phase 14 complete and Phase 15 next.
- Version numbers are consistent across backend/frontend/docs.
</acceptance_criteria>
</task>
<task type="auto">
<name>Task 2: Run full gates and commit/push</name>
<files>all changed files</files>
<read_first>
- AGENTS.md testing, security, and git protocols
- .planning/phases/14-selective-analysis-and-byte-cache/14-SECURITY.md
</read_first>
<action>
Run focused Phase 14 tests, full backend suite, full frontend suite, `docker compose config --quiet`, Bandit, npm audit, Python dependency audit if local tooling supports Python 3.12, and an executable secret scan (`gitleaks` or `trufflehog`). Fix root-cause failures within scope. Commit and push the Phase 14 closeout only after gates pass or accepted pre-existing/tooling gaps are documented.
</action>
<acceptance_criteria>
- Backend and frontend tests pass with zero Phase 14 failures.
- Security scans report zero new high/critical issues.
- Secret scan reports no new secrets.
- Atomic commit uses the project commit format and is pushed.
</acceptance_criteria>
<verify><automated>docker compose config --quiet</automated></verify>
</task>
</tasks>
<verification>
1. `cd backend && pytest -q`
2. `cd frontend && npm run test`
3. `python3 -m bandit -r backend/ --exclude backend/tests`
4. `cd frontend && npm audit --audit-level=high`
5. `docker compose config --quiet`
6. Run available secret scan and document pre-existing findings only.
</verification>
<output>Create `.planning/phases/14-selective-analysis-and-byte-cache/14-09-SUMMARY.md` and mark Phase 14 complete when all gates pass.</output>
@@ -0,0 +1,93 @@
# Phase 14 Patterns
## Shared Boundaries
- `StorageBrowser.vue` remains the only file browser. Analysis actions, aggregate progress, and expandable queue UI belong there.
- `CloudFolderView.vue` remains a thin data provider. It calls the store/API helpers and refreshes browse state; it does not own browser layout or queue rendering.
- Backend routers translate typed request/response schemas and HTTP status codes only. Service modules own analysis, cache, quota, and idempotency behavior and must not raise `HTTPException`.
- Cloud provider credentials are decrypted only inside route/task provider boundaries. Celery payloads contain IDs and control flags only.
## Status Vocabulary
Durable internal item statuses:
- `queued`
- `downloading`
- `extracting`
- `classifying`
- `indexed`
- `already_current`
- `cancelled`
- `failed`
- `unsupported`
- `stale`
UI label mapping:
- simple default: waiting, working, done, skipped, failed
- detailed setting: queued, downloading, extracting, classifying, indexed, cancelled, failed
Do not let frontend components invent a second status translation. Put API-to-UI translation in the Pinia store or a shared formatter/helper.
## Version Keys
Create one shared helper for cloud analysis version keys. All estimate, enqueue, duplicate-check, cache lookup, and worker paths must call it.
Precedence:
1. `version`
2. `etag`
3. metadata fingerprint from provider item id, size, modified time, content type
4. content hash as an additional post-hydration fact, never as a pre-download requirement
## Cache Lifecycle
1. Resolve owner and item.
2. Compute version key.
3. Reuse non-evicted matching cache entry if present.
4. Otherwise hydrate provider bytes through the mutable/content adapter boundary.
5. Store bytes under a UUID/private MinIO key.
6. Atomically increment user quota by retained size.
7. Pin for active job or preview.
8. Release pin when finished.
9. Evict inactive LRU entries when the user's configured limit or quota pressure requires it.
Eviction failure must not hide successful analysis. It should surface controlled warning state and leave quota/cache metadata consistent.
## Estimate Semantics
Small file jobs may start directly. Folder and connection jobs estimate first when thresholds are crossed, and whole-connection analysis always estimates unless trivially small.
Estimate responses include:
- supported file count
- provider-reported byte total
- unsupported/skipped item count
- whether recursion applies
- whether the estimate is complete or partial
The estimate endpoint must never download bytes.
## Error and Control Semantics
- Batch failure behavior defaults to `pause_batch`.
- `continue_item` pauses only the failed item and keeps later queued items running.
- Per-item retry restarts the full item.
- Per-item skip/cancel affects that item only.
- Batch cancel cancels queued items and requests cooperative cancellation for running work.
- Typed error bodies use controlled `kind` and `reason` fields, matching the Phase 13 mutation response style.
## Test Pattern
Each implementation plan starts with focused red tests for its slice, then implementation, then targeted verification.
Required negative coverage by the end of the phase:
- foreign user cannot estimate, enqueue, read status, cancel, retry, or read cache metadata
- admin cannot access cloud analysis/cache routes
- cache object keys and credentials never appear in responses or audit logs
- unchanged etag/version skips duplicate analysis without byte download
- cached bytes count against quota while retained and decrement after eviction
- active jobs/previews are not evicted
- folder/connection analysis does not mutate provider files
@@ -0,0 +1,129 @@
# Phase 14 Research: Selective Analysis and Byte Cache
**Phase:** 14 - Selective Analysis and Byte Cache
**Prepared:** 2026-06-23
**Status:** Ready for execution planning
## Scope Boundary
Phase 14 adds controlled analysis of provider-owned cloud files and a bounded private byte cache. It does not import cloud files into local `documents`, does not implement unified search, and does not implement provider delta feeds beyond version/fingerprint checks needed to avoid duplicate or stale analysis.
The existing system already provides the correct foundation:
- `CloudItem` stores owner, connection, provider item id, parent, kind, content type, size, etag/version, extracted text, analysis status, semantic status, and topic links without a local `Document`.
- `CloudFolderView` remains a route/store data provider; `StorageBrowser` owns the shared local/cloud browser surface.
- `cloud_tasks.py` and `document_tasks.py` show the accepted Celery sync-to-async bridge and retry sentinel pattern.
- `MinIOBackend` already generates UUID-based private object keys and is the right precedent for temporary cached cloud bytes.
## Recommended Schema Additions
Add a new migration after the current head with owner-scoped tables rather than overloading local `documents`.
### `cloud_byte_cache_entries`
Purpose: track retained cloud bytes in MinIO and make eviction/quota decisions without exposing provider credentials or paths.
Suggested fields:
- `id` UUID primary key
- `user_id` FK users, required
- `connection_id` FK cloud_connections, required
- `cloud_item_id` FK cloud_items, required
- `provider_item_id` text, required snapshot for audit/debugging without joins
- `version_key` text, required, derived from etag/version/fallback fingerprint/content hash
- `object_key` text, required, UUID/private key only
- `content_type` text nullable
- `size_bytes` bigint required
- `content_hash` text nullable, computed only when bytes are already hydrated
- `pin_count` integer required default 0
- `active_job_count` integer required default 0
- `last_accessed_at`, `created_at`, `updated_at`, `evicted_at`
- unique `(user_id, connection_id, cloud_item_id, version_key)`
- indexes on `(user_id, evicted_at, last_accessed_at)` and `(user_id, pin_count, active_job_count, last_accessed_at)`
### `cloud_analysis_jobs`
Purpose: represent user-visible batches for file, selection, folder, or connection analysis.
Suggested fields:
- `id` UUID primary key
- `user_id`, `connection_id`
- `scope_kind`: `file`, `selection`, `folder`, `connection`
- `scope_ref` nullable provider item id or root sentinel
- `recursive` boolean
- `status`: `queued`, `running`, `paused`, `completed`, `cancelled`, `failed`
- aggregate counts: total, queued, downloading, extracting, classifying, indexed, skipped, cancelled, failed, unsupported
- aggregate provider bytes estimate
- `failure_behavior`: `pause_batch` or `continue_item`
- timestamps
### `cloud_analysis_job_items`
Purpose: drive idempotent per-item processing and precise user controls.
Suggested fields:
- `id`, `job_id`, `user_id`, `connection_id`, `cloud_item_id`
- `provider_item_id`, `version_key`, `fingerprint`
- `status`: `queued`, `downloading`, `extracting`, `classifying`, `indexed`, `already_current`, `cancelled`, `failed`, `unsupported`, `stale`
- `error_code`, `error_message` controlled strings only
- `cache_entry_id` nullable
- timestamps and retry counter
- unique `(job_id, cloud_item_id)`
- index `(user_id, cloud_item_id, version_key)` for duplicate/current checks
### User Settings
Prefer explicit columns or a small owner-scoped settings table for:
- `analysis_progress_detail`: `simple` default, `detailed` optional
- `analysis_failure_behavior`: `pause_batch` default, `continue_item` optional
- `cloud_cache_limit_bytes`: user preference capped by tier/admin maximum
If the project already has a settings table at implementation time, extend it rather than creating a second settings authority.
## Version and Fingerprint Rules
Use this precedence for idempotency:
1. Provider `version` when available.
2. Provider `etag` when available.
3. Fallback metadata fingerprint: provider item id, provider size, modified time, content type.
4. Content hash only after bytes are already hydrated for analysis/open/preview.
Never download bytes solely to compute a hash.
## Byte Cache Rules
- Cache bytes only for active open, preview, or analysis work.
- Cached bytes count against `quotas.used_bytes` while retained.
- Quota changes must use the project's existing atomic update pattern.
- Eviction may delete only inactive entries with `pin_count == 0`, `active_job_count == 0`, and no active preview lease.
- Eviction must be per-user LRU and must never delete another user's entries.
- MinIO object keys must remain private UUID keys; provider filenames stay in metadata only.
## Job Execution Rules
- API requests enqueue jobs; Celery workers expand folders/connections and process items.
- Worker broker payloads include only IDs and control flags; credentials are decrypted inside the worker.
- Processing an unchanged cloud item reports `already_current` without provider byte download.
- Retry restarts the whole item from the beginning.
- Cancellation is cooperative: queued work is cancelled immediately, running download/extract/classify checks cancellation between stages and finishes safely if it cannot interrupt.
- If provider metadata changes during analysis, finish the job safely, compare final version/fingerprint, and mark the result stale rather than mutating the provider item.
## Frontend Rules
- Add analysis actions to `StorageBrowser` row actions and toolbar.
- `CloudFolderView` only maps route/store/API state and handles emitted events.
- Use an aggregate indicator plus expandable item list.
- Simplified progress labels are default; detailed labels are exposed from Settings.
- The analysis queue can reuse the existing upload queue interaction pattern, but it must be a distinct queue model because controls and statuses differ.
## Security Notes
- Admins remain blocked by `get_regular_user`.
- All analysis/cache routes must resolve `(current_user.id, connection_id, provider_item_id/cloud_item_id)` before taking action.
- Responses never include credentials, raw provider URLs, MinIO object keys, extracted text beyond explicitly authorized analysis/search surfaces, or provider error payloads.
- Audit logs contain metadata only: connection id, provider item id, cloud item id, action/status, count/byte totals where needed.