gflow-cli 0.15.0__tar.gz → 0.16.0__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 (418) hide show
  1. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/AGENTS.md +3 -1
  2. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/CHANGELOG.md +28 -1
  3. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/KNOWN_ISSUES.md +31 -1
  4. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/PKG-INFO +9 -9
  5. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/README.md +8 -8
  6. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/CHARACTER.md +2 -1
  7. gflow_cli-0.16.0/docs/IMAGE_UPSCALE_RECON.md +115 -0
  8. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/INDEX.md +7 -1
  9. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/MOVIE.md +7 -4
  10. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/USAGE.md +38 -0
  11. gflow_cli-0.16.0/docs/superpowers/plans/2026-06-11-image-upscale/PLAN.md +206 -0
  12. gflow_cli-0.16.0/docs/superpowers/plans/2026-06-11-image-upscale/SCENARIO.md +79 -0
  13. gflow_cli-0.16.0/docs/superpowers/plans/2026-06-11-issue-170-locale-selectors/PLAN.md +218 -0
  14. gflow_cli-0.16.0/docs/superpowers/plans/2026-06-11-issue-170-locale-selectors/SCENARIO.md +101 -0
  15. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/pyproject.toml +1 -1
  16. gflow_cli-0.16.0/scripts/dev/spike_image_upscale_capture.py +382 -0
  17. gflow_cli-0.16.0/scripts/dev/spike_image_upscale_drive.py +383 -0
  18. gflow_cli-0.16.0/scripts/dev/spike_image_upscale_recaptcha_action.py +188 -0
  19. gflow_cli-0.16.0/scripts/dev/spike_image_upscale_rest_probe.py +277 -0
  20. gflow_cli-0.16.0/scripts/dev/spike_issue170_picker_locale_recon.py +234 -0
  21. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_movie_attach_payload.py +13 -1
  22. gflow_cli-0.16.0/scripts/diag/README.md +29 -0
  23. gflow_cli-0.15.0/scripts/diag_capture_flow_traffic.py → gflow_cli-0.16.0/scripts/diag/capture_flow_traffic.py +1 -1
  24. gflow_cli-0.16.0/scripts/diag/memory_profile.py +235 -0
  25. gflow_cli-0.15.0/scripts/diag_recaptcha_mint.py → gflow_cli-0.16.0/scripts/diag/recaptcha_mint.py +1 -1
  26. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/__init__.py +1 -1
  27. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/client.py +138 -1
  28. gflow_cli-0.16.0/src/gflow_cli/api/image_upscale.py +159 -0
  29. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/routes.py +4 -0
  30. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/ui_automation.py +92 -3
  31. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/ui_automation_video.py +115 -18
  32. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_image.py +176 -0
  33. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/errors.py +31 -0
  34. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/exceptions.py +1 -0
  35. gflow_cli-0.16.0/tests/api/test_client_launch_kwargs.py +77 -0
  36. gflow_cli-0.16.0/tests/api/test_client_upscale.py +169 -0
  37. gflow_cli-0.16.0/tests/api/test_image_upscale.py +153 -0
  38. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_ui_automation.py +143 -0
  39. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_ui_automation_video.py +184 -13
  40. gflow_cli-0.16.0/tests/cli/test_cli_image_upscale.py +140 -0
  41. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/dev/test_recording_client.py +4 -1
  42. gflow_cli-0.16.0/tests/features/image_upscale.feature +29 -0
  43. gflow_cli-0.16.0/tests/features/locale_picker_include.feature +25 -0
  44. gflow_cli-0.16.0/tests/features/test_image_upscale_steps.py +130 -0
  45. gflow_cli-0.16.0/tests/features/test_locale_picker_include_steps.py +204 -0
  46. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_errors.py +14 -0
  47. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/uv.lock +1 -1
  48. gflow_cli-0.15.0/tests/api/test_client_launch_kwargs.py +0 -35
  49. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/README.md +0 -0
  50. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/active.md +0 -0
  51. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/branch-review.md +0 -0
  52. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/changelog.md +0 -0
  53. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/check.md +0 -0
  54. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/doc-review.md +0 -0
  55. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/known-issues.md +0 -0
  56. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/next.md +0 -0
  57. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/plan.md +0 -0
  58. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/pr-council-review.md +0 -0
  59. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/predict.md +0 -0
  60. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/release.md +0 -0
  61. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/scenario.md +0 -0
  62. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.claude/commands/gflow/status.md +0 -0
  63. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.continue-here.md +0 -0
  64. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.env.template +0 -0
  65. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.gitattributes +0 -0
  66. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/CODEOWNERS +0 -0
  67. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  68. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/copilot-instructions.md +0 -0
  69. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/dependabot.yml +0 -0
  70. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/workflows/ci.yml +0 -0
  71. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/workflows/external-pr-triage.yml +0 -0
  72. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/workflows/governance-advisory.yml +0 -0
  73. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/workflows/governance-benchmark.yml +0 -0
  74. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.github/workflows/release.yml +0 -0
  75. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.gitignore +0 -0
  76. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.gitleaks.toml +0 -0
  77. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.pre-commit-config.yaml +0 -0
  78. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/.secrets.baseline +0 -0
  79. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/CLAUDE.md +0 -0
  80. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/CONFIGURATION.md +0 -0
  81. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/CONTRIBUTING.md +0 -0
  82. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/DISCLAIMER.md +0 -0
  83. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/GEMINI.md +0 -0
  84. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/LICENSE +0 -0
  85. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/PLAN.md +0 -0
  86. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/PR162_MOVIE_CHARACTER_REVIEW.md +0 -0
  87. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/RELEASE.md +0 -0
  88. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/ROADMAP.md +0 -0
  89. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/conftest.py +0 -0
  90. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docker-compose.yml +0 -0
  91. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/AGENT_GUIDE.md +0 -0
  92. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/ARCHITECTURE.md +0 -0
  93. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/AUTHENTICATION.md +0 -0
  94. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/CHARACTER_RECON.md +0 -0
  95. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/CONFIGURATION.md +0 -0
  96. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/DATA_LAYER.md +0 -0
  97. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/DEBUGGING.md +0 -0
  98. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/DEMOS.md +0 -0
  99. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/DEVELOPMENT.md +0 -0
  100. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/E2E_TESTING.md +0 -0
  101. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/EXTERNAL_STORAGE.md +0 -0
  102. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/GITHUB.md +0 -0
  103. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/GOVERNANCE_BENCHMARK.md +0 -0
  104. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_data_layer.md +0 -0
  105. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_image_batch.md +0 -0
  106. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.10.0.md +0 -0
  107. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.11.0.md +0 -0
  108. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.12.0.md +0 -0
  109. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.13.0.md +0 -0
  110. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.7.0.md +0 -0
  111. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.8.1.md +0 -0
  112. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.9.0.md +0 -0
  113. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_v0.9.1.md +0 -0
  114. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/LIVE_VERIFICATION_video_download.md +0 -0
  115. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/PROJECT_STATUS.md +0 -0
  116. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/SECURITY.md +0 -0
  117. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/USER_GUIDE.md +0 -0
  118. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/assets/demo-split-pf.gif +0 -0
  119. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/assets/example-run.gif +0 -0
  120. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/schemas/movie-handoff.schema.json +0 -0
  121. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/2026-05-17-issue-15-handover.md +0 -0
  122. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/character-scenario.md +0 -0
  123. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/plans/2026-06-01-governance-enforcement-advisory/PLAN.md +0 -0
  124. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/plans/2026-06-04-character-create-recording.md +0 -0
  125. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/plans/2026-06-06-movie-p0-asyncio-hotfix.md +0 -0
  126. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/plans/2026-06-06-movie-p1-composition-manifest.md +0 -0
  127. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/plans/2026-06-06-movie-p2-native-identity-voice.md +0 -0
  128. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/specs/2026-06-06-movie-consistency-design.md +0 -0
  129. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/docs/superpowers/verifications/2026-05-11-phase-4-stage-g.md +0 -0
  130. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/examples/README.md +0 -0
  131. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/examples/batch_from_config.py +0 -0
  132. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/examples/multi_prompt_t2i.py +0 -0
  133. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/examples/sample_config.json +0 -0
  134. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/examples/sample_prompts.txt +0 -0
  135. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/examples/single_image_t2i.py +0 -0
  136. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/examples/workflow_chain.py +0 -0
  137. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/llms.txt +0 -0
  138. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/README.md +0 -0
  139. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/01_upload_image.json +0 -0
  140. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/02_batchAsyncGenerateVideoText.json +0 -0
  141. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/03_batchCheckAsyncVideoGenerationStatus.json +0 -0
  142. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/04_archive_workflow.json +0 -0
  143. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/05_createProject.json +0 -0
  144. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/06_batchGenerateImages.json +0 -0
  145. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/07_batchGenerateImages_seeded.json +0 -0
  146. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/08_batchAsyncGenerateVideoStartAndEndImage.json +0 -0
  147. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/09_batchAsyncGenerateVideoReferenceImages.json +0 -0
  148. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/10_batchCheckAsyncVideoGenerationStatus_successful.json +0 -0
  149. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/11_batchCheckAsyncVideoGenerationStatus_failed.json +0 -0
  150. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/12_create_scene.json +0 -0
  151. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/13_sceneWorkflows_update.json +0 -0
  152. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/14_get_scene_workflows.json +0 -0
  153. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/samples/captured/15_commit_flowWorkflow.json +0 -0
  154. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/ci/check_doc_links.py +0 -0
  155. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/ci/check_materiality.py +0 -0
  156. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/ci/check_repo_hygiene.py +0 -0
  157. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/debug_editor.py +0 -0
  158. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/debug_gen_settings.py +0 -0
  159. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/debug_settings.py +0 -0
  160. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/_recording_client.py +0 -0
  161. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/_spike_common.py +0 -0
  162. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/active_plan.py +0 -0
  163. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/capture_i2v_frame_slots_dom.py +0 -0
  164. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/capture_i2v_intercept_submit.py +0 -0
  165. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/capture_i2v_model_select_repro.py +0 -0
  166. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/capture_i2v_post_bind_state.py +0 -0
  167. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/capture_image_add_media_dom.py +0 -0
  168. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/capture_locale_invariants.py +0 -0
  169. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/cdp_drive_and_probe.py +0 -0
  170. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/character_create_spike.py +0 -0
  171. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/character_create_spike_v2.py +0 -0
  172. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/dump_character_selectors.js +0 -0
  173. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/make_project.py +0 -0
  174. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/materiality_backtest.py +0 -0
  175. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/monitor_pr_38.py +0 -0
  176. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/patch_character.py +0 -0
  177. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/record_flow_capture.py +0 -0
  178. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/skillopt/README.md +0 -0
  179. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/skillopt/harness.py +0 -0
  180. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/skillopt/tasks.json +0 -0
  181. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_char_editor_dom.py +0 -0
  182. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_char_gen_capture.py +0 -0
  183. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_movie_entity_recon.py +0 -0
  184. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_movie_gen_capture.py +0 -0
  185. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_movie_picker_select.py +0 -0
  186. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_movie_voice_list.py +0 -0
  187. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/dev/spike_patch_entity.py +0 -0
  188. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/record_demo.ps1 +0 -0
  189. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/smoke_image.py +0 -0
  190. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/smoke_real_chrome_image.py +0 -0
  191. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/smoke_video_editor.py +0 -0
  192. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/smoke_worker_style.py +0 -0
  193. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/scripts/verify_chrome_auth_viability.py +0 -0
  194. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/skills/README.md +0 -0
  195. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/skills/gflow-cli/SKILL.md +0 -0
  196. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/skills/plan/SKILL.md +0 -0
  197. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/skills/pr-council-review/SKILL.md +0 -0
  198. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/skills/predict/SKILL.md +0 -0
  199. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/skills/scenario/SKILL.md +0 -0
  200. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/skills/status/SKILL.md +0 -0
  201. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/sonar-project.properties +0 -0
  202. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/__main__.py +0 -0
  203. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/_cli_helpers.py +0 -0
  204. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/__init__.py +0 -0
  205. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/_retry.py +0 -0
  206. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/_sapisidhash.py +0 -0
  207. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/character.py +0 -0
  208. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/dto.py +0 -0
  209. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/image.py +0 -0
  210. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/recaptcha.py +0 -0
  211. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/scene.py +0 -0
  212. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/__init__.py +0 -0
  213. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/_common.py +0 -0
  214. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/_fingerprint.py +0 -0
  215. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/base.py +0 -0
  216. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/experimental/__init__.py +0 -0
  217. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/experimental/bearer.py +0 -0
  218. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/experimental/evaluate_fetch.py +0 -0
  219. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/transports/experimental/sapisidhash.py +0 -0
  220. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/api/video.py +0 -0
  221. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/auth/__init__.py +0 -0
  222. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/auth/base.py +0 -0
  223. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/auth/factory.py +0 -0
  224. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/auth/internal_chromium.py +0 -0
  225. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/auth/real_chrome.py +0 -0
  226. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/auth/strategies.py +0 -0
  227. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/auth/verification.py +0 -0
  228. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/browser_manager.py +0 -0
  229. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/chain.py +0 -0
  230. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/chain_manifest.py +0 -0
  231. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli.py +0 -0
  232. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_character.py +0 -0
  233. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_data.py +0 -0
  234. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_models.py +0 -0
  235. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_movie.py +0 -0
  236. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_run.py +0 -0
  237. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_scene.py +0 -0
  238. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/cli_video.py +0 -0
  239. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/composition.py +0 -0
  240. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/config.py +0 -0
  241. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/__init__.py +0 -0
  242. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/chain_repo.py +0 -0
  243. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/migrations/0001_initial.sql +0 -0
  244. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/migrations/0002_add_cloud_storage.sql +0 -0
  245. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/migrations/0003_add_scene_tables.sql +0 -0
  246. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/migrations/0004_add_scene_output_path.sql +0 -0
  247. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/migrations/0005_add_chain_links.sql +0 -0
  248. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/migrations/0006_add_operations_metadata.sql +0 -0
  249. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/migrations/__init__.py +0 -0
  250. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/models.py +0 -0
  251. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/queries.py +0 -0
  252. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/recorder.py +0 -0
  253. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/redaction.py +0 -0
  254. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/repository.py +0 -0
  255. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/data/store.py +0 -0
  256. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/image_batch.py +0 -0
  257. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/json_output.py +0 -0
  258. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/manifest.py +0 -0
  259. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/media.py +0 -0
  260. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/movie_manifest.py +0 -0
  261. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/observability.py +0 -0
  262. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/paths.py +0 -0
  263. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/profile_store.py +0 -0
  264. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/services/__init__.py +0 -0
  265. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/services/character_create.py +0 -0
  266. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/src/gflow_cli/storage.py +0 -0
  267. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tasks/lessons.md +0 -0
  268. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/test_assets/sample_batch.json +0 -0
  269. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/test_assets/sample_batch.tsv +0 -0
  270. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/test_assets/sample_batch_invalid.tsv +0 -0
  271. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/__init__.py +0 -0
  272. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/__init__.py +0 -0
  273. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/fixtures/character_gen_response.json +0 -0
  274. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/fixtures/patch_entity_response.json +0 -0
  275. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_aisandbox_auth_error.py +0 -0
  276. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_aisandbox_auth_headers.py +0 -0
  277. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_bearer_redaction.py +0 -0
  278. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_character.py +0 -0
  279. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_client.py +0 -0
  280. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_client_character.py +0 -0
  281. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_client_delete_characters.py +0 -0
  282. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_client_generate_character.py +0 -0
  283. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_client_image.py +0 -0
  284. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_client_patch_entity.py +0 -0
  285. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_client_scene.py +0 -0
  286. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_concurrency.py +0 -0
  287. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_dto.py +0 -0
  288. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_image.py +0 -0
  289. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_image_dto.py +0 -0
  290. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_post_json_aisandbox_auth.py +0 -0
  291. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_recaptcha.py +0 -0
  292. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_retry.py +0 -0
  293. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_routes.py +0 -0
  294. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_routes_character.py +0 -0
  295. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_routes_scene.py +0 -0
  296. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_sapisidhash_helper.py +0 -0
  297. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_scene_models.py +0 -0
  298. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_video.py +0 -0
  299. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/test_video_request.py +0 -0
  300. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/__init__.py +0 -0
  301. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_base.py +0 -0
  302. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_bearer.py +0 -0
  303. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_common.py +0 -0
  304. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_evaluate_fetch.py +0 -0
  305. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_factory.py +0 -0
  306. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_fingerprint.py +0 -0
  307. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_sapisidhash.py +0 -0
  308. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_transport_timeout.py +0 -0
  309. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_ui_automation_batch.py +0 -0
  310. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_ui_automation_image_mode.py +0 -0
  311. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/api/transports/test_ui_character_editor.py +0 -0
  312. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/auth/strategies/test_factory.py +0 -0
  313. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/auth/strategies/test_strategies.py +0 -0
  314. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/auth/test_verification.py +0 -0
  315. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/__init__.py +0 -0
  316. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_auth_list.py +0 -0
  317. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_character.py +0 -0
  318. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_character_create.py +0 -0
  319. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_data.py +0 -0
  320. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_image.py +0 -0
  321. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_image_seed_removed.py +0 -0
  322. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_models.py +0 -0
  323. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_movie.py +0 -0
  324. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_run.py +0 -0
  325. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_scene.py +0 -0
  326. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_video.py +0 -0
  327. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_cli_video_chain.py +0 -0
  328. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_error_handling.py +0 -0
  329. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_helpers.py +0 -0
  330. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_movie_manifest.py +0 -0
  331. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/cli/test_t2i_multi_prompt.py +0 -0
  332. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/composition/test_character.py +0 -0
  333. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/composition/test_compose_prompt.py +0 -0
  334. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/composition/test_handoff.py +0 -0
  335. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/conftest.py +0 -0
  336. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/__init__.py +0 -0
  337. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_chain_repo.py +0 -0
  338. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_find_incomplete_character.py +0 -0
  339. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_models.py +0 -0
  340. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_packaging.py +0 -0
  341. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_recorder.py +0 -0
  342. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_recorder_character.py +0 -0
  343. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_redaction.py +0 -0
  344. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_repository.py +0 -0
  345. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_scene_persistence.py +0 -0
  346. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_settings_and_errors.py +0 -0
  347. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/data/test_store_migrations.py +0 -0
  348. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/dev/test_record_flow_capture.py +0 -0
  349. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/__init__.py +0 -0
  350. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/conftest.py +0 -0
  351. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_aisandbox_auth_live.py +0 -0
  352. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_auth_verification_e2e.py +0 -0
  353. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_chain_e2e.py +0 -0
  354. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_character_create_e2e.py +0 -0
  355. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_data_layer_e2e.py +0 -0
  356. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_i2v_flags_e2e.py +0 -0
  357. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_image_batch_e2e.py +0 -0
  358. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_image_i2i_ref_cap_e2e.py +0 -0
  359. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_json_output_e2e.py +0 -0
  360. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_locale_selectors_e2e.py +0 -0
  361. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_scene_compose_live.py +0 -0
  362. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_transports_e2e.py +0 -0
  363. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_video_r2v_ref_cap_e2e.py +0 -0
  364. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/e2e/test_video_t2v_e2e.py +0 -0
  365. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/__init__.py +0 -0
  366. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/auth.feature +0 -0
  367. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/auth_login.feature +0 -0
  368. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/character_create.feature +0 -0
  369. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/character_read.feature +0 -0
  370. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/conftest.py +0 -0
  371. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/image.feature +0 -0
  372. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/test_auth_login_steps.py +0 -0
  373. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/test_auth_steps.py +0 -0
  374. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/test_character_create_steps.py +0 -0
  375. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/test_character_read_steps.py +0 -0
  376. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/test_image_steps.py +0 -0
  377. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/test_step_collision_guard.py +0 -0
  378. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/test_video_chain_steps.py +0 -0
  379. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/features/video_chain.feature +0 -0
  380. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/fixtures/__init__.py +0 -0
  381. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/fixtures/seeded_catalog.py +0 -0
  382. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/image_batch/__init__.py +0 -0
  383. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/image_batch/test_image_manifest.py +0 -0
  384. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/image_batch/test_observability_events.py +0 -0
  385. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/integration/__init__.py +0 -0
  386. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/integration/conftest.py +0 -0
  387. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/integration/constants.py +0 -0
  388. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/integration/test_storage_gcs.py +0 -0
  389. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/integration/test_storage_s3.py +0 -0
  390. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/scripts/test_capture_locale_invariants.py +0 -0
  391. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/scripts/test_check_materiality.py +0 -0
  392. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/scripts/test_check_repo_hygiene.py +0 -0
  393. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/scripts/test_materiality_backtest.py +0 -0
  394. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/services/__init__.py +0 -0
  395. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/services/test_character_create_redaction.py +0 -0
  396. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/services/test_character_create_saga.py +0 -0
  397. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/services/test_character_gen_no_direct_post.py +0 -0
  398. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/smoke/__init__.py +0 -0
  399. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/smoke/test_profile_account_smoke.py +0 -0
  400. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/smoke/test_real_flow.py +0 -0
  401. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_auth.py +0 -0
  402. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_browser_manager.py +0 -0
  403. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_chain.py +0 -0
  404. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_chain_manifest.py +0 -0
  405. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_cli_data.py +0 -0
  406. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_config.py +0 -0
  407. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_conftest_isolation.py +0 -0
  408. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_data_queries.py +0 -0
  409. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_documentation_gate.py +0 -0
  410. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_errors_403.py +0 -0
  411. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_json_output.py +0 -0
  412. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_manifest.py +0 -0
  413. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_marker_registry.py +0 -0
  414. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_media.py +0 -0
  415. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_observability.py +0 -0
  416. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_paths.py +0 -0
  417. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_profile_store.py +0 -0
  418. {gflow_cli-0.15.0 → gflow_cli-0.16.0}/tests/test_smoke.py +0 -0
@@ -76,10 +76,12 @@ The `skills/` directory ships installable agent skill docs in plain Markdown wit
76
76
  | `gflow-cli` | [`skills/gflow-cli/SKILL.md`](skills/gflow-cli/SKILL.md) | User wants to run any `gflow` command — auth, T2V, I2V, T2I, I2I, batch |
77
77
  | `predict` | [`skills/predict/SKILL.md`](skills/predict/SKILL.md) | Pre-implementation adversarial analysis before any high-stakes change |
78
78
  | `scenario` | [`skills/scenario/SKILL.md`](skills/scenario/SKILL.md) | Edge-case explorer after a predict GO/CAUTION |
79
+ | `plan` | [`skills/plan/SKILL.md`](skills/plan/SKILL.md) | Create a structured task-by-task implementation plan for a feature |
80
+ | `status` | [`skills/status/SKILL.md`](skills/status/SKILL.md) | Show current plan state, progress, and next unchecked task |
79
81
  | `pr-council-review` | [`skills/pr-council-review/SKILL.md`](skills/pr-council-review/SKILL.md) | Multi-dimensional PR council review |
80
82
 
81
83
  **Cursor / Aider / Codex / Gemini CLI:** paste or include the relevant `SKILL.md` in your system context.
82
- **Claude Code:** symlink `skills/gflow-cli` to `~/.claude/skills/gflow-cli` to register the skill; the `/gflow:` slash commands (in `.claude/commands/gflow/`) are auto-discovered from the project directory.
84
+ **Claude Code:** the `/gflow:` slash commands in `.claude/commands/gflow/` are auto-discovered when the project is open — no extra setup needed. To register a skill globally, copy the command file to `~/.claude/commands/`.
83
85
  **Custom agents:** fetch `skills/gflow-cli/SKILL.md` into your knowledge base before answering gflow questions.
84
86
 
85
87
  The SkillOpt harness at `scripts/dev/skillopt/` measures how accurately each skill guides an agent, and supports multiple providers (Anthropic, OpenAI-compat, Gemini, local models). See [`scripts/dev/skillopt/README.md`](scripts/dev/skillopt/README.md).
@@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.16.0] — 2026-06-12
11
+
12
+ ### Fixed
13
+
14
+ - **`--reference-entity` no longer fails on non-Portuguese Flow accounts** ([#170](https://github.com/ffroliva/gflow-cli/issues/170)) — the resource-picker include selectors hardcoded the pt-BR caption "Incluir no comando"; they are now locale-free tier cascades (context-menu `add`-ligature anchor + pt/ru/en text fallback), fixing `gflow image t2i --reference-entity`, movie R2V entity attach, and Vozes voice attach for every account language. Failures are now typed (`TransportTimeoutError`, exit 9) with a locale-neutral remediation hint, the matched selector tier is logged (`include_selector_tier`) for drift telemetry, and a new image-side submit backstop raises `WireFormatError` (exit 7) if a staged character never reaches the wire instead of silently returning a text-only generation. Thanks @papushin7987 for the live-verified report
15
+
16
+ ### Added
17
+
18
+ - **`gflow image upscale <mediaId> --scale 2k|4k`** — upscale a platform-generated image to 2K or 4K (Flow's download-menu 1K/2K/4K options) and save it locally; credit-free. The owning project is resolved from the local catalog (or pass `--project` for images gflow didn't record). 4K requires a Flow Ultra subscription — a non-Ultra 4K request fails fast with exit code 22 (`UpscaleUnavailableError`) rather than a generic 403. Reverse-engineered wire documented in [docs/IMAGE_UPSCALE_RECON.md](docs/IMAGE_UPSCALE_RECON.md); live-verified end-to-end (issue #171)
19
+
20
+ ## [0.15.1] — 2026-06-10
21
+
22
+ ### Changed
23
+
24
+ - Added `--disable-dev-shm-usage` to Chrome launch args in both `FlowApiClient._persistent_context_kwargs()` and `UiAutomationTransport.setup()` — prevents OOM in Docker containers with the default 64 MB `/dev/shm` allocation; no effect on developer machines with adequate shared memory
25
+ - README Stats badges hardened against shields.io outages — GitHub-stat badges now pass `cacheSeconds=3600` (mitigates shields.io's shared GitHub token-pool exhaustion, the "Unable to select next GitHub token from pool" error) and the PyPI downloads badge moved from `img.shields.io/pypi/dm` to pepy.tech (pypistats rate-limits shields.io upstream)
26
+
27
+ ### Added
28
+
29
+ - `scripts/diag/` directory — documented home for investigation scripts that require a live authenticated profile; includes `memory_profile.py` (Chrome process-tree RSS profiler for issue #155), `capture_flow_traffic.py`, and `recaptcha_mint.py` (both moved from `scripts/` root via git mv, history preserved)
30
+
31
+ ### Fixed
32
+
33
+ - Video status poll now raises `AuthExpiredError` (exit 3) immediately on HTTP 401 from `batchCheckAsyncVideoGenerationStatus` instead of silently timing out after 600 s with a bare `TimeoutError` (exit 1) — session expiry is now detected mid-workflow, not only at login time (issue #156)
34
+
10
35
  ## [0.15.0] — 2026-06-09
11
36
 
12
37
  ### Added
@@ -1469,7 +1494,9 @@ shell-script template that branches on these codes.
1469
1494
 
1470
1495
  First skeleton. Not functional end-to-end yet.
1471
1496
 
1472
- [Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.15.0...HEAD
1497
+ [Unreleased]: https://github.com/ffroliva/gflow-cli/compare/v0.16.0...HEAD
1498
+ [0.16.0]: https://github.com/ffroliva/gflow-cli/compare/v0.15.1...v0.16.0
1499
+ [0.15.1]: https://github.com/ffroliva/gflow-cli/compare/v0.15.0...v0.15.1
1473
1500
  [0.15.0]: https://github.com/ffroliva/gflow-cli/compare/v0.14.0...v0.15.0
1474
1501
  [0.14.0]: https://github.com/ffroliva/gflow-cli/compare/v0.13.0...v0.14.0
1475
1502
  [0.13.0]: https://github.com/ffroliva/gflow-cli/compare/v0.12.0...v0.13.0
@@ -14,6 +14,22 @@ Living list of behaviour that's broken, surprising, or limited by design — alo
14
14
 
15
15
  ## Open
16
16
 
17
+ ### 4K image upscale requires a Flow Ultra subscription
18
+
19
+ - **Status:** **Open** (by design — a Flow platform limit, not a gflow bug)
20
+ - **Severity:** Low · **Affects:** `gflow image upscale --scale 4k` on non-Ultra accounts
21
+
22
+ `gflow image upscale <mediaId> --scale 4k` returns **exit code 22**
23
+ (`UpscaleUnavailableError`) on accounts below the Ultra tier — Flow gates 4K
24
+ upscaling behind Ultra (the web UI shows an "Upgrade" button instead of a 4K
25
+ option). The account tier is reported on the wire as `userPaygateTier` but is
26
+ enforced server-side, so gflow cannot grant 4K locally.
27
+
28
+ **Workaround:** use `--scale 2k` (available on all tiers), or upgrade the Flow
29
+ account to Ultra. If you just upgraded, re-run `gflow auth login --profile <name>`
30
+ to refresh the session before retrying 4K. Wire detail:
31
+ [docs/IMAGE_UPSCALE_RECON.md](docs/IMAGE_UPSCALE_RECON.md) (#171).
32
+
17
33
  ### Image generation returns HTTP 401 — `aisandbox-pa` generation endpoint
18
34
 
19
35
  - **Status:** **RESOLVED in v0.7.0** — moved to [Resolved](#resolved) section
@@ -332,7 +348,7 @@ issue and not blocked by any code change in this repo.
332
348
 
333
349
  ### `UiAutomationTransport` selectors locale-agnostic — issue #24 Phase 5 complete
334
350
 
335
- - **Status:** Resolved (pending owner live e2e on non-EN profile) · **Severity:** Low · **Tracking:** [issue #24](https://github.com/ffroliva/gflow-cli/issues/24), [issue #94](https://github.com/ffroliva/gflow-cli/issues/94)
351
+ - **Status:** Resolved (pending owner live e2e on non-EN profile) · **Severity:** Low · **Tracking:** [issue #24](https://github.com/ffroliva/gflow-cli/issues/24), [issue #94](https://github.com/ffroliva/gflow-cli/issues/94), [issue #170](https://github.com/ffroliva/gflow-cli/issues/170)
336
352
 
337
353
  `--lang=en-US` removed in PR #127 (2026-05-30). All selector groups now use
338
354
  locale-stable anchors: `IMAGE_MODEL_OPTION_SELECTORS` and
@@ -343,6 +359,20 @@ issue and not blocked by any code change in this repo.
343
359
  Playwright kwarg (persists across all in-session navigations). Full resolution
344
360
  gate: live e2e with `gflow image t2i` (each model) on a non-EN Chrome profile.
345
361
 
362
+ **2026-06-12 correction (issue #170):** the "all selector groups" claim above
363
+ had two stragglers — `PICKER_INCLUDE_BUTTON` and `PICKER_CONTEXT_INCLUDE`
364
+ hardcoded the pt-BR caption "Incluir no comando", breaking
365
+ `--reference-entity` (image t2i), movie R2V entity attach, and Vozes voice
366
+ attach on every non-Portuguese account (Flow renders in the ACCOUNT language;
367
+ `?hl=en` cannot override it). Fixed by converting both constants to sequential
368
+ tier cascades — context-menu Tier 1 is the locale-free `add`-ligature menuitem
369
+ scoped to the open menu; the Vozes button has no ligature, so pt/ru/en text
370
+ leads with a lone-iconless-dialog-button structural fallback. The matched tier
371
+ is emitted as `ui_automation_video.include_selector_tier` (drift telemetry),
372
+ exhaustion raises typed `TransportTimeoutError` (exit 9) with a locale-neutral
373
+ remediation hint, and an image-side submit backstop now raises
374
+ `WireFormatError` when a requested entity never rode the wire.
375
+
346
376
  **Phase 2 progress (2026-05-25, develop / post-v0.8.1, unreleased):**
347
377
 
348
378
  - **`ONBOARDING_SELECTORS` restructured** — replaced the original 9 English/PT-BR
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gflow-cli
3
- Version: 0.15.0
3
+ Version: 0.16.0
4
4
  Summary: Unofficial CLI for Google Flow — drive Veo image-to-video generations from the terminal.
5
5
  Project-URL: Homepage, https://github.com/ffroliva/gflow-cli
6
6
  Project-URL: Issues, https://github.com/ffroliva/gflow-cli/issues
@@ -196,13 +196,13 @@ gflow CLI → Provider (interchangeable) → Flow (ui_automation) / Mock (te
196
196
 
197
197
  ## Stats
198
198
 
199
- [![GitHub stars](https://img.shields.io/github/stars/ffroliva/gflow-cli?style=social)](https://github.com/ffroliva/gflow-cli/stargazers)
200
- [![GitHub forks](https://img.shields.io/github/forks/ffroliva/gflow-cli?style=social)](https://github.com/ffroliva/gflow-cli/network/members)
201
- [![GitHub watchers](https://img.shields.io/github/watchers/ffroliva/gflow-cli?style=social)](https://github.com/ffroliva/gflow-cli/watchers)
202
- [![GitHub issues](https://img.shields.io/github/issues/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli/issues)
203
- [![GitHub pull requests](https://img.shields.io/github/issues-pr/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli/pulls)
204
- [![GitHub last commit](https://img.shields.io/github/last-commit/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli/commits/main)
205
- [![GitHub repo size](https://img.shields.io/github/repo-size/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli)
206
- [![PyPI downloads](https://img.shields.io/pypi/dm/gflow-cli.svg)](https://pypi.org/project/gflow-cli/)
199
+ [![GitHub stars](https://img.shields.io/github/stars/ffroliva/gflow-cli?style=social&cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/stargazers)
200
+ [![GitHub forks](https://img.shields.io/github/forks/ffroliva/gflow-cli?style=social&cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/network/members)
201
+ [![GitHub watchers](https://img.shields.io/github/watchers/ffroliva/gflow-cli?style=social&cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/watchers)
202
+ [![GitHub issues](https://img.shields.io/github/issues/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/issues)
203
+ [![GitHub pull requests](https://img.shields.io/github/issues-pr/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/pulls)
204
+ [![GitHub last commit](https://img.shields.io/github/last-commit/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/commits/main)
205
+ [![GitHub repo size](https://img.shields.io/github/repo-size/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli)
206
+ [![PyPI downloads](https://static.pepy.tech/badge/gflow-cli/month)](https://pepy.tech/project/gflow-cli)
207
207
 
208
208
  If `gflow-cli` saves you time, please ⭐ the repo — it is the cheapest way to support the project.
@@ -132,13 +132,13 @@ gflow CLI → Provider (interchangeable) → Flow (ui_automation) / Mock (te
132
132
 
133
133
  ## Stats
134
134
 
135
- [![GitHub stars](https://img.shields.io/github/stars/ffroliva/gflow-cli?style=social)](https://github.com/ffroliva/gflow-cli/stargazers)
136
- [![GitHub forks](https://img.shields.io/github/forks/ffroliva/gflow-cli?style=social)](https://github.com/ffroliva/gflow-cli/network/members)
137
- [![GitHub watchers](https://img.shields.io/github/watchers/ffroliva/gflow-cli?style=social)](https://github.com/ffroliva/gflow-cli/watchers)
138
- [![GitHub issues](https://img.shields.io/github/issues/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli/issues)
139
- [![GitHub pull requests](https://img.shields.io/github/issues-pr/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli/pulls)
140
- [![GitHub last commit](https://img.shields.io/github/last-commit/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli/commits/main)
141
- [![GitHub repo size](https://img.shields.io/github/repo-size/ffroliva/gflow-cli)](https://github.com/ffroliva/gflow-cli)
142
- [![PyPI downloads](https://img.shields.io/pypi/dm/gflow-cli.svg)](https://pypi.org/project/gflow-cli/)
135
+ [![GitHub stars](https://img.shields.io/github/stars/ffroliva/gflow-cli?style=social&cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/stargazers)
136
+ [![GitHub forks](https://img.shields.io/github/forks/ffroliva/gflow-cli?style=social&cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/network/members)
137
+ [![GitHub watchers](https://img.shields.io/github/watchers/ffroliva/gflow-cli?style=social&cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/watchers)
138
+ [![GitHub issues](https://img.shields.io/github/issues/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/issues)
139
+ [![GitHub pull requests](https://img.shields.io/github/issues-pr/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/pulls)
140
+ [![GitHub last commit](https://img.shields.io/github/last-commit/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli/commits/main)
141
+ [![GitHub repo size](https://img.shields.io/github/repo-size/ffroliva/gflow-cli?cacheSeconds=3600)](https://github.com/ffroliva/gflow-cli)
142
+ [![PyPI downloads](https://static.pepy.tech/badge/gflow-cli/month)](https://pepy.tech/project/gflow-cli)
143
143
 
144
144
  If `gflow-cli` saves you time, please ⭐ the repo — it is the cheapest way to support the project.
@@ -375,7 +375,8 @@ convenience later.
375
375
  generate) so Flow's JS sets `entityContext` and passes the WAF; gflow captures `media[]`/`workflows[]`
376
376
  from the response. Reuse gflow's prompt-submit + response-capture machinery (`ui_automation.py`), but in
377
377
  the character-editor context (NOT the new-project flow). Video `--character` reuse = resource picker
378
- (`Pesquisar recursos` → Personagens → *Incluir no comando*) generate; mirrors #123 `_attach_likeness`.
378
+ (search resources → Personagens → *include-in-prompt* context-menu action; captions are localized,
379
+ selectors locale-free since issue #170) → generate; mirrors #123 `_attach_likeness`.
379
380
  All selectors **ligature/structural only** (language-agnostic).
380
381
  - **Cost reality:** the feature is UI-automation-heavy (new character-editor + picker selectors), not the
381
382
  "mostly REST" earlier framing. Structural metadata is REST; the value-generating steps are UI.
@@ -0,0 +1,115 @@
1
+ # Image Upscale — Reverse-Engineering Recon
2
+
3
+ > Status: **recon complete, pre-implementation**. Wire empirically captured 2026-06-11
4
+ > (denon82 Pro account, project `ffb768fb…`). Spikes: `scripts/dev/spike_image_upscale_drive.py`
5
+ > (UI drive + capture) and `scripts/dev/spike_image_upscale_rest_probe.py` (schema + REST probe).
6
+
7
+ ## Feature
8
+
9
+ Flow's image editor download menu offers **1K Original / 2K Upscaled / 4K Upscaled**. gflow
10
+ today saves only the 1K original (the pre-signed `fifeUrl` from the generation response). This
11
+ feature adds `gflow image upscale <mediaId> --scale 2k|4k` to fetch the upscaled variant.
12
+
13
+ Scope: **platform-generated images only** (referenced by `mediaId`). Uploaded images are not
14
+ supported by this endpoint. **4K is Ultra-tier-gated**; Pro accounts see "Upgrade" in the UI.
15
+
16
+ ## Wire protocol
17
+
18
+ ### Endpoint
19
+ ```
20
+ POST https://aisandbox-pa.googleapis.com/v1/flow/upsampleImage
21
+ ```
22
+ Same host + auth class as image generation (`batchGenerateImages`).
23
+
24
+ ### Request body
25
+ ```json
26
+ {
27
+ "mediaId": "<source-image-uuid>",
28
+ "targetResolution": "UPSAMPLE_IMAGE_RESOLUTION_2K",
29
+ "clientContext": {
30
+ "recaptchaContext": {
31
+ "token": "<reCAPTCHA-Enterprise-token>",
32
+ "applicationType": "RECAPTCHA_APPLICATION_TYPE_WEB"
33
+ },
34
+ "projectId": "<project-that-owns-the-media>",
35
+ "sessionId": ";<epoch_ms>",
36
+ "tool": "PINHOLE",
37
+ "userPaygateTier": "PAYGATE_TIER_ONE"
38
+ }
39
+ }
40
+ ```
41
+ - `targetResolution` enum: `UPSAMPLE_IMAGE_RESOLUTION_2K` | `UPSAMPLE_IMAGE_RESOLUTION_4K`.
42
+ 1K = original (no API call — gflow already has it).
43
+ - **The FULL `clientContext` is required.** A minimal `{recaptchaContext}` body returns
44
+ **403 even with a valid token** (confirmed by live smoke). All five fields are needed;
45
+ `projectId` (the project owning the media) is load-bearing.
46
+ - `sessionId` format is `;<epoch_ms>` (e.g. `;1781190457842`), same as image generation.
47
+ - `userPaygateTier` is **where the account tier surfaces on the wire** (`PAYGATE_TIER_ONE`
48
+ on a Pro account). It is client-reported telemetry — the server enforces the real tier
49
+ independently (a non-Ultra 4K request 403s regardless), so it is not a security control.
50
+
51
+ ### reCAPTCHA action — `IMAGE_GENERATION`
52
+ The token MUST be minted with action **`IMAGE_GENERATION`** (uppercase). reCAPTCHA Enterprise
53
+ scores by action; the guessed `"upsampleImage"` scored low and 403'd. Captured live by hooking
54
+ `grecaptcha.enterprise.execute` (`scripts/dev/spike_image_upscale_recaptcha_action.py`). The
55
+ site key is page-discovered, so it auto-matches; minting on the bootstrap page is fine — the
56
+ action was the only gap. **Live-verified 2026-06-11**: a 2K upscale wrote a 3.8 MB JPEG.
57
+
58
+ ### Response
59
+ ```json
60
+ { "encodedImage": "<base64>" }
61
+ ```
62
+ - Single field. ~3.8–5.1 MB base64 observed (varies by source image). Decode → write image bytes.
63
+ - Synchronous: one call returns the result. **No async poll/status loop** (unlike video gen).
64
+
65
+ ## Transport decision — browser required, REST is dead
66
+
67
+ | Approach | Viable? | Evidence |
68
+ |---|---|---|
69
+ | Pure REST / Bearer-only | ❌ No | Bearer `ya29` + **no** reCAPTCHA token → **403** (probed with and without `clientContext`) |
70
+ | Browser reCAPTCHA-mint + POST | ✅ Yes | UI drive returns 200; reuses the existing `batchGenerateImages` transport |
71
+ | Hybrid (browser submit + Bearer poll) | ⚠️ N/A | No poll/download phase exists — response is synchronous inline base64 |
72
+
73
+ **Conclusion:** reCAPTCHA token is **mandatory**. Reuse the existing image-generation reCAPTCHA
74
+ minting path; there is no Bearer-only slice to peel off. See [REST-path capability matrix] — a
75
+ generative-class op stays reCAPTCHA-gated.
76
+
77
+ ## Tier gating (4K = Ultra)
78
+
79
+ - 4K is Ultra-only. On Pro, the UI renders "Fazer upgrade" (Upgrade) instead of a clickable 4K.
80
+ - Account tier is **NOT** in `GET /fx/api/auth/session` (only `user` / `expires` / `access_token`).
81
+ It surfaces via the upsell recommendations (`fetchUserRecommendations` onramp list) and is
82
+ enforced server-side. A 4K request on a non-Ultra account is expected to 403 (permission), which
83
+ must be distinguished from a WAF/reCAPTCHA 403.
84
+ - Session staleness is real: an idle session returns `error: ACCESS_TOKEN_REFRESH_NEEDED` and
85
+ re-auths before the call succeeds — so a freshly-upgraded account may need a session refresh
86
+ before 4K unlocks.
87
+
88
+ ## UI navigation facts (for the spike/transport)
89
+
90
+ - **Cold-loading `/project/<pid>/edit/<mediaId>` 500s** ("Algo deu errado"). Must land on the
91
+ gallery `/project/<pid>` then click the `a[href*=<mediaId>]` tile (in-app SPA routing).
92
+ - A "What's new" changelog modal overlays the gallery but does **not** block the href tile click.
93
+ - Working selectors (locale leaks into the UI — match language-neutral tokens):
94
+ - Download button: `button:has(i.google-symbols:text-is('download'))`
95
+ - Scale menu item: `[role='menuitem']:has-text('2K')` (and `'4K'`)
96
+ - pt labels are 1K="Tamanho original", 2K/4K="Aumentada" — **never** match on "Aumentada".
97
+
98
+ ## Implementation sketch (from `/gflow:predict` GO, 7.5/10)
99
+
100
+ - `api/routes.py`: `UPSAMPLE_IMAGE = f"{FLOW_API_BASE}/flow/upsampleImage"`.
101
+ - `api/image.py`: frozen `UpsampleImageRequest(media_id, target_resolution, recaptcha_token="")`;
102
+ `TargetResolution` enum with `from_cli("2k"|"4k")`.
103
+ - `api/client.py`: `upsample_image()` — mint reCAPTCHA (existing path), POST, validate + decode
104
+ `encodedImage` with `MAX_UPSAMPLE_B64_LEN ≈ 50 MB` cap + `del` + PNG/JPEG magic-byte check
105
+ (mirror `concatenate_scene`).
106
+ - `cli_image.py`: `gflow image upscale <mediaId> --scale 2k|4k [--out]`.
107
+ - `errors.py`: `UpscaleUnavailableError` (exit 22), distinct from WAF/reCAPTCHA 403; **no auto-retry**
108
+ on a 4K 403.
109
+ - Never log `encodedImage`. Record the output via `OperationRecorder` honoring the redaction gate.
110
+ - Discover mediaIds via the existing `gflow data list images`.
111
+
112
+ ## Credit cost
113
+
114
+ Image operation → expected **credit-free** (only video generation spends credits). Not yet
115
+ stress-confirmed; treat as free but do not batch aggressively (per-profile WAF heat).
@@ -34,9 +34,11 @@ Welcome to the `gflow-cli` documentation. This index is the routing layer: it te
34
34
  | **[docs/DATA_LAYER.md](DATA_LAYER.md)** | Local SQLite catalog: goals, schema, recording flow, redaction, `gflow data` CLI, migrations, extension guide | Anything touching `gflow_cli.data`, debugging missing rows, building I2V/repair tooling, auditing what is stored |
35
35
  | **[docs/CHARACTER.md](CHARACTER.md)** | Characters feature spec & system design: domain model, endpoint/cost matrix, sequence diagrams, JSON payloads (I/O), CLI surface, reuse via `referenceEntities` (#145) | Working on `gflow character`, reusing a character in generations, or understanding Flow's character wire protocol |
36
36
  | **[docs/MOVIE.md](MOVIE.md)** | `gflow movie` — multi-scene character-consistent films: manifest format, run lifecycle (browser stays open through generate→poll→download), entity-attach mechanism (Personagens right-click), resume/handoff, credits | Working on `gflow movie`, debugging scene generation, or understanding the character-entity attach + consistency model |
37
+ | **[docs/IMAGE_UPSCALE_RECON.md](IMAGE_UPSCALE_RECON.md)** | `gflow image upscale` wire protocol: `upsampleImage` endpoint, full clientContext (projectId/sessionId/tool/userPaygateTier), reCAPTCHA action `IMAGE_GENERATION`, inline base64 response, 4K Ultra-gating, REST-is-dead proof | Working on `gflow image upscale`, debugging the 403/reCAPTCHA path, or understanding Flow's image-upscale wire protocol (#171) |
37
38
  | **[tasks/lessons.md](../tasks/lessons.md)** | Running notebook of patterns + reviewer findings, dated and traced to commits | Starting a new phase; debugging "why did the council flag this?" |
38
39
  | **[skills/README.md](../skills/README.md)** | Installable agent skill docs (gflow-cli, predict, pr-council-review, scenario) — cross-tool portable Markdown consumed by Claude Code, Cursor, Codex, Gemini CLI, Aider, etc. | Any agent wanting to use gflow-cli correctly |
39
40
  | **[scripts/dev/skillopt/README.md](../scripts/dev/skillopt/README.md)** | SkillOpt mock harness — rollout→score loop for measuring and improving skill doc accuracy across multiple LLM providers | Measuring a skill edit's impact; comparing Claude vs GPT-4o vs Gemini on gflow tasks |
41
+ | **[scripts/diag/README.md](../scripts/diag/README.md)** | Diagnostic investigation scripts — run against a live authenticated profile to capture wire samples, measure Chrome memory, or mint reCAPTCHA tokens | Running a one-off investigation against a live Flow session; establishing baseline measurements for issue #155 |
40
42
 
41
43
  ## Agent commands
42
44
 
@@ -54,6 +56,9 @@ Slash commands for Claude Code, stored in `.claude/commands/gflow/`. All prefixe
54
56
  | `/gflow:release` | Full release flow (calls `/gflow:changelog` + `/gflow:check`) | Cutting a new version |
55
57
  | `/gflow:predict <proposal>` | 5-persona pre-implementation analysis → GO / CAUTION / STOP | Before any high-stakes design decision (new transport, auth change, selector redesign, schema migration) |
56
58
  | `/gflow:scenario <feature>` | 12-dimension edge-case explorer → severity-ranked scenario table + BDD skeleton | After predict GO/CAUTION; before `/gflow:plan` |
59
+ | `/gflow:pr-council-review [PR#]` | Multi-dimensional council review of an open PR (5 baseline + adaptive dimensions) | Before merging any non-trivial PR; mandatory for auth/transport/data changes |
60
+ | `/gflow:branch-review` | Same council review run against the current local feature branch (no PR needed) | Pre-PR self-audit; after predict/scenario on a high-stakes branch |
61
+ | `/gflow:doc-review` | Systematic council-driven audit of documentation completeness and drift | Before cutting a release; after major documentation changes |
57
62
 
58
63
  **Governance:** commands are executable docs — they decay like any doc. When a phase advances or a file path changes, update the relevant command in the same commit. `/gflow:release` includes a staleness review step.
59
64
 
@@ -90,6 +95,7 @@ Slash commands for Claude Code, stored in `.claude/commands/gflow/`. All prefixe
90
95
  **"How do I use this project's skills in Cursor / Codex / Gemini CLI / Aider?"** → [skills/README.md](../skills/README.md#use-with-other-agents)
91
96
  **"How do I benchmark a skill doc against real tasks?"** → [scripts/dev/skillopt/README.md](../scripts/dev/skillopt/README.md)
92
97
  **"How do I compare Claude vs GPT-4o vs Gemini on gflow tasks?"** → `python scripts/dev/skillopt/harness.py --provider openai --model gpt-4o` (see [skillopt README](../scripts/dev/skillopt/README.md))
98
+ **"What does Chrome actually use in RAM during a generation?"** → run `uv run python scripts/diag/memory_profile.py --profile NAME` (see [scripts/diag/README.md](../scripts/diag/README.md))
93
99
  **"How do I report a security issue?"** → [SECURITY § Reporting](SECURITY.md#reporting)
94
100
  **"What branch do I work on? How do I name it?"** → [DEVELOPMENT § Branching model](DEVELOPMENT.md#branching-model)
95
101
  **"How do I handle an external GitHub PR?"** → [GITHUB § Scenario Matrix](GITHUB.md#scenario-matrix)
@@ -104,7 +110,7 @@ Slash commands for Claude Code, stored in `.claude/commands/gflow/`. All prefixe
104
110
  **"A gflow command hangs / fails — where do I start?"** → [DEBUGGING § Quick reference](DEBUGGING.md#quick-reference)
105
111
  **"Flow's UI broke a selector — how do I diagnose it?"** → [DEBUGGING § Inspecting Flow's live UI](DEBUGGING.md#inspecting-flows-live-ui)
106
112
  **"What does each `ui_automation.*` log event mean?"** → [DEBUGGING § Listener & HTTP-layer debugging](DEBUGGING.md#listener--http-layer-debugging)
107
- **"What was actually live-verified for the latest release?"** → [LIVE_VERIFICATION_v0.13.0](LIVE_VERIFICATION_v0.13.0.md) · prior: [v0.12.0](LIVE_VERIFICATION_v0.12.0.md) · [v0.11.0](LIVE_VERIFICATION_v0.11.0.md) · [v0.10.0](LIVE_VERIFICATION_v0.10.0.md) · [v0.9.1](LIVE_VERIFICATION_v0.9.1.md)
113
+ **"What was actually live-verified for the latest release?"** → v0.15.0 / v0.14.x: no dedicated live-verification doc (CI + the v0.13.0 baseline). Latest doc: [LIVE_VERIFICATION_v0.13.0](LIVE_VERIFICATION_v0.13.0.md) · prior: [v0.12.0](LIVE_VERIFICATION_v0.12.0.md) · [v0.11.0](LIVE_VERIFICATION_v0.11.0.md) · [v0.10.0](LIVE_VERIFICATION_v0.10.0.md) · [v0.9.1](LIVE_VERIFICATION_v0.9.1.md)
108
114
  **"What was live-verified for the data layer (PR #58)?"** → [LIVE_VERIFICATION_data_layer](LIVE_VERIFICATION_data_layer.md) — 1 Imagen + 1 Veo credit on denon82, 6-layer ledger (file + magic + Pillow + DB rows + CLI round-trip + structlog)
109
115
  **"What was live-verified for the video-download feature (#29)?"** → [LIVE_VERIFICATION_video_download](LIVE_VERIFICATION_video_download.md)
110
116
  **"What is the jitter matrix evidence for `gflow image batch`?"** → [`LIVE_VERIFICATION_image_batch.md`](LIVE_VERIFICATION_image_batch.md) — jitter matrix evidence for `gflow image batch` (always-same-project mode)
@@ -100,10 +100,13 @@ attached by driving Flow's resource picker:
100
100
  1. Click **Add Media** in the composer (references sub-mode).
101
101
  2. Switch to the **Personagens** (Characters) tab.
102
102
  3. **Right-click** the entity tile — addressed by entity id as
103
- `data-tile-id="fe_id_<entityId>"` — and choose **"Incluir no comando"** from
104
- the context menu. *(A plain left-click navigates into the character editor;
105
- the inline "Incluir" button on the **Tudo** tab attaches the character's
106
- thumbnail as a plain image, not the entity.)*
103
+ `data-tile-id="fe_id_<entityId>"` — and choose the **include-in-prompt**
104
+ action from the context menu (the `add`-ligature menu item; its caption is
105
+ localized per account language, e.g. "Incluir no comando" on pt-BR or
106
+ "Добавить в запрос" on ru selectors are locale-free since issue #170).
107
+ *(A plain left-click navigates into the character editor; the inline include
108
+ button on the **Tudo** tab attaches the character's thumbnail as a plain
109
+ image, not the entity.)*
107
110
 
108
111
  This puts `referenceEntities:[{entityId}]` on the
109
112
  `video:batchAsyncGenerateVideoReferenceImages` **request**. Flow's **response**
@@ -105,6 +105,44 @@ UUID=$(gflow image upload hero.png | awk '/Asset UUID:/ {print $3}')
105
105
  gflow image i2i "make it cinematic" --ref "$UUID"
106
106
  ```
107
107
 
108
+ ## `gflow image upscale`
109
+
110
+ Upscale a **platform-generated** image to 2K or 4K (the same 1K/2K/4K options Flow's
111
+ download menu offers) and save it locally. Uploaded images are not supported.
112
+
113
+ ```text
114
+ gflow image upscale MEDIA_ID --scale 2k|4k [OPTIONS]
115
+
116
+ Arguments:
117
+ MEDIA_ID UUID of a Flow-generated image (find one with
118
+ `gflow data list images`).
119
+
120
+ Options:
121
+ --scale [2k|4k] Target resolution. 4k requires a Flow Ultra
122
+ subscription; 1k is the original (no upscale).
123
+ --project ID Project that owns the image. Resolved from the local
124
+ catalog when omitted; pass it explicitly for images
125
+ gflow didn't record (e.g. generated in the web UI).
126
+ --out PATH Output directory (see "Output paths" below).
127
+ --profile NAME Profile name (overrides default).
128
+ ```
129
+
130
+ ```bash
131
+ # Upscale a previously generated image to 2K (project auto-resolved from the catalog)
132
+ gflow image upscale 3a56bb5e-92a2-44f4-9992-3c6a9bf0cd14 --scale 2k
133
+
134
+ # Upscale an image generated in the Flow web UI (not in the local catalog)
135
+ gflow image upscale <mediaId> --scale 2k --project <projectId>
136
+ ```
137
+
138
+ Notes:
139
+
140
+ - **Credit-free** — upscaling is an image operation and spends no credits.
141
+ - **4K is Ultra-only.** On a non-Ultra account a 4K request fails with exit code 22
142
+ (`UpscaleUnavailableError`) and a hint to use `--scale 2k` or upgrade.
143
+ - The result is saved as `<output_dir>/images/<YYYY-MM-DD>/<mediaId>_<scale>.<ext>`
144
+ (extension matches the returned format — usually `.jpg`).
145
+
108
146
  ## `gflow image t2i`
109
147
 
110
148
  Generate 1–4 images from one text prompt, or run a shell-friendly batch of 1–50
@@ -0,0 +1,206 @@
1
+ # Image Upscale Implementation Plan
2
+
3
+ > **For agentic workers:** Run `/gflow:status --feature image-upscale` to find the next
4
+ > unchecked task. Implement one task at a time. Run `/gflow:check` before every commit.
5
+
6
+ **Goal:** Add `gflow image upscale <mediaId> --scale 2k|4k` so a user can fetch Flow's
7
+ server-side 2K/4K upscaled variant of a platform-generated image and save it locally.
8
+
9
+ **Architecture:** Reuses the existing image-generation reCAPTCHA browser transport — same host
10
+ (`aisandbox-pa.googleapis.com`) and `recaptchaContext` shape as `batchGenerateImages`. New work is
11
+ glue: a route constant, a frozen request value object, a synchronous `FlowApiClient.upsample_image()`
12
+ that mints a reCAPTCHA token, POSTs, and decodes the inline `{encodedImage: base64}` (mirroring
13
+ `concatenate_scene`'s cap + `del` + magic-byte pattern), a new exit-coded error, and a Click
14
+ subcommand. No transport-Protocol change (it's a client-level op like `concatenate_scene`). No new
15
+ auth, no new persistent state, no async poll loop.
16
+
17
+ **Tracking issue:** [#171](https://github.com/ffroliva/gflow-cli/issues/171)
18
+
19
+ **Predict verdict:** GO — confidence 7.5/10. Recon: `docs/IMAGE_UPSCALE_RECON.md`. Scenario matrix
20
+ complete (20 scenarios; 12 Critical/High are must-cover).
21
+
22
+ **Risk register:**
23
+ | Severity | Risk | Mitigation |
24
+ |---|---|---|
25
+ | Critical | 403 ambiguity: tier-gate (4K/Pro) vs WAF heat vs expired token all return 403 | Disambiguate by response context; `UpscaleUnavailableError` (exit 22) for tier; **never auto-retry** a 4K 403 |
26
+ | Critical | ~5 MB `encodedImage` base64 leaks into logs / error context | Never log the field; decode then `del`; structlog carries size only |
27
+ | High | Pathological oversized base64 (4K PNG) → OOM | `MAX_UPSAMPLE_B64_LEN` (~50 MB) cap **before** decode; typed error |
28
+ | High | Response missing `encodedImage` / decodes to non-image | `WireFormatError` (redacted discovery payload); PNG/JPEG magic-byte check |
29
+ | High | Per-profile reCAPTCHA/WAF heat (a 4th gated op) | One upscale per invocation; no implicit batch; document the heat |
30
+ | High | mediaId injection / malformed input | UUID allowlist; reject before any request fires |
31
+ | Medium | Selector drift (download button / scale menu) on Flow UI update | Structural-first, locale-neutral selectors (`download`, `2K`/`4K`); re-capture via spike |
32
+
33
+ ---
34
+
35
+ ## File structure
36
+
37
+ ### New files
38
+ ```
39
+ src/gflow_cli/api/image_upscale.py (or extend api/image.py)
40
+ UpsampleImageRequest frozen dataclass + TargetResolution enum (from_cli "2k"/"4k")
41
+ tests/api/test_image_upscale.py
42
+ Unit tests: request build, response parse (cap/magic-byte/missing-field), 403 disambiguation
43
+ tests/features/image_upscale.feature
44
+ BDD scenarios from /gflow:scenario (happy 2K, 4K-on-Pro, oversized, malformed mediaId)
45
+ tests/features/test_image_upscale_steps.py
46
+ Step defs mirroring runtime signatures
47
+ ```
48
+
49
+ ### Modified files
50
+ ```
51
+ src/gflow_cli/api/routes.py
52
+ + UPSAMPLE_IMAGE = f"{FLOW_API_BASE}/flow/upsampleImage"
53
+ src/gflow_cli/api/client.py
54
+ + MAX_UPSAMPLE_B64_LEN; + async def upsample_image(media_id, target_resolution, out_path)
55
+ (mint reCAPTCHA via _mint_recaptcha_token; POST; cap+decode+magic-byte; write via image_output_path)
56
+ src/gflow_cli/errors.py
57
+ + UpscaleUnavailableError (exit 22) registered in EXIT_CODE_MAP; distinct from WAF/reCAPTCHA 403
58
+ src/gflow_cli/cli_image.py
59
+ + `upscale` Click command: <mediaId> arg, --scale Choice(['2k','4k']), --out, --profile
60
+ src/gflow_cli/paths.py
61
+ (reuse image_output_path; add <mediaId>_<scale> naming if needed)
62
+ docs/USAGE.md, README.md, docs/INDEX.md, CHANGELOG.md
63
+ document the command + the platform-only / Ultra-only constraints
64
+ ```
65
+
66
+ ---
67
+
68
+ ## Task 1 — Error type + exit code (test-first)
69
+
70
+ **What:** Add `UpscaleUnavailableError` (exit 22) for tier-gated/permission failures, distinct from WAF/reCAPTCHA 403.
71
+
72
+ **Files:**
73
+ - `tests/test_errors.py` — assert exit code 22, EXIT_CODE_MAP registration, ordering invariant
74
+ - `src/gflow_cli/errors.py` — new class + map entry
75
+
76
+ **Steps:**
77
+ - [x] Red test: `UpscaleUnavailableError` maps to 22; not equal to WAF 403 code
78
+ - [x] Add the class (RFC 9457 fields: type/title/status/detail/remediation_hint) + register in `EXIT_CODE_MAP`
79
+ - [x] Verify `test_exit_code_map_ordering_invariant` still passes (inheritance trap — see memory)
80
+
81
+ **Tests created (red):**
82
+ - [x] `test_upscale_unavailable_exit_code` — exit 22, distinct from WAF/reCAPTCHA
83
+
84
+ ---
85
+
86
+ ## Task 2 — Value objects (test-first)
87
+
88
+ **What:** `TargetResolution` enum (`2K`/`4K` ↔ wire `UPSAMPLE_IMAGE_RESOLUTION_*`, `from_cli`) and frozen `UpsampleImageRequest`.
89
+
90
+ **Files:**
91
+ - `tests/api/test_image_upscale.py` — enum mapping, `from_cli` rejects bad values, request immutability
92
+ - `src/gflow_cli/api/image.py` (or new `image_upscale.py`) — enum + dataclass + body builder
93
+
94
+ **Steps:**
95
+ - [x] Red tests: `TargetResolution.from_cli("2k")` → enum; `"1k"`/`"8k"` rejected; request frozen
96
+ - [x] Add enum + `UpsampleImageRequest(media_id, target_resolution, recaptcha_token="")`
97
+ - [x] Body builder → `{mediaId, targetResolution, clientContext:{recaptchaContext:{token}}}`
98
+ - [x] mediaId UUID-allowlist validation (reject malformed before request)
99
+
100
+ **Tests created (red):**
101
+ - [x] `test_target_resolution_from_cli` / `test_target_resolution_rejects_1k_and_unknown`
102
+ - [x] `test_upsample_request_body_shape`
103
+ - [x] `test_media_id_uuid_validation`
104
+
105
+ ---
106
+
107
+ ## Task 3 — Client `upsample_image()` (test-first)
108
+
109
+ **What:** Synchronous client method: mint reCAPTCHA, POST `upsampleImage`, parse `{encodedImage}` with cap + magic-byte, write file. Route constant added.
110
+
111
+ **Files:**
112
+ - `tests/api/test_image_upscale.py` — mocked transport/HTTP: happy path, oversized cap, missing field, non-image bytes, 403→typed error, no-retry on 4K 403, `encodedImage` never logged
113
+ - `src/gflow_cli/api/routes.py` — `UPSAMPLE_IMAGE`
114
+ - `src/gflow_cli/api/client.py` — `MAX_UPSAMPLE_B64_LEN = 50 * 1024 * 1024`; `upsample_image(...)`
115
+
116
+ **Steps:**
117
+ - [x] Red tests for: 200 happy (decode → PNG/JPEG bytes written); response > cap → typed error before decode; missing `encodedImage` → `WireFormatError` (redacted); decoded bytes fail magic-byte → typed error
118
+ - [x] Red tests for 403 disambiguation: tier 403 → `UpscaleUnavailableError` (no retry); WAF 403 → existing `WafRejectionError`; expired-token 401 → existing refresh+single-retry
119
+ - [x] Red test: structlog capture asserts `encodedImage` value never present in any event
120
+ - [x] Add route + method; reuse `_mint_recaptcha_token("upscaleImage" or correct action)`; single Page checkout (no nested checkout — use `context.request` if aux call needed)
121
+ - [x] Decode mirrors `concatenate_scene` (cap → `b64decode` → magic-byte → `del encoded`)
122
+ - [x] Write via `paths.image_output_path` as `<mediaId>_<scale>.<ext>` (ext from magic byte)
123
+
124
+ **Tests created (red):**
125
+ - [x] `test_upsample_happy_2k`, `test_upsample_oversized_rejected`, `test_upsample_missing_field`,
126
+ `test_upsample_non_image_bytes`, `test_upsample_4k_pro_403_no_retry`,
127
+ `test_upsample_waf_403_distinct`, `test_upsample_encoded_image_never_logged`
128
+
129
+ ---
130
+
131
+ ## Task 4 — CLI surface (test-first)
132
+
133
+ **What:** `gflow image upscale <mediaId> --scale 2k|4k [--out] [--profile]` with self-contained `--help`.
134
+
135
+ **Files:**
136
+ - `tests/test_cli_image.py` — Click invocation: arg/flag parsing, `--scale` Choice, exit codes, 4K/Pro hint, malformed mediaId usage error (no request), structlog `upscale_started/completed/unavailable`
137
+ - `src/gflow_cli/cli_image.py` — `upscale` command
138
+
139
+ **Steps:**
140
+ - [x] Red tests: happy invocation calls `upsample_image` with mapped enum; `--scale 8k` rejected by Click; `--scale 1k` rejected with "1k is the original" hint; malformed mediaId → usage error, no HTTP
141
+ - [x] Red test: 4K-on-Pro path surfaces exit 22 + Ultra-only remediation; no auto-retry
142
+ - [x] Implement command; emit `upscale_started/completed/unavailable` (stable keys); `--help` states platform-only + Ultra-only constraints + "find mediaId via `gflow data list images`"
143
+ - [x] Record the output asset via `OperationRecorder` honoring the redaction gate; wrap callback in try/except `DataStoreError`
144
+
145
+ **Tests created (red):**
146
+ - [x] `test_upscale_cli_happy`, `test_upscale_cli_scale_choice`, `test_upscale_cli_1k_rejected`,
147
+ `test_upscale_cli_bad_media_id`, `test_upscale_cli_4k_pro_exit22`
148
+
149
+ ---
150
+
151
+ ## Task 5 — BDD scaffold + green
152
+
153
+ **What:** Gherkin feature covering all Critical+High scenarios; step defs mirror runtime signatures.
154
+
155
+ **Files:**
156
+ - `tests/features/image_upscale.feature` — happy 2K, 4K-on-Pro, oversized, malformed mediaId
157
+ - `tests/features/test_image_upscale_steps.py` — typed step defs (mirror signatures — see memory)
158
+
159
+ **Steps:**
160
+ - [x] Add the four `/gflow:scenario` BDD scenarios as a feature file
161
+ - [x] Implement step defs against the real command; assert exit codes + redaction
162
+ - [x] All BDD green
163
+
164
+ **Tests created:**
165
+ - [x] BDD: 2K happy, 4K/Pro exit 22, oversized rejected, malformed mediaId usage error
166
+
167
+ ---
168
+
169
+ ## Task 6 — Docs + recon finalize
170
+
171
+ **What:** User-facing docs + cross-references; recon already written.
172
+
173
+ **Files:**
174
+ - `docs/USAGE.md` — `gflow image upscale` section (workflow: `data list images` → `upscale`)
175
+ - `README.md` command table; `docs/INDEX.md` route to `IMAGE_UPSCALE_RECON.md`
176
+ - `docs/KNOWN_ISSUES.md` — note 4K Ultra-gating + per-profile WAF heat from the extra gated op
177
+ - `CHANGELOG.md` `[Unreleased]` — `feat(image): upscale to 2K/4K (#171)`
178
+
179
+ **Steps:**
180
+ - [x] Write usage + constraints (platform-only, Ultra-only, credit-free expectation)
181
+ - [x] Index the recon doc; cross-link spikes
182
+ - [x] CHANGELOG entry referencing #171
183
+
184
+ ---
185
+
186
+ ## Task 7 — Full gates + PR
187
+
188
+ **What:** Green `/gflow:check`; open PR to `develop`.
189
+
190
+ **Steps:**
191
+ - [x] `/gflow:check` green (ruff + format + `pyright src` + pytest ≥ 80% on changed dirs)
192
+ - [x] Live smoke (opt-in, supervised): one real 2K upscale on a known mediaId (credit-free) confirms wire still matches
193
+ - [x] PR `feature/image-upscale` → `develop`, `Closes #171`
194
+
195
+ ---
196
+
197
+ ## Definition of done
198
+
199
+ - [x] All task steps checked off
200
+ - [x] `/gflow:check` green (ruff / format / pyright / pytest ≥ 80% coverage)
201
+ - [x] `CHANGELOG.md` `[Unreleased]` updated (`#171`)
202
+ - [x] Docs updated (`USAGE.md`, `README.md`, `INDEX.md`, `KNOWN_ISSUES.md`)
203
+ - [x] BDD feature covers all Critical + High scenarios from `/gflow:scenario`
204
+ - [x] `encodedImage` proven absent from logs (test) — Critical mitigation verified
205
+ - [x] 4K/Pro 403 → exit 22, no auto-retry — Critical mitigation verified
206
+ - [x] No `# TODO` in diff without a tracked issue link