--- phase: "13" plan: "08" type: execute wave: 5 depends_on: - "13-03" - "13-04" - "13-06" files_modified: - backend/api/cloud/operations.py - backend/api/cloud/schemas.py - backend/services/cloud_operations.py - backend/services/cloud_items.py - backend/storage/google_drive_backend.py - backend/storage/onedrive_backend.py - backend/storage/webdav_backend.py - backend/tests/test_cloud_mutations.py - backend/tests/test_cloud_backends.py - backend/tests/test_cloud_provider_contract.py autonomous: true requirements: - CLOUD-04 - CLOUD-05 - CLOUD-09 must_haves: truths: - "Create-folder and rename collisions auto-suffix human-readable counters with bounded retry." - "Stale create or rename targets stop, refresh the affected folder, and return typed retry guidance instead of forcing the mutation." - "Successful create and rename operations preserve stable cloud item identity through centralized reconciliation." artifacts: - path: "backend/api/cloud/operations.py" provides: "Create-folder and rename endpoints with typed collision and stale-result bodies." - path: "backend/services/cloud_operations.py" provides: "Create-folder and rename orchestration with bounded retry and reconcile-on-success behavior." key_links: - from: "create-folder and rename provider result" to: "cloud_items stable row identity" via: "centralized post-mutation reconciliation" pattern: "parent_ref" --- Implement the bounded backend create-folder and rename slice of Phase 13: collision-safe naming, stale guards, bounded retry, and stable-identity reconciliation for successful results. Purpose: Deliver `CLOUD-04` and `CLOUD-05` without mixing move or delete semantics into the same plan. Output: Passing backend create-folder and rename mutation suites with centralized reconciliation intact. @$HOME/.codex/gsd-core/workflows/execute-plan.md @$HOME/.codex/gsd-core/templates/summary.md @AGENTS.md @.planning/phases/13-virtual-local-cloud-operations/13-CONTEXT.md @.planning/phases/13-virtual-local-cloud-operations/13-RESEARCH.md @backend/api/cloud/operations.py @backend/services/cloud_operations.py @backend/services/cloud_items.py @backend/storage/google_drive_backend.py @backend/storage/onedrive_backend.py @backend/storage/webdav_backend.py ## Artifacts this phase produces - Create-folder and rename support in the operations router and cloud operations service. - Four-provider collision, bounded-retry, and stale-result normalization through Google Drive, OneDrive, Nextcloud-via-WebDAV, and generic WebDAV. - Passing create-folder and rename backend, provider-contract, and mutation suites. ## Pattern analogs - `backend/api/folders.py` — local create and rename handler structure. - `backend/services/cloud_items.py` — stable identity and freshness reconciliation behavior. - `backend/tests/test_cloud_backends.py` and `backend/tests/test_cloud_provider_contract.py` — provider normalization assertions. Task 1: Implement create-folder and rename semantics with bounded collision retries and stale guards backend/api/cloud/operations.py, backend/api/cloud/schemas.py, backend/services/cloud_operations.py, backend/storage/google_drive_backend.py, backend/storage/onedrive_backend.py, backend/storage/webdav_backend.py, backend/tests/test_cloud_mutations.py, backend/tests/test_cloud_backends.py, backend/tests/test_cloud_provider_contract.py - backend/api/folders.py - backend/storage/google_drive_backend.py - backend/storage/onedrive_backend.py - backend/storage/webdav_backend.py - backend/tests/test_cloud_mutations.py - .planning/phases/13-virtual-local-cloud-operations/13-CONTEXT.md - Test 1: create-folder and rename choose `Name (n)` counters and retry within a bounded window after concurrent collisions - Test 2: stale version or etag mismatches stop the mutation, refresh the folder, and return a typed retry-needed result - Test 3: provider differences normalize behind one shared contract Implement D-05 through D-07 for create-folder and rename. Use the shared mutable-operation contract to normalize collision detection, bounded retry, and stale precondition failure behavior across Google Drive, OneDrive, and the shared WebDAV path. Keep counter insertion human-readable and before the file extension for files, and keep Nextcloud on the shared WebDAV mutation path unless a narrow override is unavoidable. - create-folder and rename suites pass across provider-contract and backend mutation coverage - stale mismatches return typed retry-needed results after refresh rather than forcing the mutation - no provider writes `cloud_items` directly or bypasses the shared contract docker compose run --rm backend pytest -v tests/test_cloud_mutations.py tests/test_cloud_backends.py tests/test_cloud_provider_contract.py -k "create or rename or stale" -x Create-folder and rename now satisfy the bounded collision and stale-safety rules. Task 2: Reconcile successful create-folder and rename results through stable item identity backend/services/cloud_operations.py, backend/services/cloud_items.py, backend/tests/test_cloud_mutations.py - backend/services/cloud_operations.py - backend/services/cloud_items.py - backend/tests/test_cloud_mutations.py - .planning/phases/13-virtual-local-cloud-operations/13-CONTEXT.md - Test 1: successful create-folder and rename update navigation through centralized reconciliation before success returns - Test 2: stable cloud item identity is preserved instead of creating duplicate rows - Test 3: refresh guidance remains typed and tied to the service layer rather than provider-specific router branches Route successful create-folder and rename results back through `backend/services/cloud_items.py` so stable row identity, parent relationships, and folder freshness stay authoritative before the API returns success. Keep the route layer thin, keep typed stale-retry guidance service-owned, and do not introduce a second reconciliation path for create or rename. - create-folder and rename mutation suites pass with reconcile-before-return behavior - stable row identity is preserved across successful create-folder and rename operations - centralized reconciliation remains the only metadata write path docker compose run --rm backend pytest -v tests/test_cloud_mutations.py -k "create or rename" -x Create-folder and rename success now satisfy the stable-identity half of `CLOUD-09`. ## Trust Boundaries | Boundary | Description | |----------|-------------| | proposed new name → provider mutation | User-supplied names must be collision-safe, stale-safe, and provider-neutral before mutation. | | mutation success → metadata state | Only authoritative success may update cloud metadata and folder freshness. | ## STRIDE Threat Register | Threat ID | Category | Component | Disposition | Mitigation Plan | |-----------|----------|-----------|-------------|-----------------| | T-13-24 | T | collision handling | mitigate | Mutation and provider-contract suites require bounded retry and forbid silent overwrite behavior. | | T-13-25 | T | stale mutation safety | mitigate | Stale guards refresh and require retry instead of forcing create-folder or rename. | | T-13-26 | T | identity reconciliation | mitigate | Successful create-folder and rename must flow back through `cloud_items.py` to preserve stable row identity. | - Pass the create-folder and rename backend and provider-contract suites. - Confirm every backend pytest invocation is a direct `docker compose run --rm backend pytest ...` command. - Confirm create-folder and rename remain separated from move and delete work in both files touched and task scope. - The backend fully supports `CLOUD-04` and `CLOUD-05` with bounded collision and stale-safety semantics. - Successful create-folder and rename results refresh navigation through centralized reconciliation. - This bounded plan stays at 10 files and does not absorb move or delete behavior. Create `.planning/phases/13-virtual-local-cloud-operations/13-08-SUMMARY.md` when done