9.0 KiB
phase, plan, subsystem, status, tags, dependency_graph, tech_stack, key_files, decisions, metrics
| phase | plan | subsystem | status | tags | dependency_graph | tech_stack | key_files | decisions | metrics | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 13 | 09 | cloud-operations | complete |
|
|
|
|
|
|
Phase 13 Plan 09: Move and Delete — Validation, Reconciliation, and Audit Summary
One-liner: Move descendant-safety, stale guard, and reconcile-before-return; delete folder disclosure and metadata-only audit rows for both move and delete.
Tasks Completed
| Task | Name | Commit | Key Files |
|---|---|---|---|
| 1 (RED) | Add failing tests for move stale-guard, descendant safety, reconciliation, and delete/audit | af7d45f |
test_cloud_mutations.py |
| 1/2 (GREEN) | Implement move/delete with stale guards, reconciliation, disclosure, and audit | 508d276 |
api/cloud/operations.py, test_cloud_audit.py |
What Was Built
Task 1: Move — Descendant Safety, Stale Guard, Centralized Reconciliation
_is_descendant_destination() helper in backend/api/cloud/operations.py:
New async helper that walks the ancestor chain of a proposed destination through cloud_items metadata:
while current_ref is not None:
if current_ref == source_item_id:
return True # destination is a descendant of source
# look up parent of current_ref via CloudItem.parent_ref
current_ref = parent_item.parent_ref if parent_item else None
- D-09: Backend independently rejects descendant destinations without provider involvement
- Protection against cycles via a visited-set guard
move_cloud_item in backend/api/cloud/operations.py:
Comprehensive move implementation:
- D-08 Cross-connection rejection — before any adapter call (unchanged)
- D-09 Self-destination rejection — before any adapter call (unchanged)
- D-09 Descendant destination rejection — metadata-only ancestor-chain walk before adapter call
- Pre-fetch item metadata — resolves
source_parent_ref,item_kind,item_namebefore adapter - D-07 Stale guard — stale adapter result marks source folder non-fresh, returns typed stale body
- Reconcile-before-return on success:
upsert_cloud_itemwithparent_ref=resolved_dest_parent_refupdate_folder_statefor source folder (item removed)update_folder_statefor destination folder (item added)write_audit_logcloud.item_movedwith metadata-only payloadsession.commit()
Task 2: Delete — Folder Disclosure and Metadata-Only Audit
delete_cloud_item in backend/api/cloud/operations.py:
- Pre-fetch item metadata — resolves
item_kindanditem_parent_refbefore adapter call - D-10 Folder disclosure — response includes
is_folderanditem_kindfor frontend to display stronger folder-delete warning - Reconcile-before-return on success:
update_folder_statefor parent folder (item removed)write_audit_logcloud.item_deletedwithdelete_kind,item_kind,provider_item_idsession.commit()
- D-11 Trash vs permanent —
delete_kindin audit metadata and responsereasondistinguish trashed vs permanent delete
Success response now includes:
{
"kind": "deleted",
"reason": "trashed", # or "permanent"
"provider_item_id": "...",
"item_kind": "folder", # D-10 disclosure
"is_folder": True, # D-10 stronger confirmation
}
Test Suite Results
766 passed, 17 skipped, 4 deselected, 10 xfailed, 55 warnings
Previous baseline (Plan 08): 755 passed, 17 skipped, 4 deselected, 12 xfailed
- 11 new tests added in
test_cloud_mutations.py(all pass) - 2 xfail markers promoted in
test_cloud_audit.py(move + delete audit tests now pass) - Net: +11 passing, -2 xfailed = 766 total passing
Deviations from Plan
Auto-fixed Issues
1. [Rule 1 - Bug] Audit tests in test_cloud_audit.py needed mock adapters
- Found during: Task 2 (GREEN verification)
- Issue:
test_move_success_writes_audit_rowandtest_delete_success_writes_audit_rowwere promoted from xfail but used real connections without mock adapters — provider calls returned 503 which was not in the accepted status codes - Fix: Added explicit mock adapters with
build_mutable_cloud_adapterpatch so tests exercise the audit write path deterministically - Files modified:
backend/tests/test_cloud_audit.py - Commit:
508d276(included in GREEN commit)
Known Stubs
None. Move and delete reconciliation are fully functional, including stale guards, descendant safety, and metadata-only audit rows.
Threat Flags
No new security surfaces introduced. T-13-27, T-13-28, T-13-29 are mitigated:
- T-13-27 (move destinations): Descendant-chain walk + self-check + cross-connection check enforce D-08 and D-09 before and independently of provider submission.
- T-13-28 (stale move safety): Stale guard stops move, refreshes source folder, requires retry — never forcing a stale move.
- T-13-29 (delete disclosure and audit): Typed delete results carry
is_folder/item_kind; audit tests verify no token or byte appears inmetadata_.
Self-Check: PASSED
- FOUND:
backend/api/cloud/operations.pywith_is_descendant_destination, move stale guard, move/delete reconcile-before-return, and move/delete audit writes - FOUND:
backend/tests/test_cloud_mutations.pywith 11 new behavioral tests - FOUND:
backend/tests/test_cloud_audit.pywith promoted move/delete xfail markers and mock adapters - FOUND commit:
af7d45f(RED tests) - FOUND commit:
508d276(GREEN implementation) - Full suite: 766 passed, 17 skipped, 4 deselected, 10 xfailed