pushframe 5.0.3__tar.gz → 5.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (381) hide show
  1. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/MILESTONES.md +25 -0
  2. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/PROJECT.md +2 -0
  3. pushframe-5.0.4/.planning/REQUIREMENTS.md +118 -0
  4. pushframe-5.0.4/.planning/ROADMAP.md +105 -0
  5. pushframe-5.0.4/.planning/STATE.md +22 -0
  6. pushframe-5.0.3/.planning/REQUIREMENTS.md → pushframe-5.0.4/.planning/milestones/v5.0-REQUIREMENTS.md +9 -0
  7. pushframe-5.0.4/.planning/state.json +32 -0
  8. {pushframe-5.0.3 → pushframe-5.0.4}/CHANGELOG.md +47 -1
  9. {pushframe-5.0.3 → pushframe-5.0.4}/PKG-INFO +1 -1
  10. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/__init__.py +1 -1
  11. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/cli.py +4 -6
  12. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/google/bootstrap.py +61 -8
  13. {pushframe-5.0.3 → pushframe-5.0.4}/pyproject.toml +1 -1
  14. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_cli_google_link.py +32 -7
  15. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_version.py +2 -2
  16. {pushframe-5.0.3 → pushframe-5.0.4}/uv.lock +1 -1
  17. pushframe-5.0.3/.planning/STATE.md +0 -168
  18. pushframe-5.0.3/.planning/state.json +0 -28
  19. {pushframe-5.0.3 → pushframe-5.0.4}/.env.sample +0 -0
  20. {pushframe-5.0.3 → pushframe-5.0.4}/.freebuff/project-id +0 -0
  21. {pushframe-5.0.3 → pushframe-5.0.4}/.github/workflows/release.yml +0 -0
  22. {pushframe-5.0.3 → pushframe-5.0.4}/.github/workflows/tests.yml +0 -0
  23. {pushframe-5.0.3 → pushframe-5.0.4}/.gitignore +0 -0
  24. {pushframe-5.0.3 → pushframe-5.0.4}/.gsd/dispatch-isolation-sentinel.json +0 -0
  25. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/RETROSPECTIVE.md +0 -0
  26. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/WINDOWS.md +0 -0
  27. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/codebase/ARCHITECTURE.md +0 -0
  28. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/codebase/CONCERNS.md +0 -0
  29. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/codebase/CONVENTIONS.md +0 -0
  30. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/codebase/INTEGRATIONS.md +0 -0
  31. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/codebase/STACK.md +0 -0
  32. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/codebase/STRUCTURE.md +0 -0
  33. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/codebase/TESTING.md +0 -0
  34. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/config.json +0 -0
  35. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/debug/knowledge-base.md +0 -0
  36. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/debug/login-475-null-creds.md +0 -0
  37. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/debug/resolved/cli-status-verbose-logging.md +0 -0
  38. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/debug/resolved/inspect-asset-null-fields.md +0 -0
  39. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/debug/resolved/select-asset-401-unauthorized.md +0 -0
  40. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-REQUIREMENTS.md +0 -0
  41. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-ROADMAP.md +0 -0
  42. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/01-toolchain-revival/01-01-PLAN.md +0 -0
  43. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/01-toolchain-revival/01-01-SUMMARY.md +0 -0
  44. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/01-toolchain-revival/01-02-PLAN.md +0 -0
  45. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/01-toolchain-revival/01-02-SUMMARY.md +0 -0
  46. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/01-toolchain-revival/01-CONTEXT.md +0 -0
  47. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/01-toolchain-revival/01-DISCUSSION-LOG.md +0 -0
  48. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/01-toolchain-revival/01-PATTERNS.md +0 -0
  49. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/01-toolchain-revival/01-RESEARCH.md +0 -0
  50. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/01-toolchain-revival/01-REVIEW.md +0 -0
  51. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/01-toolchain-revival/01-VERIFICATION.md +0 -0
  52. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/02-live-read-path-verification/02-01-PLAN.md +0 -0
  53. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/02-live-read-path-verification/02-01-SUMMARY.md +0 -0
  54. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/02-live-read-path-verification/02-02-PLAN.md +0 -0
  55. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/02-live-read-path-verification/02-02-SUMMARY.md +0 -0
  56. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/02-live-read-path-verification/02-CONTEXT.md +0 -0
  57. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/02-live-read-path-verification/02-DISCUSSION-LOG.md +0 -0
  58. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/02-live-read-path-verification/02-LIVE-EVIDENCE.md +0 -0
  59. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/02-live-read-path-verification/02-PATTERNS.md +0 -0
  60. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/02-live-read-path-verification/02-RESEARCH.md +0 -0
  61. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/02-live-read-path-verification/02-REVIEW.md +0 -0
  62. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/02-live-read-path-verification/02-VERIFICATION.md +0 -0
  63. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/03-run-docs-verification-report/03-01-PLAN.md +0 -0
  64. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/03-run-docs-verification-report/03-01-SUMMARY.md +0 -0
  65. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/03-run-docs-verification-report/03-CONTEXT.md +0 -0
  66. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/03-run-docs-verification-report/03-DISCUSSION-LOG.md +0 -0
  67. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/03-run-docs-verification-report/03-PATTERNS.md +0 -0
  68. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/03-run-docs-verification-report/03-RESEARCH.md +0 -0
  69. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/03-run-docs-verification-report/03-REVIEW.md +0 -0
  70. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.0-phases/03-run-docs-verification-report/03-VERIFICATION.md +0 -0
  71. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.1-ROADMAP.md +0 -0
  72. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.1-phases/04-client-transport-seam-for-offline-testability/.gitkeep +0 -0
  73. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.1-phases/04-client-transport-seam-for-offline-testability/04-01-PLAN.md +0 -0
  74. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.1-phases/04-client-transport-seam-for-offline-testability/04-01-SUMMARY.md +0 -0
  75. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.1-phases/04-client-transport-seam-for-offline-testability/04-02-PLAN.md +0 -0
  76. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.1-phases/04-client-transport-seam-for-offline-testability/04-02-SUMMARY.md +0 -0
  77. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.1-phases/04-client-transport-seam-for-offline-testability/04-03-PLAN.md +0 -0
  78. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.1-phases/04-client-transport-seam-for-offline-testability/04-03-SUMMARY.md +0 -0
  79. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.1-phases/04-client-transport-seam-for-offline-testability/04-PATTERNS.md +0 -0
  80. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.1-phases/04-client-transport-seam-for-offline-testability/04-RESEARCH.md +0 -0
  81. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.1-phases/04-client-transport-seam-for-offline-testability/04-REVIEW.md +0 -0
  82. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.1-phases/04-client-transport-seam-for-offline-testability/04-SECURITY.md +0 -0
  83. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.1-phases/04-client-transport-seam-for-offline-testability/04-UAT.md +0 -0
  84. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v1.1-phases/04-client-transport-seam-for-offline-testability/04-VERIFICATION.md +0 -0
  85. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-REQUIREMENTS.md +0 -0
  86. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-ROADMAP.md +0 -0
  87. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/05-cli-skeleton-status/05-01-PLAN.md +0 -0
  88. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/05-cli-skeleton-status/05-01-SUMMARY.md +0 -0
  89. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/05-cli-skeleton-status/05-02-PLAN.md +0 -0
  90. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/05-cli-skeleton-status/05-02-SUMMARY.md +0 -0
  91. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/05-cli-skeleton-status/05-CONTEXT.md +0 -0
  92. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/05-cli-skeleton-status/05-DISCUSSION-LOG.md +0 -0
  93. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/05-cli-skeleton-status/05-PATTERNS.md +0 -0
  94. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/05-cli-skeleton-status/05-REVIEW.md +0 -0
  95. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/05-cli-skeleton-status/05-SECURITY.md +0 -0
  96. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/05-cli-skeleton-status/05-UAT.md +0 -0
  97. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/05-cli-skeleton-status/05-VERIFICATION.md +0 -0
  98. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/06-inspect-frame-resolution/06-01-PLAN.md +0 -0
  99. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/06-inspect-frame-resolution/06-01-SUMMARY.md +0 -0
  100. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/06-inspect-frame-resolution/06-02-PLAN.md +0 -0
  101. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/06-inspect-frame-resolution/06-02-SUMMARY.md +0 -0
  102. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/06-inspect-frame-resolution/06-CONTEXT.md +0 -0
  103. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/06-inspect-frame-resolution/06-DISCUSSION-LOG.md +0 -0
  104. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/06-inspect-frame-resolution/06-PATTERNS.md +0 -0
  105. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/06-inspect-frame-resolution/06-RESEARCH.md +0 -0
  106. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/06-inspect-frame-resolution/06-REVIEW.md +0 -0
  107. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/06-inspect-frame-resolution/06-SECURITY.md +0 -0
  108. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/06-inspect-frame-resolution/06-VERIFICATION.md +0 -0
  109. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/07-sync-diffing-engine-dry-run-only/07-01-PLAN.md +0 -0
  110. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/07-sync-diffing-engine-dry-run-only/07-01-SUMMARY.md +0 -0
  111. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/07-sync-diffing-engine-dry-run-only/07-02-PLAN.md +0 -0
  112. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/07-sync-diffing-engine-dry-run-only/07-02-SUMMARY.md +0 -0
  113. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/07-sync-diffing-engine-dry-run-only/07-03-PLAN.md +0 -0
  114. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/07-sync-diffing-engine-dry-run-only/07-03-SUMMARY.md +0 -0
  115. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/07-sync-diffing-engine-dry-run-only/07-CONTEXT.md +0 -0
  116. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/07-sync-diffing-engine-dry-run-only/07-DISCUSSION-LOG.md +0 -0
  117. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/07-sync-diffing-engine-dry-run-only/07-PATTERNS.md +0 -0
  118. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/07-sync-diffing-engine-dry-run-only/07-REVIEW-FIX.md +0 -0
  119. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/07-sync-diffing-engine-dry-run-only/07-REVIEW.md +0 -0
  120. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/07-sync-diffing-engine-dry-run-only/07-SECURITY.md +0 -0
  121. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/07-sync-diffing-engine-dry-run-only/07-VERIFICATION.md +0 -0
  122. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-01-PLAN.md +0 -0
  123. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-01-SUMMARY.md +0 -0
  124. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-02-PLAN.md +0 -0
  125. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-02-SUMMARY.md +0 -0
  126. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-03-PLAN.md +0 -0
  127. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-03-SUMMARY.md +0 -0
  128. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-04-PLAN.md +0 -0
  129. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-04-SUMMARY.md +0 -0
  130. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-CONTEXT.md +0 -0
  131. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-DISCUSSION-LOG.md +0 -0
  132. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-LIVE-FINDINGS.md +0 -0
  133. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-PATTERNS.md +0 -0
  134. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-RESEARCH.md +0 -0
  135. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-REVIEW-FIX.md +0 -0
  136. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-REVIEW.md +0 -0
  137. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/08-destructive-execution-upload-delete-verification/08-VERIFICATION.md +0 -0
  138. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/09-proactive-write-rate-limiter-geo-guard/.gitkeep +0 -0
  139. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/09-proactive-write-rate-limiter-geo-guard/09-01-PLAN.md +0 -0
  140. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/09-proactive-write-rate-limiter-geo-guard/09-01-SUMMARY.md +0 -0
  141. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/09-proactive-write-rate-limiter-geo-guard/09-02-PLAN.md +0 -0
  142. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/09-proactive-write-rate-limiter-geo-guard/09-02-SUMMARY.md +0 -0
  143. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/09-proactive-write-rate-limiter-geo-guard/09-CONTEXT.md +0 -0
  144. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/09-proactive-write-rate-limiter-geo-guard/09-RESEARCH.md +0 -0
  145. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/09-proactive-write-rate-limiter-geo-guard/09-REVIEW-FIX.md +0 -0
  146. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/09-proactive-write-rate-limiter-geo-guard/09-REVIEW.md +0 -0
  147. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/09-proactive-write-rate-limiter-geo-guard/09-VERIFICATION.md +0 -0
  148. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/.gitkeep +0 -0
  149. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-01-PLAN.md +0 -0
  150. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-01-SUMMARY.md +0 -0
  151. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-02-PLAN.md +0 -0
  152. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-02-SUMMARY.md +0 -0
  153. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-03-PLAN.md +0 -0
  154. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-03-SUMMARY.md +0 -0
  155. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-04-PLAN.md +0 -0
  156. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-04-SUMMARY.md +0 -0
  157. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-CONTEXT.md +0 -0
  158. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-DISCUSSION-LOG.md +0 -0
  159. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-LIVE-FINDINGS.md +0 -0
  160. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-PATTERNS.md +0 -0
  161. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-RESEARCH.md +0 -0
  162. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-SECURITY.md +0 -0
  163. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-UAT.md +0 -0
  164. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/10-VERIFICATION.md +0 -0
  165. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-phases/10-hide-instead-of-delete-sync-mode/COVERAGE.md +0 -0
  166. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-quick/260630-qs8-make-main-py-load-a-local-env-file-at-st/260630-qs8-PLAN.md +0 -0
  167. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-quick/260630-qs8-make-main-py-load-a-local-env-file-at-st/260630-qs8-SUMMARY.md +0 -0
  168. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-quick/260708-dt9-add-progress-feedback-to-aura-cli-sync-a/260708-dt9-PLAN.md +0 -0
  169. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-quick/260708-dt9-add-progress-feedback-to-aura-cli-sync-a/260708-dt9-SUMMARY.md +0 -0
  170. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-quick/260708-dt9-add-progress-feedback-to-aura-cli-sync-a/deferred-items.md +0 -0
  171. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-quick/260708-fyr-batch-refactor-of-sync-apply-write-path-/260708-fyr-PLAN.md +0 -0
  172. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-quick/260708-fyr-batch-refactor-of-sync-apply-write-path-/260708-fyr-SUMMARY.md +0 -0
  173. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-quick/260708-fyr-batch-refactor-of-sync-apply-write-path-/260708-fyr-VERIFICATION.md +0 -0
  174. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v2.0-quick/README.md +0 -0
  175. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-REQUIREMENTS.md +0 -0
  176. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-ROADMAP.md +0 -0
  177. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-01-PLAN.md +0 -0
  178. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-01-SUMMARY.md +0 -0
  179. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-02-PLAN.md +0 -0
  180. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-02-SUMMARY.md +0 -0
  181. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-03-PLAN.md +0 -0
  182. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-03-SUMMARY.md +0 -0
  183. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-04-PLAN.md +0 -0
  184. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-04-SUMMARY.md +0 -0
  185. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-05-PLAN.md +0 -0
  186. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-05-SUMMARY.md +0 -0
  187. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-06-PLAN.md +0 -0
  188. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-06-SUMMARY.md +0 -0
  189. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-CONTEXT.md +0 -0
  190. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-DISCUSSION-LOG.md +0 -0
  191. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-LIVE-FINDINGS.md +0 -0
  192. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-PATTERNS.md +0 -0
  193. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-REVIEW.md +0 -0
  194. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v3.0-phases/11-write-path-reliability-format-support/11-VERIFICATION.md +0 -0
  195. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-REQUIREMENTS.md +0 -0
  196. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-ROADMAP.md +0 -0
  197. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/16-local-mechanism-spike-decision/16-01-PLAN.md +0 -0
  198. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/16-local-mechanism-spike-decision/16-01-SUMMARY.md +0 -0
  199. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/16-local-mechanism-spike-decision/16-02-PLAN.md +0 -0
  200. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/16-local-mechanism-spike-decision/16-02-SUMMARY.md +0 -0
  201. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/16-local-mechanism-spike-decision/16-03-PLAN.md +0 -0
  202. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/16-local-mechanism-spike-decision/16-03-SUMMARY.md +0 -0
  203. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/16-local-mechanism-spike-decision/16-CONTEXT.md +0 -0
  204. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/16-local-mechanism-spike-decision/16-DECISION-RECORD.md +0 -0
  205. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/16-local-mechanism-spike-decision/16-DISCUSSION-LOG.md +0 -0
  206. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/16-local-mechanism-spike-decision/16-LIVE-FINDINGS.md +0 -0
  207. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/16-local-mechanism-spike-decision/COVERAGE.md +0 -0
  208. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/17-google-link-album-selection/17-01-PLAN.md +0 -0
  209. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/17-google-link-album-selection/17-01-SUMMARY.md +0 -0
  210. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/17-google-link-album-selection/17-02-PLAN.md +0 -0
  211. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/17-google-link-album-selection/17-02-SUMMARY.md +0 -0
  212. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/17-google-link-album-selection/17-CONTEXT.md +0 -0
  213. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/17-google-link-album-selection/17-DISCUSS-CHECKPOINT.json +0 -0
  214. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/17-google-link-album-selection/17-VERIFICATION.md +0 -0
  215. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/17-google-link-album-selection/COVERAGE.md +0 -0
  216. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/18-album-frame-mirror-sync-single-pair/18-01-PLAN.md +0 -0
  217. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/18-album-frame-mirror-sync-single-pair/18-01-SUMMARY.md +0 -0
  218. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/18-album-frame-mirror-sync-single-pair/18-02-PLAN.md +0 -0
  219. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/18-album-frame-mirror-sync-single-pair/18-02-SUMMARY.md +0 -0
  220. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/18-album-frame-mirror-sync-single-pair/18-03-PLAN.md +0 -0
  221. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/18-album-frame-mirror-sync-single-pair/18-03-SUMMARY.md +0 -0
  222. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/18-album-frame-mirror-sync-single-pair/18-CONTEXT.md +0 -0
  223. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/18-album-frame-mirror-sync-single-pair/18-RESEARCH.md +0 -0
  224. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/18-album-frame-mirror-sync-single-pair/18-UAT.md +0 -0
  225. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/18-album-frame-mirror-sync-single-pair/18-VERIFICATION.md +0 -0
  226. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/19-debt-closeout/19-01-PLAN.md +0 -0
  227. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/19-debt-closeout/19-01-SUMMARY.md +0 -0
  228. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/19-debt-closeout/19-02-PLAN.md +0 -0
  229. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/19-debt-closeout/19-02-SUMMARY.md +0 -0
  230. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/19-debt-closeout/19-CONTEXT.md +0 -0
  231. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/19-debt-closeout/19-RESEARCH.md +0 -0
  232. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/milestones/v4.0-phases/19-debt-closeout/19-VERIFICATION.md +0 -0
  233. /pushframe-5.0.3/.planning/ROADMAP.md → /pushframe-5.0.4/.planning/milestones/v5.0-ROADMAP.md +0 -0
  234. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/20-pushframe-rename-migration-repo-switch/20-SUMMARY.md +0 -0
  235. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/21-debian-package-apt-repo/21-01-PLAN.md +0 -0
  236. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/21-debian-package-apt-repo/21-01-SUMMARY.md +0 -0
  237. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/21-debian-package-apt-repo/21-02-PLAN.md +0 -0
  238. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/21-debian-package-apt-repo/21-02-SUMMARY.md +0 -0
  239. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/21-debian-package-apt-repo/21-CONTEXT.md +0 -0
  240. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/21-debian-package-apt-repo/21-RESEARCH.md +0 -0
  241. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/21-debian-package-apt-repo/21-VERIFICATION.md +0 -0
  242. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/22-pypi-release-engineering/22-01-PLAN.md +0 -0
  243. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/22-pypi-release-engineering/22-01-SUMMARY.md +0 -0
  244. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/22-pypi-release-engineering/22-02-PLAN.md +0 -0
  245. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/22-pypi-release-engineering/22-02-SUMMARY.md +0 -0
  246. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/22-pypi-release-engineering/22-CONTEXT.md +0 -0
  247. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/22-pypi-release-engineering/22-RESEARCH.md +0 -0
  248. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/22-pypi-release-engineering/22-VERIFICATION.md +0 -0
  249. {pushframe-5.0.3/.planning/phases → pushframe-5.0.4/.planning/milestones/v5.0-phases}/22-pypi-release-engineering/OPERATOR-STEPS.md +0 -0
  250. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/research/ALBUM-ACCESS-V4-ADDENDUM.md +0 -0
  251. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/research/ALBUM-ACCESS.md +0 -0
  252. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/research/ARCHITECTURE.md +0 -0
  253. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/research/BROWSER-AUTOMATION.md +0 -0
  254. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/research/FEATURES.md +0 -0
  255. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/research/PITFALLS.md +0 -0
  256. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/research/STACK.md +0 -0
  257. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/research/SUMMARY.md +0 -0
  258. {pushframe-5.0.3 → pushframe-5.0.4}/.planning/todos/completed/2026-07-06-promote-debug-flag-to-a-global-cli-convention.md +0 -0
  259. {pushframe-5.0.3 → pushframe-5.0.4}/.python-version +0 -0
  260. {pushframe-5.0.3 → pushframe-5.0.4}/CLAUDE.md +0 -0
  261. {pushframe-5.0.3 → pushframe-5.0.4}/LICENSE +0 -0
  262. {pushframe-5.0.3 → pushframe-5.0.4}/README.md +0 -0
  263. {pushframe-5.0.3 → pushframe-5.0.4}/SECURITY.md +0 -0
  264. {pushframe-5.0.3 → pushframe-5.0.4}/VERIFICATION-REPORT.md +0 -0
  265. {pushframe-5.0.3 → pushframe-5.0.4}/docs/CLI.md +0 -0
  266. {pushframe-5.0.3 → pushframe-5.0.4}/docs/agents/domain.md +0 -0
  267. {pushframe-5.0.3 → pushframe-5.0.4}/docs/agents/issue-tracker.md +0 -0
  268. {pushframe-5.0.3 → pushframe-5.0.4}/docs/agents/triage-labels.md +0 -0
  269. {pushframe-5.0.3 → pushframe-5.0.4}/docs/superpowers/specs/2026-07-09-write-rate-limiter-design.md +0 -0
  270. {pushframe-5.0.3 → pushframe-5.0.4}/main.py +0 -0
  271. {pushframe-5.0.3 → pushframe-5.0.4}/packaging/control-template +0 -0
  272. {pushframe-5.0.3 → pushframe-5.0.4}/packaging/lintian-overrides +0 -0
  273. {pushframe-5.0.3 → pushframe-5.0.4}/packaging/postinst +0 -0
  274. {pushframe-5.0.3 → pushframe-5.0.4}/packaging/pushframe.copyright +0 -0
  275. {pushframe-5.0.3 → pushframe-5.0.4}/probes/.gitignore +0 -0
  276. {pushframe-5.0.3 → pushframe-5.0.4}/probes/README.md +0 -0
  277. {pushframe-5.0.3 → pushframe-5.0.4}/probes/browser_bootstrap.py +0 -0
  278. {pushframe-5.0.3 → pushframe-5.0.4}/probes/common.py +0 -0
  279. {pushframe-5.0.3 → pushframe-5.0.4}/probes/cookie_vault.py +0 -0
  280. {pushframe-5.0.3 → pushframe-5.0.4}/probes/fidelity_check.py +0 -0
  281. {pushframe-5.0.3 → pushframe-5.0.4}/probes/rpc_capture.py +0 -0
  282. {pushframe-5.0.3 → pushframe-5.0.4}/probes/shared_link_probe.py +0 -0
  283. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/api/__init__.py +0 -0
  284. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/api/accountApi.py +0 -0
  285. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/api/activityApi.py +0 -0
  286. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/api/assetApi.py +0 -0
  287. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/api/baseApi.py +0 -0
  288. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/api/frameApi.py +0 -0
  289. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/api/notificationApi.py +0 -0
  290. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/api/peopleApi.py +0 -0
  291. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/api/playlistApi.py +0 -0
  292. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/aura.py +0 -0
  293. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/aws/__init__.py +0 -0
  294. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/aws/awsclient.py +0 -0
  295. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/aws/s3client.py +0 -0
  296. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/aws/sqsclient.py +0 -0
  297. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/cache.py +0 -0
  298. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/client.py +0 -0
  299. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/exif.py +0 -0
  300. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/export.py +0 -0
  301. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/google/__init__.py +0 -0
  302. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/google/cache.py +0 -0
  303. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/google/client.py +0 -0
  304. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/google/enumerate.py +0 -0
  305. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/google/manifest.py +0 -0
  306. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/google/parsers.py +0 -0
  307. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/google/redaction.py +0 -0
  308. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/google/vault.py +0 -0
  309. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/gsync.py +0 -0
  310. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/migration.py +0 -0
  311. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/models/__init__.py +0 -0
  312. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/models/activity.py +0 -0
  313. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/models/asset.py +0 -0
  314. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/models/frame.py +0 -0
  315. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/models/meta.py +0 -0
  316. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/models/person.py +0 -0
  317. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/models/user.py +0 -0
  318. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/ratelimit.py +0 -0
  319. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/reconcile.py +0 -0
  320. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/sync.py +0 -0
  321. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/utils/dt.py +0 -0
  322. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/utils/io.py +0 -0
  323. {pushframe-5.0.3 → pushframe-5.0.4}/pushframe/utils/settings.py +0 -0
  324. {pushframe-5.0.3 → pushframe-5.0.4}/scripts/build-deb.sh +0 -0
  325. {pushframe-5.0.3 → pushframe-5.0.4}/scripts/make-apt-key.sh +0 -0
  326. {pushframe-5.0.3 → pushframe-5.0.4}/scripts/publish-apt-repo.sh +0 -0
  327. {pushframe-5.0.3 → pushframe-5.0.4}/scripts/test-apt-journey-container.sh +0 -0
  328. {pushframe-5.0.3 → pushframe-5.0.4}/scripts/test-deb-container.sh +0 -0
  329. {pushframe-5.0.3 → pushframe-5.0.4}/scripts/test-install-journey-container.sh +0 -0
  330. {pushframe-5.0.3 → pushframe-5.0.4}/tests/conftest.py +0 -0
  331. {pushframe-5.0.3 → pushframe-5.0.4}/tests/fixtures/asset_unprocessed.json +0 -0
  332. {pushframe-5.0.3 → pushframe-5.0.4}/tests/fixtures/assets_page1.json +0 -0
  333. {pushframe-5.0.3 → pushframe-5.0.4}/tests/fixtures/assets_page2.json +0 -0
  334. {pushframe-5.0.3 → pushframe-5.0.4}/tests/fixtures/assets_placeholders.json +0 -0
  335. {pushframe-5.0.3 → pushframe-5.0.4}/tests/fixtures/error_envelope.json +0 -0
  336. {pushframe-5.0.3 → pushframe-5.0.4}/tests/fixtures/frame_detail.json +0 -0
  337. {pushframe-5.0.3 → pushframe-5.0.4}/tests/fixtures/frames.json +0 -0
  338. {pushframe-5.0.3 → pushframe-5.0.4}/tests/fixtures/google_rpc_snackc_page.json +0 -0
  339. {pushframe-5.0.3 → pushframe-5.0.4}/tests/fixtures/google_share_page_sample.html +0 -0
  340. {pushframe-5.0.3 → pushframe-5.0.4}/tests/fixtures/login.json +0 -0
  341. {pushframe-5.0.3 → pushframe-5.0.4}/tests/fixtures/probe_af_initdata_sample.html +0 -0
  342. {pushframe-5.0.3 → pushframe-5.0.4}/tests/offline.py +0 -0
  343. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_asset_partial.py +0 -0
  344. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_asset_unprocessed.py +0 -0
  345. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_aura_logger.py +0 -0
  346. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_batch_update_contract.py +0 -0
  347. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_cli_apply.py +0 -0
  348. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_cli_google_album.py +0 -0
  349. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_cli_inspect.py +0 -0
  350. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_cli_push_budget_geo.py +0 -0
  351. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_cli_reconcile.py +0 -0
  352. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_cli_status.py +0 -0
  353. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_cli_status_google.py +0 -0
  354. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_cli_sync.py +0 -0
  355. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_client_rate_limit.py +0 -0
  356. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_execute_plan.py +0 -0
  357. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_execute_plan_budget_geo.py +0 -0
  358. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_fixtures_validity.py +0 -0
  359. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_google_cache.py +0 -0
  360. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_google_client.py +0 -0
  361. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_google_enumerate.py +0 -0
  362. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_google_manifest.py +0 -0
  363. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_google_parsers.py +0 -0
  364. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_google_vault.py +0 -0
  365. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_gsync_engine.py +0 -0
  366. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_gsync_execute.py +0 -0
  367. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_imports.py +0 -0
  368. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_migration.py +0 -0
  369. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_offline_read_path.py +0 -0
  370. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_prep_upload_formats.py +0 -0
  371. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_probe_browser.py +0 -0
  372. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_probe_shared_link.py +0 -0
  373. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_ratelimit.py +0 -0
  374. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_read_path.py +0 -0
  375. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_reconcile.py +0 -0
  376. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_retry_401.py +0 -0
  377. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_settings_budget.py +0 -0
  378. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_sync_engine.py +0 -0
  379. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_write_endpoints_failloud.py +0 -0
  380. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_write_formats_live.py +0 -0
  381. {pushframe-5.0.3 → pushframe-5.0.4}/tests/test_write_throttling.py +0 -0
@@ -1,5 +1,30 @@
1
1
  # Milestones
2
2
 
3
+ ## v5.0 — Distribution & Rename: pushframe packages (Shipped: 2026-09-29)
4
+
5
+ **Phases completed:** 3 phases (20-22), 4 plans — the first milestone
6
+ about *shipping the tool itself* rather than its features.
7
+
8
+ **Key accomplishments:**
9
+
10
+ | Phase | Delivered | Proof |
11
+ |-------|-----------|-------|
12
+ | 20 — Rename & repo switch | `auraframes`→`pushframe` (module, binary, config migration), env `PUSHFRAME_*` primary, standalone repo `coredmp95/pushframe` (not a fork), MIT LICENSE + provenance | 407 tests green through the rename; live migration validated; name cleared on PyPI + trademark-adjacency checked |
13
+ | 21 — Debian + APT | Hermetic `.deb` (embedded CPython 3.14, lintian 0E/0W, clean removal), signed APT repo live on GitHub Pages, container journeys for both channels | bytecode-ownership defect caught by our own container test and fixed for every user; live-URL journey exit 0 |
14
+ | 22 — PyPI + releases | Trusted publishing (OIDC, zero PyPI tokens), tag-triggered release workflow, `--version` single-sourced, OPERATOR-STEPS + CHANGELOG | v5.0.2 run all-green 5/5 jobs; v5.0.3 carries the Changelog URL |
15
+
16
+ **Shipped releases:** 5.0.0 → 5.0.1 (page metadata) → 5.0.2 (first
17
+ pipeline-complete) → 5.0.3 (changelog URL) — each on PyPI + TestPyPI +
18
+ APT + GitHub Releases simultaneously. First real deployment:
19
+ venus.coredmp.net via the signed APT repo (human-driven: keyring →
20
+ sources → install).
21
+
22
+ **Known gaps carried forward:** 5.0.0 remains on PyPI (empty page,
23
+ immutable) — yank candidate; `AURA_*` env vars in a one-release
24
+ deprecation window; credentials still live in env vars/.env (v5.1's
25
+ charter: config wizard + token-first sessions).
26
+
27
+
3
28
  ## v4.0 Local Google Photos Album Sync (Shipped: 2026-09-29)
4
29
 
5
30
  **Phases completed:** 4 phases (16-19), 10 plans, offline suite 349 → **401 tests**
@@ -364,3 +364,5 @@ sequences write-path reliability first, then Google account linking → album di
364
364
  album-to-frame mirroring via a pruned local cache, then the carried debt. Biggest open
365
365
  unknown: whether Google's post-March-2025 Photos API still permits enumerating a user's own
366
366
  albums, or whether album selection has to go through the Picker API.*
367
+
368
+ **Current Milestone:** v5.1 — Operations: Config, Sessions, Multi-frame & Scheduling (started 2026-09-29)
@@ -0,0 +1,118 @@
1
+ # Requirements: pushframe — v5.1 Operations: Config, Sessions, Multi-frame & Scheduling
2
+
3
+ **Defined:** 2026-09-29
4
+ **Core Value:** `pushframe` becomes *operable unattended*: configuration is a
5
+ conversation (`pushframe config`) instead of env-var archaeology, the Aura
6
+ password never touches disk (token-first sessions), mirrors run on a schedule
7
+ without root (systemd user timers), one album can mirror to every frame
8
+ (named mappings), and every command that needs a machine prerequisite fails
9
+ with the remedy instead of a traceback.
10
+
11
+ ## Requirements
12
+
13
+ ### Config wizard (CFG)
14
+
15
+ - [ ] **CFG-01**: `pushframe config` (interactive) asks for and stores: Aura
16
+ email, Aura secret, default frame name, and the tool's non-secret settings
17
+ (default album, write-budget override, debug) — prompts are masked for
18
+ secrets (getpass-style), values are validated (email shape; login test on
19
+ request), and the result is written to `~/.config/pushframe/config.json`
20
+ with mode `0600`. Re-running edits in place (existing values shown
21
+ redacted, Enter keeps).
22
+ - [ ] **CFG-02**: precedence is `env var > config file > built-in default`
23
+ everywhere the CLI reads configuration; the env vars keep working exactly
24
+ as today (deprecation window opened in 5.0.0 stays honored); `pushframe
25
+ config show` prints the *effective* configuration with secrets redacted
26
+ and the source of each value (env/file/default).
27
+ - [ ] **CFG-03**: `pushframe config import` migrates an existing `.env`
28
+ (or exported `PUSHFRAME_*`/`AURA_*` set) into `config.json` without
29
+ retyping; the command reports what it took from where and never stores
30
+ what it could resolve from the environment instead.
31
+ - [ ] **CFG-04**: `pushframe config path` prints the config file location;
32
+ `pushframe config set <key> <value>` / `get <key>` exist for scripts;
33
+ unknown keys fail with the list of known keys.
34
+
35
+ ### Credential handling (SEC — token-first)
36
+
37
+ - [ ] **SEC-01**: the Aura password is **never persisted** — not in
38
+ `config.json`, not in env files the tool writes. `pushframe config`
39
+ authenticates once, stores the returned `auth_token` (0600) plus the
40
+ account email, and discards the password when the process exits.
41
+ - [ ] **SEC-02**: every command that needs the API uses the stored token
42
+ (header auth) and falls back to interactive password login **only** when
43
+ the token is absent/expired/revoked, after which the new token is
44
+ persisted; a `--password` / `PUSHFRAME_PASSWORD` override still wins
45
+ (CI/script path) but is documented as discouraged for humans.
46
+ - [ ] **SEC-03**: `pushframe logout` deletes the stored token (and only the
47
+ token); token material never appears in logs, output, or the history
48
+ ledger (existing redaction stays enforced by tests).
49
+
50
+ ### Scheduling (TMR — systemd user)
51
+
52
+ - [ ] **TMR-01**: `pushframe schedule add <job>` installs a systemd **user**
53
+ timer + service unit under `~/.config/systemd/user/` for the supported
54
+ jobs (`google-sync --apply` for a named pair, directory `sync`) with a
55
+ prompted or `--every` schedule; no root anywhere; `pushframe schedule
56
+ list` shows installed jobs with next-run times (from `systemctl list-timers`).
57
+ - [ ] **TMR-02**: `pushframe schedule remove <job>` uninstalls cleanly
58
+ (units + timer state); installed units are named `pushframe-<job>.service/.timer`
59
+ and never collide with system units.
60
+ - [ ] **TMR-03**: unattended correctness: a scheduled run uses only
61
+ stored configuration (no prompts), honors SAFE-02's removal threshold
62
+ (a run that would exceed it **skips and logs** rather than fails the unit),
63
+ writes a per-job log (`~/.local/state/pushframe/<job>.log`), and the
64
+ docs cover `loginctl enable-linger` for headless machines (venus).
65
+
66
+ ### Multi-frame (MTF — GSF-01 closed)
67
+
68
+ - [ ] **MTF-01**: named **album↔frame mappings** live in config: one album
69
+ may mirror to N frames and one frame may receive from N albums
70
+ (`pushframe config` manages them; `--pair <name>` selects one,
71
+ `--all` selects every pair).
72
+ - [ ] **MTF-02**: `google-sync` resolves a pair the same way it resolves the
73
+ current single pair today (dry-run default, `--apply` gated, SAFE-01..04
74
+ per pair); **state is per-pair** — the manifest and staging cache are
75
+ sharded by pair so two pairs never share dedupe memory.
76
+ - [ ] **MTF-03**: the write budget is **account-wide and shared** across
77
+ pairs within one run (`--all`), preserving SAFE-02 semantics at account
78
+ level; per-pair reports stay exact (pairs list what they did, and a
79
+ skipped pair never blocks the others).
80
+
81
+ ### Preflights & error quality (PRF)
82
+
83
+ - [ ] **PRF-01**: commands with machine prerequisites check them up front
84
+ and fail with per-item remedies — `google-link` (playwright package,
85
+ Chrome/Chromium, profile dir) ships in 5.1's first cut (already
86
+ implemented on master), extended to: `google-sync` (vault present),
87
+ `schedule` (systemd user session available, `loginctl` linger status),
88
+ and `sync`/`push` (target dir exists/contains images).
89
+ - [ ] **PRF-02**: no user-facing command may end in an unhandled traceback
90
+ for a foreseeable condition (missing module, missing browser, missing
91
+ vault, ambiguous frame, multi-arch notice): each maps to a named,
92
+ one-screen error with the next action. A test sweep asserts the
93
+ traceback-free contract for the documented failure modes.
94
+
95
+ ## Non-Goals
96
+
97
+ | Feature | Reason |
98
+ |---------|--------|
99
+ | OS keyring storage (gnome-keyring/Secret Service) | headless servers (venus) lack a keyring session; file-0600 token is the contract, keyring is a later nicety |
100
+ | Encrypting config.json with a user passphrase | circularity (where does the passphrase live?); token-first removes the high-value secret anyway |
101
+ | Cron support | systemd user timers are the modern path; cron adds a second code path for no new capability |
102
+ | Real deletion exposure on the Google verb | unchanged posture from v2.0/v4.0; hide-not-delete stays |
103
+ | Many-to-many with per-pair schedules | each pair is its own scheduled job — same capability, simpler model |
104
+
105
+ ## Traceability
106
+
107
+ Every v5.1 requirement maps to exactly one phase; numbering continues from
108
+ Phase 22.
109
+
110
+ | Requirement | Phase | Status |
111
+ |-------------|-------|--------|
112
+ | CFG-01..04 | Phase 23 | Pending |
113
+ | SEC-01..03 | Phase 24 | Pending |
114
+ | PRF-01..02 | Phase 24 | Pending |
115
+ | MTF-01..03 | Phase 25 | Pending |
116
+ | TMR-01..03 | Phase 25 | Pending |
117
+
118
+ **Coverage:** v5.1 requirements: 14 total — no orphans, no double-mapping.
@@ -0,0 +1,105 @@
1
+ # pushframe Roadmap — v5.1 Operations: Config, Sessions, Multi-frame & Scheduling
2
+
3
+ **Defined:** 2026-09-29
4
+ **Ships when:** a fresh machine goes from `apt install pushframe` to a
5
+ scheduled, unattended, multi-frame Google mirror with **zero** hand-edited
6
+ config files and **zero** stored passwords.
7
+
8
+ ## Milestone Goal
9
+
10
+ Make pushframe *operable* the way it is *installable*: one conversational
11
+ command (`pushframe config`) to set everything up, password-free sessions
12
+ (token-first), `pushframe schedule` for root-less systemd user timers,
13
+ named album↔frame mappings with per-pair mirror state, and preflights that
14
+ always fail with a remedy.
15
+
16
+ ## Phases
17
+
18
+ ### Phase 23: Config Wizard & Precedence (CFG-01..04)
19
+
20
+ **Goal**: `pushframe config` replaces env-var archaeology — interactive,
21
+ masked, validated, `0600`; env vars keep working; `show` prints effective
22
+ config with sources; `import` swallows an existing `.env`.
23
+
24
+ **Success Criteria**:
25
+
26
+ 1. On a fresh machine, `pushframe config` → `pushframe status` works with
27
+ no env vars set at all (file-only path), verified in a clean container.
28
+ 2. With env vars set, they override the file — proven by a test that flips
29
+ both and asserts which value each command sees.
30
+ 3. `config show` never prints a secret value (redaction test); `config
31
+ import` on a real `.env` reproduces the same effective config as the
32
+ env-var path (golden diff test).
33
+
34
+ **Depends on**: nothing (master already carries the google-link preflights
35
+ that started this work).
36
+
37
+ ### Phase 24: Token-First Sessions & Preflight Sweep (SEC-01..03, PRF-01..02)
38
+
39
+ **Goal**: the password is used once at login and never stored; the token
40
+ drives every subsequent command with transparent re-login on expiry; the
41
+ preflight pattern from google-link covers every command's machine
42
+ prerequisites; no foreseeable condition ends in a traceback.
43
+
44
+ **Success Criteria**:
45
+
46
+ 1. `pushframe config` + login → `~/.config/pushframe/` contains a token,
47
+ no password, mode 0600 (file-content test).
48
+ 2. A token-expiry simulation (mocked 401) transparently re-logins once and
49
+ retries the request; a second consecutive failure surfaces the login
50
+ error (no loops).
51
+ 3. The traceback-free sweep passes: every documented foreseeable failure
52
+ mode maps to a named error with a remedy (parametrized test).
53
+
54
+ **Depends on**: Phase 23 (config file is where the token lives).
55
+
56
+ ### Phase 25: Multi-frame Mappings & systemd User Scheduling (MTF-01..03, TMR-01..03)
57
+
58
+ **Goal**: GSF-01 and GSF-02 close — named album↔frame pairs (N:M),
59
+ per-pair mirror state with an account-wide shared write budget, and
60
+ `pushframe schedule` installing systemd **user** timers that run pairs
61
+ unattended (SAFE-02 skips-and-logs, per-job logs, linger documented for
62
+ headless hosts like venus).
63
+
64
+ **Success Criteria**:
65
+
66
+ 1. Two pairs (one album → two frames) sync in one `--all` run, each with
67
+ its own manifest/cache shard, the shared budget capping the total, and
68
+ per-pair reports exact (container + fake-API proof).
69
+ 2. `schedule add/list/remove` round-trips units in
70
+ `~/.config/systemd/user/` (unit-content assertions in a container with
71
+ systemd available); a scheduled google-sync run is prompt-free and
72
+ logs to `~/.local/state/pushframe/<job>.log`.
73
+ 3. SAFE-02 behavior under scheduling: a pair whose plan exceeds the
74
+ removal threshold is skipped-and-logged, the unit exits 0, and the
75
+ other pairs still run.
76
+
77
+ **Depends on**: Phase 24 (scheduled runs read token sessions, not
78
+ passwords; preflights guard scheduled contexts).
79
+
80
+ ## Progress
81
+
82
+ **Execution Order:** 23 → 24 → 25
83
+
84
+ | Phase | Plans Complete | Status | Completed |
85
+ |-------|----------------|--------|-----------|
86
+ | 23. Config Wizard & Precedence | 0/? | Not started | - |
87
+ | 24. Token-First Sessions & Preflight Sweep | 0/? | Not started | - |
88
+ | 25. Multi-frame & systemd User Scheduling | 0/? | Not started | - |
89
+
90
+ ## Requirement Coverage (v5.1)
91
+
92
+ | Phase | Requirements | Count |
93
+ |-------|--------------|-------|
94
+ | 23 | CFG-01..04 | 4 |
95
+ | 24 | SEC-01..03, PRF-01..02 | 5 |
96
+ | 25 | MTF-01..03, TMR-01..03 | 6 |
97
+ | **Total** | | **15 / 15** |
98
+
99
+ No orphaned requirements; no requirement mapped to more than one phase.
100
+
101
+ ## Backlog
102
+
103
+ - Yank 5.0.0 from PyPI (empty-page release, superseded by 5.0.3).
104
+ - OS keyring token storage (Secret Service) as an optional backend.
105
+ - Ubuntu 26 runner observation after 2026-10-19 (deb job toolchain).
@@ -0,0 +1,22 @@
1
+ # pushframe — State
2
+
3
+ **Milestone:** v5.1 — Operations: Config, Sessions, Multi-frame & Scheduling
4
+ **Started:** 2026-09-29
5
+
6
+ ## Current Position
7
+
8
+ Phase: 23 — Config Wizard & Precedence
9
+ Current Plan: Not started
10
+ Total Plans in Phase: 0
11
+ Status: Ready to plan
12
+
13
+ ## Milestone Roadmap (v5.1, Phases 23-25)
14
+
15
+ - [ ] Phase 23 — Config Wizard & Precedence (CFG-01..04)
16
+ - [ ] Phase 24 — Token-First Sessions & Preflight Sweep (SEC-01..03, PRF-01..02)
17
+ - [ ] Phase 25 — Multi-frame Mappings & systemd User Scheduling (MTF-01..03, TMR-01..03)
18
+
19
+ ## Completed Milestones
20
+
21
+ - v4.0 — Local Google Photos Album Sync (2026-09-29)
22
+ - v5.0 — Distribution & Rename: pushframe packages (2026-09-29)
@@ -1,3 +1,12 @@
1
+ # Requirements Archive: v5.0 v5.0
2
+
3
+ **Archived:** 2026-09-29
4
+ **Status:** SHIPPED
5
+
6
+ For current requirements, see `.planning/REQUIREMENTS.md`.
7
+
8
+ ---
9
+
1
10
  # Requirements: Aura Frames Python Client — v5.0 Distribution & Rename: pushframe packages
2
11
 
3
12
  **Defined:** 2026-09-29
@@ -0,0 +1,32 @@
1
+ {
2
+ "contract": "1.0.0",
3
+ "flavor": "core",
4
+ "milestone": {
5
+ "version": "v5.1",
6
+ "name": "Operations: Config, Sessions, Multi-frame & Scheduling",
7
+ "started": "2026-09-29"
8
+ },
9
+ "phases": [
10
+ {
11
+ "number": "23",
12
+ "name": "Config Wizard & Precedence",
13
+ "status": "pending"
14
+ },
15
+ {
16
+ "number": "24",
17
+ "name": "Token-First Sessions & Preflight Sweep",
18
+ "status": "pending"
19
+ },
20
+ {
21
+ "number": "25",
22
+ "name": "Multi-frame & systemd User Scheduling",
23
+ "status": "pending"
24
+ }
25
+ ],
26
+ "next": {
27
+ "command": "/gsd:progress --next",
28
+ "label": "Advance to the next step",
29
+ "reason": "Phase 23 of 3 \u00b7 0% \u00b7 ready to plan"
30
+ },
31
+ "updated_at": "2026-09-29T13:27:41.229Z"
32
+ }
@@ -108,7 +108,53 @@ Milestone summary — see `.planning/MILESTONES.md` for the full retros.
108
108
 
109
109
  ## [Unreleased]
110
110
 
111
- - Nothing staged yet; next changes land here before the next tag.
111
+ - (v5.1 work will land here)
112
+
113
+ ## [5.0.4] — 2026-09-29
114
+
115
+ ### Fixed
116
+
117
+ - google-link preflight on the uv-tool install path: remedy for a missing
118
+ playwright now matches every install shape (`uv tool install
119
+ 'pushframe[google-browser]' --force` for uv tools — `pip install
120
+ --user` targets the wrong interpreter there); stray duplicate quote in
121
+ the message fixed.
122
+
123
+ ### Added
124
+
125
+ - google-link zero-config: dedicated Chrome profile defaults to
126
+ `~/.config/pushframe/chrome-profile` (created on demand); the env var
127
+ becomes an override. A near-miss env name (e.g. a truncated
128
+ `USHFRAME_…`) is called out explicitly instead of looking like "unset".
129
+ - google-link preflight: missing prerequisites (playwright package,
130
+ Chrome/Chromium) fail with the exact remedy instead of a traceback
131
+ (`ModuleNotFoundError: playwright` was the whole output before).
132
+
133
+ ### Changed
134
+
135
+ - `PUSHFRAME_PROBE_CHROME_PROFILE` is no longer required to run
136
+ `google-link`.
137
+
138
+ - google-link zero-config: the dedicated Chrome profile defaults to
139
+ `~/.config/pushframe/chrome-profile` (created on demand); the env var
140
+ becomes an override. A near-miss env name (e.g. a truncated
141
+ `USHFRAME_…`) is called out explicitly instead of looking like "unset".
142
+ - google-link preflight: missing prerequisites (playwright package,
143
+ Chrome/Chromium) now fail with the exact remedy instead of a traceback
144
+ (`ModuleNotFoundError: playwright` was the whole output before).
145
+
146
+ ### Fixed
147
+
148
+ - `google-link` preflight on the uv-tool install path: the message for a
149
+ missing playwright package now matches every install shape (`uv tool
150
+ install 'pushframe[google-browser]'` for uv tools — `pip install
151
+ --user` targets the wrong interpreter there), and the leftover
152
+ duplicate browser-detection line was removed.
153
+
154
+ ### Changed
155
+
156
+ - `PUSHFRAME_PROBE_CHROME_PROFILE` is no longer required to run
157
+ `google-link`.
112
158
 
113
159
  ## [5.0.3] — 2026-09-29
114
160
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pushframe
3
- Version: 5.0.3
3
+ Version: 5.0.4
4
4
  Summary: Unofficial community CLI for Aura Frames digital photo frames (sync a local folder or a Google Photos album; not affiliated with Aura Frames Inc.)
5
5
  Project-URL: Homepage, https://github.com/coredmp95/pushframe
6
6
  Project-URL: Repository, https://github.com/coredmp95/pushframe
@@ -1,4 +1,4 @@
1
1
  # pushframe — unofficial community CLI for Aura Frames (not affiliated).
2
2
  # Version single source for the CLI surface (REL-02); pyproject keeps the
3
3
  # packaging metadata version and tests/test_version.py enforces lockstep.
4
- __version__ = "5.0.3"
4
+ __version__ = "5.0.4"
@@ -324,12 +324,10 @@ def run_google_link(*, debug: bool = False, bootstrap_fn=None) -> int:
324
324
  """
325
325
  _configure_cli_logging(debug)
326
326
 
327
- if not os.environ.get(PROFILE_ENV_VAR, '').strip():
328
- print(f'google-link failed: {PROFILE_ENV_VAR} is unset — the daily-driver '
329
- f'profile is structurally unreachable; point the env var at a '
330
- f'dedicated Chrome profile directory (e.g. ~/.config/pushframe/'
331
- f'chrome-profile) and re-run (T-16-06)')
332
- return 1
327
+ # v5.1: no env prerequisite here — bootstrap._require_profile() owns the
328
+ # precedence (override > legacy > built-in default, created on demand)
329
+ # and raises a helpful BootstrapError (near-miss names included) that the
330
+ # handler below prints verbatim.
333
331
 
334
332
  # Re-link notice (LGS-02): same command refreshes an existing session.
335
333
  # Vault read routes through from_vault (denylist-sanctioned); a dead or
@@ -42,18 +42,43 @@ class BootstrapError(RuntimeError):
42
42
  """Bootstrap prerequisites missing or the login never completed."""
43
43
 
44
44
 
45
+ DEFAULT_PROFILE_DIR = Path.home() / ".config" / "pushframe" / "chrome-profile"
46
+
47
+
45
48
  def _require_profile() -> Path:
46
- """Resolve the dedicated profile directory; fail loud when unset (T-16-06)."""
49
+ """Resolve the dedicated profile directory (v5.1 simplification).
50
+
51
+ Precedence: PUSHFRAME_PROBE_CHROME_PROFILE > AURA_PROBE_CHROME_PROFILE
52
+ (legacy) > the built-in default ~/.config/pushframe/chrome-profile —
53
+ created on demand. The env var is now an OVERRIDE, not a prerequisite:
54
+ a fresh machine gets google-link with zero configuration.
55
+
56
+ A near-miss env name (e.g. USHFRAME_PROBE_CHROME_PROFILE — a truncated
57
+ prefix, seen in the wild on venus) is called out explicitly, because a
58
+ silent typo looks identical to "unset".
59
+ """
47
60
  profile = os.environ.get(PROFILE_ENV_VAR, "").strip()
48
61
  if not profile:
49
62
  profile = os.environ.get(_LEGACY_PROFILE_ENV_VAR, "").strip()
50
63
  if not profile:
51
- raise BootstrapError(
52
- f"{PROFILE_ENV_VAR} is unset — the daily-driver profile is "
53
- f"structurally unreachable; point the env var at a dedicated "
54
- f"profile directory (e.g. ~/.config/pushframe/chrome-profile) "
55
- f"and re-run (T-16-06)"
56
- )
64
+ # Near-miss detection: subsequence match (USHFRAME_… = PUSHFRAME_…
65
+ # minus its first letter — a real-world typo, seen on venus) catches
66
+ # truncated/scrambled names that a plain substring check misses.
67
+ target = PROFILE_ENV_VAR.lower()
68
+ for name, value in os.environ.items():
69
+ low = name.lower()
70
+ if name == PROFILE_ENV_VAR or not low.endswith(target[4:]):
71
+ continue
72
+ it = iter(target)
73
+ if all(ch in it for ch in low): # low is a subsequence of target
74
+ raise BootstrapError(
75
+ f"env var '{name}' looks like a misspelled "
76
+ f"{PROFILE_ENV_VAR} (value: {value}) — fix the name in "
77
+ f"your shell profile, or unset it to use the default "
78
+ f"profile at {DEFAULT_PROFILE_DIR}"
79
+ )
80
+ DEFAULT_PROFILE_DIR.mkdir(parents=True, exist_ok=True)
81
+ return DEFAULT_PROFILE_DIR
57
82
  path = Path(profile).expanduser().resolve()
58
83
  path.mkdir(parents=True, exist_ok=True)
59
84
  return path
@@ -68,6 +93,35 @@ def run_bootstrap(*, auto: bool = False) -> dict:
68
93
  {vault_path, cookie_count, auth_markers} — never cookie values.
69
94
  """
70
95
  profile_dir = _require_profile()
96
+
97
+ # Preflight (v5.1): fail with the REMEDY, not a traceback. Order matters —
98
+ # the python package first, then a browser able to drive.
99
+ missing = []
100
+ try:
101
+ import playwright # noqa: F401
102
+ except ImportError:
103
+ missing.append(
104
+ "the 'playwright' python package — install it into the SAME"
105
+ " interpreter as pushframe: uv-tool users: "
106
+ "uv tool install 'pushframe[google-browser]' --force; "
107
+ ".deb users: pip install --user playwright"
108
+ )
109
+ has_chrome = shutil.which("google-chrome") is not None
110
+ has_chromium = shutil.which("chromium") is not None or shutil.which("chromium-browser") is not None
111
+ if not has_chrome and not has_chromium:
112
+ missing.append(
113
+ "a browser for Playwright to drive — install Google Chrome "
114
+ "(recommended; channel=chrome avoids bot flags), or run "
115
+ "'playwright install chromium' after installing the package"
116
+ )
117
+ if missing:
118
+ remedy = "\n - ".join(missing)
119
+ raise BootstrapError(
120
+ "google-link prerequisites missing on this machine:\n"
121
+ f" - {remedy}\n"
122
+ "Then re-run: pushframe google-link"
123
+ )
124
+
71
125
  from playwright.sync_api import sync_playwright # lazy, in-function import ONLY
72
126
 
73
127
  print(f"dedicated profile: {profile_dir}")
@@ -77,7 +131,6 @@ def run_bootstrap(*, auto: bool = False) -> dict:
77
131
  # engine already treats it as an ordinary browser); otherwise bundled
78
132
  # Chromium with automation switches masked so navigator.webdriver stays
79
133
  # false.
80
- has_chrome = shutil.which("google-chrome") is not None
81
134
  launch_kwargs = dict(user_data_dir=str(profile_dir), headless=False,
82
135
  args=["--disable-blink-features=AutomationControlled"])
83
136
  if has_chrome:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pushframe"
3
- version = "5.0.3"
3
+ version = "5.0.4"
4
4
  description = "Unofficial community CLI for Aura Frames digital photo frames (sync a local folder or a Google Photos album; not affiliated with Aura Frames Inc.)"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.14"
@@ -40,13 +40,38 @@ def test_google_link_success_with_injected_bootstrap(monkeypatch, capsys):
40
40
  assert FAKE_COOKIE_VALUE not in out
41
41
 
42
42
 
43
- def test_google_link_missing_profile_fails_loud(monkeypatch, capsys):
44
- monkeypatch.delenv("PUSHFRAME_PROBE_CHROME_PROFILE", raising=False)
45
- rc = run_google_link(bootstrap_fn=_fake_bootstrap())
46
- assert rc == 1
47
- out = capsys.readouterr().out
48
- assert "PUSHFRAME_PROBE_CHROME_PROFILE" in out
49
- assert "structurally unreachable" in out
43
+ def test_require_profile_zero_config_uses_default(tmp_path, monkeypatch):
44
+ """v5.1 contract: the profile env var is an OVERRIDE, not a prerequisite.
45
+ With nothing set, _require_profile resolves to the built-in default
46
+ (~/.config/pushframe/chrome-profile) and CREATES it — a fresh machine
47
+ needs no shell configuration."""
48
+ for name in ("PUSHFRAME_PROBE_CHROME_PROFILE", "AURA_PROBE_CHROME_PROFILE",
49
+ "USHFRAME_PROBE_CHROME_PROFILE"):
50
+ monkeypatch.delenv(name, raising=False)
51
+ from pushframe.google import bootstrap as bs
52
+ monkeypatch.setattr(bs, "DEFAULT_PROFILE_DIR", tmp_path / "chrome-profile")
53
+ resolved = bs._require_profile()
54
+ assert resolved == tmp_path / "chrome-profile"
55
+ assert resolved.is_dir()
56
+
57
+
58
+ def test_require_profile_near_miss_env_name_is_called_out(tmp_path, monkeypatch):
59
+ """A truncated prefix (USHFRAME_PROBE_CHROME_PROFILE, seen in the wild
60
+ on venus) must not look like a plain 'unset': the error names the
61
+ suspect variable and offers the default-profile escape hatch."""
62
+ for name in ("PUSHFRAME_PROBE_CHROME_PROFILE", "AURA_PROBE_CHROME_PROFILE"):
63
+ monkeypatch.delenv(name, raising=False)
64
+ from pushframe.google import bootstrap as bs
65
+ monkeypatch.setattr(bs, "DEFAULT_PROFILE_DIR", tmp_path / "chrome-profile")
66
+ monkeypatch.setenv("USHFRAME_PROBE_CHROME_PROFILE", "/somewhere")
67
+ try:
68
+ bs._require_profile()
69
+ raised = None
70
+ except bs.BootstrapError as e:
71
+ raised = str(e)
72
+ assert raised is not None
73
+ assert "USHFRAME_PROBE_CHROME_PROFILE" in raised and "misspell" in raised
74
+ assert "chrome-profile" in raised
50
75
 
51
76
 
52
77
  def test_google_link_relink_notice_when_vault_exists(tmp_path, monkeypatch, capsys):
@@ -18,8 +18,8 @@ PYPROJECT = Path(__file__).resolve().parent.parent / "pyproject.toml"
18
18
 
19
19
  def test_version_is_first_distribution_release():
20
20
  """The current distribution release (moved off 0.1.0 at 5.0.0; page
21
- metadata fix shipped in 5.0.3)."""
22
- assert __version__ == "5.0.3"
21
+ metadata fix shipped in 5.0.4)."""
22
+ assert __version__ == "5.0.4"
23
23
 
24
24
 
25
25
  def test_version_matches_pyproject_single_source():
@@ -432,7 +432,7 @@ wheels = [
432
432
 
433
433
  [[package]]
434
434
  name = "pushframe"
435
- version = "5.0.0"
435
+ version = "5.0.4"
436
436
  source = { editable = "." }
437
437
  dependencies = [
438
438
  { name = "boto3" },