shared module map documents the shared detail surface
DocumentDetailSurface
from
to
via
pattern
backend/main.py
frontend/package.json
version strings match
version
Close out Phase 14.1: run the full backend + frontend test suites, run the mandatory security gate (owner/admin negatives, credential/object_key/provider-URL leakage scan, dependency + secret audits), update CLAUDE.md and README for the cloud detail parity surface, bump the app version per protocol, and commit/push atomically.
Purpose: Satisfies the Mandatory Cross-Cutting Gates (tests pass, security gate, dependency audits, docs/version updates, atomic commit) and the CLAUDE.md Documentation/Testing/Security/Git protocols before Phase 14.1 is marked complete. This is the only plan that touches docs and versions (no implementation logic).
Output: Green full suites, passed security gate, updated CLAUDE.md/README, bumped version, one atomic commit pushed.
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/14.1-cloud-local-file-parity-hardening/14.1-CONTEXT.md
@.planning/phases/14.1-cloud-local-file-parity-hardening/14.1-RESEARCH.md
@CLAUDE.md
@README.md
@backend/main.py
@frontend/package.json
Task 1: Full test suites + security gate + dependency/secret audits
- CLAUDE.md (Testing Protocol, Security Protocol, Security gate checklist — the exact gate commands)
- backend/tests/test_cloud_security.py (owner/admin/no-leak coverage that must include the new detail endpoint and force re-analyze)
- backend/tests/test_cloud_detail_parity.py and backend/tests/test_cloud_reanalyze_force.py (Plan 01 suites — must be GREEN now)
- frontend/src/views/__tests__/CloudDetailParity.test.js and frontend/src/components/storage/__tests__/StorageBrowser.parity.test.js (Plan 01 frontend suites — must be GREEN now)
- .planning/phases/14.1-cloud-local-file-parity-hardening/14.1-RESEARCH.md (Security Domain ASVS V4/V8/V12 targets; Package Legitimacy Audit: no new packages)
Run the full backend suite (cd backend && python -m pytest -v) and the full frontend suite (cd frontend && npm run test or npx vitest run) — both MUST pass with zero failures; fix any regressions introduced by Plans 02-04 at root cause (≤50 lines per fix per CLAUDE.md; larger means a separate plan). Run the security gate per the CLAUDE.md Security gate checklist: bandit -r backend/ (zero HIGH), pip audit (zero critical/high), npm audit --audit-level=high (zero high/critical). Verify the cloud detail endpoint and force re-analyze path are covered by owner/admin-negative and no-leak assertions — if test_cloud_security.py does not yet exercise the new detail route and force enqueue, add focused negative tests there (foreign user 404, admin 403, response excludes credentials/object_key/provider URL). Run an executable secret scan over the diff (the repo's existing secret-scan approach, e.g. trufflehog/git secrets if configured) and confirm no credentials, tokens, provider URLs, or object keys are present in code, tests, or planning artifacts. Confirm no provider bytes are downloaded during browse/detail/estimate (the metadata-only invariant) by confirming the relevant cache/analysis contract tests pass. Do NOT install new packages (RESEARCH: none required) — if any audit flags an existing CVE, fix by version bump in a separate chore commit before this closeout commit.
cd backend && python -m pytest -q 2>&1 | tail -8 && bandit -r backend/ -lll 2>&1 | tail -5 && cd ../frontend && npx vitest run 2>&1 | tail -8 && npm audit --audit-level=high 2>&1 | tail -5
- Backend full suite: `cd backend && python -m pytest -q` reports 0 failed.
- Frontend full suite: `cd frontend && npx vitest run` reports 0 failed.
- bandit -r backend/ reports 0 HIGH severity findings.
- npm audit --audit-level=high reports 0 high/critical vulnerabilities.
- test_cloud_security.py (or test_cloud_detail_parity.py) includes the detail-endpoint and force-enqueue owner/admin/no-leak negatives: `grep -nE 'detail|force' backend/tests/test_cloud_security.py backend/tests/test_cloud_detail_parity.py` shows coverage.
- No secrets/object keys/provider URLs in the diff (secret scan clean).
Full backend + frontend suites pass; bandit/pip/npm audits clean; detail + force re-analyze covered by owner/admin/no-leak negatives; secret scan clean.
Checkpoint: Human verification of cloud/local file parity
Human verifies the cloud detail view, browser row parity, force re-analyze confirmation, and unsupported-preview-keeps-download behavior against a running app. See what-built and how-to-verify below.
Cloud/local file parity: a cloud detail view (route cloud-file-detail) backed by CloudItem, shared DocumentDetailSurface used by local + cloud detail, browser row parity (topics + analysis status + Re-analyze/Retry slots), force re-analyze with confirmation, and unsupported-preview-keeps-download-explicit behavior.
1. Start the app: `docker compose up` (or backend `uvicorn main:app --reload` + frontend `npm run dev`).
2. Log in, open /cloud, navigate into a connected provider folder.
3. Click a cloud file row — confirm it opens a DETAIL view (URL contains /cloud/.../item/...), NOT an immediate preview or download.
4. On an un-analyzed cloud file: confirm the detail shows "No analysis yet" + an "Analyze file" action; trigger Analyze and watch status progress.
5. On an analyzed cloud file: confirm extracted text, topic badges, analysis status, and a "Re-analyze" action appear (NO "Re-classify" text anywhere).
6. Click Re-analyze on a current file: confirm a confirmation dialog appears ("Re-analyze this file? Existing extracted text and topics stay visible…") and proceeding re-runs analysis without losing prior text/topics.
7. On a file whose preview is unsupported: confirm "Preview unavailable" + reason shows and Download stays active and does NOT auto-download.
8. Open a LOCAL document at /document/:id and confirm the detail layout (header, topics, extracted text, Re-analyze) matches the cloud detail layout.
9. In the browser grid, confirm cloud rows show topic badges + analysis status in the same place as local rows.
Type "approved" or describe any parity/behavior issues to fix
Task 2: Update CLAUDE.md + README, bump version, atomic commit + push
- CLAUDE.md (Current state line in GSD Workflow section; shared module map tables backend + frontend; Documentation Protocol; Git Protocol; version bump rule)
- README.md (Features section, env var table, version reference)
- backend/main.py (FastAPI version="0.4.0")
- frontend/package.json ("version": "0.4.0")
- .planning/ROADMAP.md (Phase 14.1 plan checklist to tick)
Update CLAUDE.md: change the "Current state" line in the GSD Workflow section to record Phase 14.1 complete (cloud/local file parity: cloud detail route + view, shared DocumentDetailSurface, browser row parity, force re-analyze, unsupported-preview keeps download explicit). Add to the FRONTEND shared module map a row for frontend/src/components/storage/DocumentDetailSurface.vue (shared detail surface used by DocumentView and CloudDetailView) and note CloudDetailView.vue + the cloud-file-detail route as thin data providers. Add to the BACKEND shared module map the CloudItemDetailOut schema and resolve_owned_cloud_item_detail (owner-scoped cloud detail + topics, metadata-only), the GET .../items/{id}/detail route, and the force flag on enqueue. Add non-negotiable rules: visible copy says "Re-analyze" not "Re-classify"; cloud row click opens the cloud detail route (no auto preview/download); cloud detail resolution is metadata-only (no byte hydration); CloudItemDetailOut/CloudItemOut remain allowlists excluding object_key/credentials_enc/provider URL. Update README.md if any user-facing feature/route/behavior changed (add cloud file detail view + Re-analyze to the Features section; no new env vars expected). Bump the version: per CLAUDE.md protocol, Phase 14.1 is an inserted hardening phase shipping user-facing changes — bump the PATCH segment in backend/main.py (version="0.4.0" → "0.4.1") and frontend/package.json ("0.4.0" → "0.4.1") so both match. Tick the Phase 14.1 plan checkboxes in ROADMAP.md. Stage explicitly and commit atomically per CLAUDE.md Git Protocol: `git add backend/ frontend/ CLAUDE.md README.md .planning/` then commit `feat(14.1): cloud/local file parity — shared detail surface, cloud detail route, force re-analyze`, then push. Do NOT use git add -A.
cd backend && grep -c 'version="0.4.1"' main.py && cd ../frontend && grep -c '"version": "0.4.1"' package.json && cd .. && grep -c 'DocumentDetailSurface' CLAUDE.md && grep -c 'Phase 14.1' CLAUDE.md
- backend/main.py version is "0.4.1": `grep -c 'version="0.4.1"' backend/main.py` returns 1.
- frontend/package.json version is "0.4.1": `grep -c '"version": "0.4.1"' frontend/package.json` returns 1.
- CLAUDE.md documents the shared surface and phase completion: `grep -c 'DocumentDetailSurface' CLAUDE.md` >= 1 and the Current state line references Phase 14.1.
- CLAUDE.md adds the cloud detail backend symbols: `grep -cE 'CloudItemDetailOut|resolve_owned_cloud_item_detail' CLAUDE.md` >= 1.
- ROADMAP Phase 14.1 plans are checked off and a single atomic commit exists: `git log --oneline -1` shows the feat(14.1) message.
- The commit is pushed (git status shows clean / ahead-by-0 after push).
CLAUDE.md + README updated, both versions bumped to 0.4.1, ROADMAP ticked, one atomic feat(14.1) commit created and pushed.
<threat_model>
Trust Boundaries
Boundary
Description
diff → repo
committed code/tests/docs must contain no secrets, tokens, provider URLs, or object keys
dependency tree → app
audits must show no high/critical CVEs
STRIDE Threat Register
Threat ID
Category
Component
Disposition
Mitigation Plan
T-14.1-13
Information Disclosure
committed artifacts
mitigate
Secret scan over diff; no credentials/object_key/provider URL in code/tests/planning
T-14.1-14
Tampering / Vulnerable deps
dependency tree
mitigate
bandit + pip audit + npm audit gate; no new packages added
T-14.1-15
Elevation of Privilege
detail + force endpoints (regression)
mitigate
Security gate re-runs owner/admin negatives on the new surfaces
T-14.1-SC
Tampering
npm/pip installs
accept
No package installs this phase (RESEARCH Package Legitimacy Audit: none)