simplicio-video 0.5.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 (305) hide show
  1. simplicio_video-0.5.0/CHANGELOG.md +266 -0
  2. simplicio_video-0.5.0/LICENSE +661 -0
  3. simplicio_video-0.5.0/NOTICE +9 -0
  4. simplicio_video-0.5.0/PKG-INFO +108 -0
  5. simplicio_video-0.5.0/PYPI.md +67 -0
  6. simplicio_video-0.5.0/pyproject.toml +82 -0
  7. simplicio_video-0.5.0/setup.cfg +4 -0
  8. simplicio_video-0.5.0/src/simplicio_video/__init__.py +4 -0
  9. simplicio_video-0.5.0/src/simplicio_video/__main__.py +5 -0
  10. simplicio_video-0.5.0/src/simplicio_video/aio.py +88 -0
  11. simplicio_video-0.5.0/src/simplicio_video/auth.py +493 -0
  12. simplicio_video-0.5.0/src/simplicio_video/busca.py +1194 -0
  13. simplicio_video-0.5.0/src/simplicio_video/busca_ajuda.py +51 -0
  14. simplicio_video-0.5.0/src/simplicio_video/catalog.py +36 -0
  15. simplicio_video-0.5.0/src/simplicio_video/cli.py +749 -0
  16. simplicio_video-0.5.0/src/simplicio_video/clone.py +46 -0
  17. simplicio_video-0.5.0/src/simplicio_video/commands/__init__.py +0 -0
  18. simplicio_video-0.5.0/src/simplicio_video/commands/doctor.py +363 -0
  19. simplicio_video-0.5.0/src/simplicio_video/commands/install.py +290 -0
  20. simplicio_video-0.5.0/src/simplicio_video/commands/login.py +333 -0
  21. simplicio_video-0.5.0/src/simplicio_video/commands/setup.py +76 -0
  22. simplicio_video-0.5.0/src/simplicio_video/commands/update.py +561 -0
  23. simplicio_video-0.5.0/src/simplicio_video/compiler.py +194 -0
  24. simplicio_video-0.5.0/src/simplicio_video/contract.py +247 -0
  25. simplicio_video-0.5.0/src/simplicio_video/data/angles/angles.json +456 -0
  26. simplicio_video-0.5.0/src/simplicio_video/data/busca/cache.schema.json +179 -0
  27. simplicio_video-0.5.0/src/simplicio_video/data/busca/contador.schema.json +25 -0
  28. simplicio_video-0.5.0/src/simplicio_video/data/busca/registro.schema.json +137 -0
  29. simplicio_video-0.5.0/src/simplicio_video/data/busca/tinyfish.json +113 -0
  30. simplicio_video-0.5.0/src/simplicio_video/data/busca/tinyfish.schema.json +75 -0
  31. simplicio_video-0.5.0/src/simplicio_video/data/formats/formats.json +1094 -0
  32. simplicio_video-0.5.0/src/simplicio_video/data/formats/instrucoes.md +16 -0
  33. simplicio_video-0.5.0/src/simplicio_video/data/motion/README.md +117 -0
  34. simplicio_video-0.5.0/src/simplicio_video/data/motion/assets/fonts/Anton-Regular.ttf +0 -0
  35. simplicio_video-0.5.0/src/simplicio_video/data/motion/assets/fonts/Fredoka.ttf +0 -0
  36. simplicio_video-0.5.0/src/simplicio_video/data/motion/assets/fonts/Inter.ttf +0 -0
  37. simplicio_video-0.5.0/src/simplicio_video/data/motion/assets/fonts/OFL-Anton.txt +93 -0
  38. simplicio_video-0.5.0/src/simplicio_video/data/motion/assets/fonts/OFL-Fredoka.txt +93 -0
  39. simplicio_video-0.5.0/src/simplicio_video/data/motion/assets/fonts/OFL-Inter.txt +93 -0
  40. simplicio_video-0.5.0/src/simplicio_video/data/motion/assets/placeholder-logo.svg +4 -0
  41. simplicio_video-0.5.0/src/simplicio_video/data/motion/assets/placeholder-photo.svg +7 -0
  42. simplicio_video-0.5.0/src/simplicio_video/data/motion/catalog.json +1135 -0
  43. simplicio_video-0.5.0/src/simplicio_video/data/motion/lib/retime.js +32 -0
  44. simplicio_video-0.5.0/src/simplicio_video/data/motion/pattern.schema.json +176 -0
  45. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/balloons-confetti/block.html +85 -0
  46. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/balloons-confetti/pattern.json +94 -0
  47. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/balloons-confetti/preview.png +0 -0
  48. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/beat-burst/block.html +84 -0
  49. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/beat-burst/pattern.json +107 -0
  50. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/beat-burst/preview.png +0 -0
  51. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/beat-cut-accelerate/pattern.json +19 -0
  52. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/before-after-slider/pattern.json +18 -0
  53. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/bg-grid-glow-particles/block.html +73 -0
  54. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/bg-grid-glow-particles/pattern.json +57 -0
  55. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/bg-grid-glow-particles/preview.png +0 -0
  56. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/bg-parallax/block.html +96 -0
  57. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/bg-parallax/pattern.json +95 -0
  58. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/bg-parallax/preview.png +0 -0
  59. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/brand-lockup-soft/block.html +102 -0
  60. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/brand-lockup-soft/pattern.json +159 -0
  61. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/brand-lockup-soft/preview.png +0 -0
  62. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/caption-word-highlight/block.html +70 -0
  63. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/caption-word-highlight/pattern.json +58 -0
  64. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/caption-word-highlight/preview.png +0 -0
  65. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/card-3d-pushin-sweep/block.html +67 -0
  66. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/card-3d-pushin-sweep/pattern.json +58 -0
  67. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/card-3d-pushin-sweep/preview.png +0 -0
  68. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/card-flip-reveal/pattern.json +18 -0
  69. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/carousel-emphasis/pattern.json +19 -0
  70. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/circle-iris-transition/block.html +71 -0
  71. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/circle-iris-transition/pattern.json +70 -0
  72. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/circle-iris-transition/preview.png +0 -0
  73. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/cliptitle-chip-cascade/block.html +69 -0
  74. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/cliptitle-chip-cascade/pattern.json +65 -0
  75. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/cliptitle-chip-cascade/preview.png +0 -0
  76. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/counter-confetti/pattern.json +18 -0
  77. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/crash-zoom-punch/pattern.json +18 -0
  78. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/cta-button-spring/block.html +68 -0
  79. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/cta-button-spring/pattern.json +80 -0
  80. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/cta-button-spring/preview.png +0 -0
  81. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/foreground-fly-through/pattern.json +19 -0
  82. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/fx-transition/block.html +97 -0
  83. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/fx-transition/pattern.json +92 -0
  84. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/fx-transition/preview.png +0 -0
  85. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/hook-3s-retention/pattern.json +19 -0
  86. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/hud-scan-photo/block.html +72 -0
  87. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/hud-scan-photo/pattern.json +58 -0
  88. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/hud-scan-photo/preview.png +0 -0
  89. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/icon-mascot/block.html +139 -0
  90. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/icon-mascot/pattern.json +137 -0
  91. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/icon-mascot/preview.png +0 -0
  92. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/infinite-zoom-collage/pattern.json +18 -0
  93. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/item-relay-counter/block.html +82 -0
  94. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/item-relay-counter/pattern.json +65 -0
  95. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/item-relay-counter/preview.png +0 -0
  96. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/kinetic-bounce-title/block.html +81 -0
  97. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/kinetic-bounce-title/pattern.json +115 -0
  98. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/kinetic-bounce-title/preview.png +0 -0
  99. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/kinetic-letters-punch/block.html +73 -0
  100. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/kinetic-letters-punch/pattern.json +73 -0
  101. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/kinetic-letters-punch/preview.png +0 -0
  102. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/kinetic-words/block.html +97 -0
  103. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/kinetic-words/pattern.json +109 -0
  104. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/kinetic-words/preview.png +0 -0
  105. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/line-accent/block.html +79 -0
  106. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/line-accent/pattern.json +108 -0
  107. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/line-accent/preview.png +0 -0
  108. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/logo-drop-shockwave/block.html +75 -0
  109. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/logo-drop-shockwave/pattern.json +63 -0
  110. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/logo-drop-shockwave/preview.png +0 -0
  111. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/logo-portal/pattern.json +19 -0
  112. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/logo-shrink-lockup/pattern.json +18 -0
  113. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/logo-wireframe-shards/block.html +77 -0
  114. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/logo-wireframe-shards/pattern.json +64 -0
  115. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/logo-wireframe-shards/preview.png +0 -0
  116. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/marker-underline-title/block.html +65 -0
  117. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/marker-underline-title/pattern.json +65 -0
  118. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/marker-underline-title/preview.png +0 -0
  119. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/materializing-result/pattern.json +19 -0
  120. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/odometer-digit-roll/block.html +77 -0
  121. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/odometer-digit-roll/pattern.json +58 -0
  122. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/odometer-digit-roll/preview.png +0 -0
  123. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/one-shape-morph/block.html +74 -0
  124. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/one-shape-morph/pattern.json +58 -0
  125. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/one-shape-morph/preview.png +0 -0
  126. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/process-timeline/block.html +71 -0
  127. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/process-timeline/pattern.json +64 -0
  128. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/process-timeline/preview.png +0 -0
  129. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/reactive-icon-controller/pattern.json +19 -0
  130. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/recipe-ingredients-explainer/pattern.json +18 -0
  131. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/retime-piecewise/pattern.json +22 -0
  132. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/scramble-text/block.html +69 -0
  133. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/scramble-text/pattern.json +57 -0
  134. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/scramble-text/preview.png +0 -0
  135. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/selection-expansion/pattern.json +19 -0
  136. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/service-illustrations-wjr/pattern.json +20 -0
  137. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/service-panels-slide/block.html +88 -0
  138. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/service-panels-slide/pattern.json +71 -0
  139. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/service-panels-slide/preview.png +0 -0
  140. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/showreel-15s-techniques/pattern.json +18 -0
  141. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/spending-simulation-9x16/pattern.json +19 -0
  142. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/split-flap-title/pattern.json +19 -0
  143. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/spotlight-sweep/pattern.json +18 -0
  144. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/tooth-character/block.html +101 -0
  145. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/tooth-character/pattern.json +125 -0
  146. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/tooth-character/preview.png +0 -0
  147. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/toothbrush-sparkle/block.html +111 -0
  148. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/toothbrush-sparkle/pattern.json +112 -0
  149. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/toothbrush-sparkle/preview.png +0 -0
  150. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/transition-glitch-rgb/block.html +74 -0
  151. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/transition-glitch-rgb/pattern.json +71 -0
  152. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/transition-glitch-rgb/preview.png +0 -0
  153. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/ugc-replicate-structure/pattern.json +18 -0
  154. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/word-mask-highlight/block.html +67 -0
  155. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/word-mask-highlight/pattern.json +65 -0
  156. simplicio_video-0.5.0/src/simplicio_video/data/motion/patterns/word-mask-highlight/preview.png +0 -0
  157. simplicio_video-0.5.0/src/simplicio_video/data/motion/scripts/catalog.mjs +43 -0
  158. simplicio_video-0.5.0/src/simplicio_video/data/motion/scripts/preview.sh +54 -0
  159. simplicio_video-0.5.0/src/simplicio_video/data/openverse/api.json +135 -0
  160. simplicio_video-0.5.0/src/simplicio_video/data/openverse/api.schema.json +68 -0
  161. simplicio_video-0.5.0/src/simplicio_video/data/openverse/library.schema.json +301 -0
  162. simplicio_video-0.5.0/src/simplicio_video/data/openverse/licenses.json +112 -0
  163. simplicio_video-0.5.0/src/simplicio_video/data/openverse/licenses.schema.json +93 -0
  164. simplicio_video-0.5.0/src/simplicio_video/data/schema/contract.schema.json +180 -0
  165. simplicio_video-0.5.0/src/simplicio_video/data/schemas/cli/auth-status.schema.json +148 -0
  166. simplicio_video-0.5.0/src/simplicio_video/data/schemas/cli/doctor.schema.json +87 -0
  167. simplicio_video-0.5.0/src/simplicio_video/data/schemas/cli/install-ownership.schema.json +82 -0
  168. simplicio_video-0.5.0/src/simplicio_video/data/schemas/cli/install-plan.schema.json +529 -0
  169. simplicio_video-0.5.0/src/simplicio_video/data/schemas/cli/login.schema.json +184 -0
  170. simplicio_video-0.5.0/src/simplicio_video/data/schemas/cli/logout.schema.json +62 -0
  171. simplicio_video-0.5.0/src/simplicio_video/data/schemas/cli/preview-manifest.schema.json +37 -0
  172. simplicio_video-0.5.0/src/simplicio_video/data/schemas/cli/render-manifest.schema.json +87 -0
  173. simplicio_video-0.5.0/src/simplicio_video/data/schemas/cli/render-result.schema.json +35 -0
  174. simplicio_video-0.5.0/src/simplicio_video/data/schemas/cli/run-result.schema.json +50 -0
  175. simplicio_video-0.5.0/src/simplicio_video/data/schemas/cli/update-check.schema.json +58 -0
  176. simplicio_video-0.5.0/src/simplicio_video/data/schemas/cli/validate-result.schema.json +34 -0
  177. simplicio_video-0.5.0/src/simplicio_video/data/schemas/video-spec.schema.json +247 -0
  178. simplicio_video-0.5.0/src/simplicio_video/data/skills/simplicio-video/SKILL.md +143 -0
  179. simplicio_video-0.5.0/src/simplicio_video/data/skills/simplicio-video-social/SKILL.md +63 -0
  180. simplicio_video-0.5.0/src/simplicio_video/data/social/limits.json +495 -0
  181. simplicio_video-0.5.0/src/simplicio_video/data/social/limits.schema.json +136 -0
  182. simplicio_video-0.5.0/src/simplicio_video/data/social/providers.json +469 -0
  183. simplicio_video-0.5.0/src/simplicio_video/data/social/providers.schema.json +231 -0
  184. simplicio_video-0.5.0/src/simplicio_video/data/templates/README.md +37 -0
  185. simplicio_video-0.5.0/src/simplicio_video/data/templates/alimentacao/README.md +24 -0
  186. simplicio_video-0.5.0/src/simplicio_video/data/templates/alimentacao/template.json +117 -0
  187. simplicio_video-0.5.0/src/simplicio_video/data/templates/assistencia-tecnica-games/README.md +30 -0
  188. simplicio_video-0.5.0/src/simplicio_video/data/templates/assistencia-tecnica-games/composition/assets/fonts/Anton-Regular.ttf +0 -0
  189. simplicio_video-0.5.0/src/simplicio_video/data/templates/assistencia-tecnica-games/composition/assets/fonts/Inter.ttf +0 -0
  190. simplicio_video-0.5.0/src/simplicio_video/data/templates/assistencia-tecnica-games/composition/assets/fonts/OFL-Anton.txt +93 -0
  191. simplicio_video-0.5.0/src/simplicio_video/data/templates/assistencia-tecnica-games/composition/assets/fonts/OFL-Inter.txt +93 -0
  192. simplicio_video-0.5.0/src/simplicio_video/data/templates/assistencia-tecnica-games/composition/assets/placeholders/logo.svg +7 -0
  193. simplicio_video-0.5.0/src/simplicio_video/data/templates/assistencia-tecnica-games/composition/assets/placeholders/photo-bench.svg +7 -0
  194. simplicio_video-0.5.0/src/simplicio_video/data/templates/assistencia-tecnica-games/composition/assets/placeholders/photo-hero.svg +7 -0
  195. simplicio_video-0.5.0/src/simplicio_video/data/templates/assistencia-tecnica-games/composition/hyperframes.json +6 -0
  196. simplicio_video-0.5.0/src/simplicio_video/data/templates/assistencia-tecnica-games/composition/index.template.html +609 -0
  197. simplicio_video-0.5.0/src/simplicio_video/data/templates/assistencia-tecnica-games/template.json +159 -0
  198. simplicio_video-0.5.0/src/simplicio_video/data/templates/beleza-estetica/README.md +24 -0
  199. simplicio_video-0.5.0/src/simplicio_video/data/templates/beleza-estetica/template.json +114 -0
  200. simplicio_video-0.5.0/src/simplicio_video/data/templates/brand-promo/composition/assets/fonts/Fredoka.ttf +0 -0
  201. simplicio_video-0.5.0/src/simplicio_video/data/templates/brand-promo/composition/assets/fonts/Inter.ttf +0 -0
  202. simplicio_video-0.5.0/src/simplicio_video/data/templates/brand-promo/composition/assets/fonts/OFL-Fredoka.txt +93 -0
  203. simplicio_video-0.5.0/src/simplicio_video/data/templates/brand-promo/composition/assets/fonts/OFL-Inter.txt +93 -0
  204. simplicio_video-0.5.0/src/simplicio_video/data/templates/brand-promo/composition/hyperframes.json +6 -0
  205. simplicio_video-0.5.0/src/simplicio_video/data/templates/brand-promo/composition/index.template.html +40 -0
  206. simplicio_video-0.5.0/src/simplicio_video/data/templates/brand-promo/template.json +58 -0
  207. simplicio_video-0.5.0/src/simplicio_video/data/templates/imobiliario/README.md +24 -0
  208. simplicio_video-0.5.0/src/simplicio_video/data/templates/imobiliario/template.json +114 -0
  209. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-advocacia/README.md +36 -0
  210. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-advocacia/composition/assets/fonts/Fredoka.ttf +0 -0
  211. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-advocacia/composition/assets/fonts/Inter.ttf +0 -0
  212. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-advocacia/composition/assets/fonts/OFL-Fredoka.txt +93 -0
  213. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-advocacia/composition/assets/fonts/OFL-Inter.txt +93 -0
  214. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-advocacia/composition/hyperframes.json +6 -0
  215. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-advocacia/composition/index.template.html +67 -0
  216. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-advocacia/template.json +132 -0
  217. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-estetica/README.md +16 -0
  218. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-estetica/composition/assets/fonts/Fredoka.ttf +0 -0
  219. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-estetica/composition/assets/fonts/Inter.ttf +0 -0
  220. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-estetica/composition/assets/fonts/OFL-Fredoka.txt +93 -0
  221. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-estetica/composition/assets/fonts/OFL-Inter.txt +93 -0
  222. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-estetica/composition/hyperframes.json +6 -0
  223. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-estetica/composition/index.template.html +70 -0
  224. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-estetica/template.json +136 -0
  225. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-odontologia/README.md +16 -0
  226. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-odontologia/composition/assets/fonts/Fredoka.ttf +0 -0
  227. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-odontologia/composition/assets/fonts/Inter.ttf +0 -0
  228. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-odontologia/composition/assets/fonts/OFL-Fredoka.txt +93 -0
  229. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-odontologia/composition/assets/fonts/OFL-Inter.txt +93 -0
  230. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-odontologia/composition/hyperframes.json +6 -0
  231. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-odontologia/composition/index.template.html +73 -0
  232. simplicio_video-0.5.0/src/simplicio_video/data/templates/institucional-odontologia/template.json +137 -0
  233. simplicio_video-0.5.0/src/simplicio_video/data/templates/saas-tech/README.md +24 -0
  234. simplicio_video-0.5.0/src/simplicio_video/data/templates/saas-tech/template.json +119 -0
  235. simplicio_video-0.5.0/src/simplicio_video/data/templates/saude-clinica/README.md +26 -0
  236. simplicio_video-0.5.0/src/simplicio_video/data/templates/saude-clinica/template.json +128 -0
  237. simplicio_video-0.5.0/src/simplicio_video/data/templates/saude-odontologia/README.md +19 -0
  238. simplicio_video-0.5.0/src/simplicio_video/data/templates/saude-odontologia/composition/assets/fonts/Fredoka.ttf +0 -0
  239. simplicio_video-0.5.0/src/simplicio_video/data/templates/saude-odontologia/composition/assets/fonts/Inter.ttf +0 -0
  240. simplicio_video-0.5.0/src/simplicio_video/data/templates/saude-odontologia/composition/assets/fonts/OFL-Fredoka.txt +93 -0
  241. simplicio_video-0.5.0/src/simplicio_video/data/templates/saude-odontologia/composition/assets/fonts/OFL-Inter.txt +93 -0
  242. simplicio_video-0.5.0/src/simplicio_video/data/templates/saude-odontologia/composition/hyperframes.json +6 -0
  243. simplicio_video-0.5.0/src/simplicio_video/data/templates/saude-odontologia/composition/index.template.html +84 -0
  244. simplicio_video-0.5.0/src/simplicio_video/data/templates/saude-odontologia/template.json +137 -0
  245. simplicio_video-0.5.0/src/simplicio_video/data/templates/sazonal-dia-das-criancas/README.md +23 -0
  246. simplicio_video-0.5.0/src/simplicio_video/data/templates/sazonal-dia-das-criancas/composition/assets/fonts/Fredoka.ttf +0 -0
  247. simplicio_video-0.5.0/src/simplicio_video/data/templates/sazonal-dia-das-criancas/composition/assets/fonts/Inter.ttf +0 -0
  248. simplicio_video-0.5.0/src/simplicio_video/data/templates/sazonal-dia-das-criancas/composition/assets/fonts/OFL-Fredoka.txt +93 -0
  249. simplicio_video-0.5.0/src/simplicio_video/data/templates/sazonal-dia-das-criancas/composition/assets/fonts/OFL-Inter.txt +93 -0
  250. simplicio_video-0.5.0/src/simplicio_video/data/templates/sazonal-dia-das-criancas/composition/hyperframes.json +6 -0
  251. simplicio_video-0.5.0/src/simplicio_video/data/templates/sazonal-dia-das-criancas/composition/index.template.html +86 -0
  252. simplicio_video-0.5.0/src/simplicio_video/data/templates/sazonal-dia-das-criancas/template.json +142 -0
  253. simplicio_video-0.5.0/src/simplicio_video/data/templates/template.schema.json +210 -0
  254. simplicio_video-0.5.0/src/simplicio_video/data/templates/varejo/README.md +24 -0
  255. simplicio_video-0.5.0/src/simplicio_video/data/templates/varejo/template.json +119 -0
  256. simplicio_video-0.5.0/src/simplicio_video/distribution.py +64 -0
  257. simplicio_video-0.5.0/src/simplicio_video/edit.py +62 -0
  258. simplicio_video-0.5.0/src/simplicio_video/engine/build.mjs +273 -0
  259. simplicio_video-0.5.0/src/simplicio_video/engine/master.sh +15 -0
  260. simplicio_video-0.5.0/src/simplicio_video/engine/openvoice_convert.py +18 -0
  261. simplicio_video-0.5.0/src/simplicio_video/engine/remote_render.py +246 -0
  262. simplicio_video-0.5.0/src/simplicio_video/formats.py +101 -0
  263. simplicio_video-0.5.0/src/simplicio_video/hostos.py +202 -0
  264. simplicio_video-0.5.0/src/simplicio_video/installer.py +979 -0
  265. simplicio_video-0.5.0/src/simplicio_video/jobs.py +893 -0
  266. simplicio_video-0.5.0/src/simplicio_video/mcp_server.py +372 -0
  267. simplicio_video-0.5.0/src/simplicio_video/mock_gemini.py +93 -0
  268. simplicio_video-0.5.0/src/simplicio_video/moneyprinter.py +505 -0
  269. simplicio_video-0.5.0/src/simplicio_video/montage.py +157 -0
  270. simplicio_video-0.5.0/src/simplicio_video/opencut.py +59 -0
  271. simplicio_video-0.5.0/src/simplicio_video/openverse.py +1626 -0
  272. simplicio_video-0.5.0/src/simplicio_video/openverse_contract.py +229 -0
  273. simplicio_video-0.5.0/src/simplicio_video/openverse_sheet.py +249 -0
  274. simplicio_video-0.5.0/src/simplicio_video/paths.py +84 -0
  275. simplicio_video-0.5.0/src/simplicio_video/pipeline.py +38 -0
  276. simplicio_video-0.5.0/src/simplicio_video/publish.py +151 -0
  277. simplicio_video-0.5.0/src/simplicio_video/realoficial.py +34 -0
  278. simplicio_video-0.5.0/src/simplicio_video/remote.py +212 -0
  279. simplicio_video-0.5.0/src/simplicio_video/render.py +413 -0
  280. simplicio_video-0.5.0/src/simplicio_video/scaffold.py +84 -0
  281. simplicio_video-0.5.0/src/simplicio_video/skill_sync.py +34 -0
  282. simplicio_video-0.5.0/src/simplicio_video/social.py +868 -0
  283. simplicio_video-0.5.0/src/simplicio_video/status.py +154 -0
  284. simplicio_video-0.5.0/src/simplicio_video/swap.py +806 -0
  285. simplicio_video-0.5.0/src/simplicio_video/swap_providers/__init__.py +25 -0
  286. simplicio_video-0.5.0/src/simplicio_video/swap_providers/_unverified.py +38 -0
  287. simplicio_video-0.5.0/src/simplicio_video/swap_providers/alibaba.py +58 -0
  288. simplicio_video-0.5.0/src/simplicio_video/swap_providers/base.py +210 -0
  289. simplicio_video-0.5.0/src/simplicio_video/swap_providers/fake.py +145 -0
  290. simplicio_video-0.5.0/src/simplicio_video/swap_providers/fal.py +53 -0
  291. simplicio_video-0.5.0/src/simplicio_video/swap_providers/gemini.py +155 -0
  292. simplicio_video-0.5.0/src/simplicio_video/swap_providers/http.py +67 -0
  293. simplicio_video-0.5.0/src/simplicio_video/swap_providers/kie.py +56 -0
  294. simplicio_video-0.5.0/src/simplicio_video/swap_providers/wavespeed.py +54 -0
  295. simplicio_video-0.5.0/src/simplicio_video/tools.py +144 -0
  296. simplicio_video-0.5.0/src/simplicio_video/toonflow.py +177 -0
  297. simplicio_video-0.5.0/src/simplicio_video/voice.py +403 -0
  298. simplicio_video-0.5.0/src/simplicio_video/voice_clone.py +81 -0
  299. simplicio_video-0.5.0/src/simplicio_video/words.py +82 -0
  300. simplicio_video-0.5.0/src/simplicio_video.egg-info/PKG-INFO +108 -0
  301. simplicio_video-0.5.0/src/simplicio_video.egg-info/SOURCES.txt +303 -0
  302. simplicio_video-0.5.0/src/simplicio_video.egg-info/dependency_links.txt +1 -0
  303. simplicio_video-0.5.0/src/simplicio_video.egg-info/entry_points.txt +3 -0
  304. simplicio_video-0.5.0/src/simplicio_video.egg-info/requires.txt +19 -0
  305. simplicio_video-0.5.0/src/simplicio_video.egg-info/top_level.txt +1 -0
@@ -0,0 +1,266 @@
1
+ # Changelog
2
+
3
+ O que mudou em cada issue. `simplicio-video update --check` mostra o diff deste arquivo antes de atualizar.
4
+
5
+ ## Unreleased
6
+
7
+ ## 0.5.0 — 2026-10-17
8
+
9
+ Primeira versão publicada no PyPI (`pip install simplicio-video`). Reúne o pacote pronto para o PyPI (sem dado de cliente no wheel nem no sdist, `init` fora do site-packages, metadados e `PYPI.md`), `login`, `logout`, `auth status`, `doctor` e `update --check` no contrato do simplicio-loop, e `install` universal (skills nos hosts) com `update` igual ao do loop. Windows e macOS: testados só por simulação e pelo `scripts/smoke_so.py`; ainda não confirmados em máquina real.
10
+
11
+ Resumo: `install` e `update` ficam **iguais aos do simplicio-loop e universais**: `install` copia a skill para o host do agente (os 12 hosts do loop, projeto ou `~`, Linux, macOS e Windows) e o `.venv` com uv vira `scripts/dev_install.sh` e `scripts/dev_install.ps1`; `update` num checkout recusa. `doctor` passa a seguir o contrato do loop (mesmos códigos de saída e documentos JSON), entram `login`, `logout` e `auth status` (espelho do login compartilhado com o Simplicio Runtime) e o código deixa de assumir POSIX, com testes que simulam Linux, macOS e Windows e um script de fumaça para rodar de verdade em Windows e macOS. Pedido direto do dono, sem issue, como os PRs #108 a #116.
12
+
13
+ ### Correções da revisão independente do PR #117 (2 bloqueantes, 6 importantes, 12 menores)
14
+ A revisão mediu cada falha com HOME e PATH isolados. Tudo abaixo vale para o `install`, o `--uninstall`, o `--prune-project-copies` e o `--verify` ([ADR-0020](docs/decisoes/ADR-0020-install-universal-e-update-igual-ao-loop.md)):
15
+ - **B1, a skill do pacote ensinava o contrário:** `simplicio-video/SKILL.md` (no wheel, público e imutável no PyPI) dizia que o `install` cria o `.venv` e que o `update` recusa árvore suja com `git stash`, e citava o dono em três frases. Reescrita para o contrato novo (o `install` copia as skills; o `.venv` é `scripts/dev_install.sh` ou `.ps1`; o `update` de um checkout recusa e manda `git pull`; o do pip roda `pip install --upgrade` e `install --global`), sem o nome do dono. Um teste varre cada `simplicio-video <comando> <verbo> --flag` das duas skills contra os parsers de verdade (os aninhados de `social`, `openverse` e `busca` também), proíbe as frases antigas, o dono, cliente e e-mail, e exige a skill do pacote igual à de `skills/`.
16
+ - **B2, o `--uninstall` e o `--prune-project-copies` apagavam qualquer arquivo que o recibo nomeasse:** o recibo agora guarda o **`sha256` de cada arquivo**; só se apaga o que está no recibo, no conjunto de destinos que o registro de hosts produz (as pastas das skills, os arquivos de entrada dos hosts e o próprio recibo) e com o mesmo `sha256`. Um `AGENTS.md` em que o usuário escreveu as regras dele não é mais apagado (`left_alone`, com aviso). Um recibo com `.git/config`, `src/app.py`, `.ssh/authorized_keys`, byte nulo ou caminho gigante é recusado inteiro (exit 1, nada é apagado), e um `install` por cima de um recibo plantado o ignora, avisa e não herda os caminhos. O `schema` do recibo exige o `sha256` e restringe o formato dos caminhos.
17
+ - **I1, o `--global` apagava arquivos do usuário** dentro de `~/.claude/skills/simplicio-video` e das cópias dos outros hosts (e o `update` do pip fazia isso sozinho ao chamar `install --global`). Uma primeira correção se limitou a relatar essas cópias; o dono pediu "Universal" e "igual ao loop", então o `install --global` voltou a instalar e atualizar a skill nas 11 pastas do loop, **com a regra de posse:** cria o que falta (o arquivo entra no recibo com o `sha256`); atualiza só a cópia que é do recibo e que ainda tem o `sha256` gravado (nossa, não editada); deixa em paz (`left_alone`) o que já existia ou o usuário editou; nunca apaga um arquivo extra; o `--check` sai com 10 quando uma cópia nossa e não editada está desatualizada (e uma cópia alheia antiga não o deixa pendente); `up_to_date` considera as 11 pastas, como no loop; o `--uninstall` remove só o que é nosso; uma pasta secundária que é link é pulada com aviso sem derrubar as outras. O `update` do pip continua seguro.
18
+ - **I2, `install --global --prune-project-copies` rodado do `~` apagava a instalação global recém-feita:** com o alvo igual ao home sai com 2; e o `.claude` do projeto que é link para o do home não leva embora a instalação global.
19
+ - **As skills do pacote só citam o que o usuário do pip tem** (as duas, imutáveis no PyPI): saíram `ugc/README.md`, `clients/<slug>/...`, `tools/video-use/`, `docs/...`, `intake/...`, `colab/...` e a seção de UGC (o módulo saiu no #115); o que ficou é caminho que existe no pacote, saída do CLI (`out/`, `assets/`), um script que o `update` manda rodar num checkout, ou URL absoluta para um arquivo que existe na `main`. Um teste confere cada caminho, link, comando, flag e tool MCP citados.
20
+ - **I3, um link acima da pasta da skill era escrito por dentro e o uninstall falhava para sempre:** as pastas que o install cria (`.claude/skills`, a da skill, as de dentro dela e `.simplicio-video`) nunca são link (recusa com exit 2, nada escrito); a pasta base (`~/.claude`) pode ser link de dotfiles: é resolvida uma vez, o recibo grava o caminho real (`bases`) e o uninstall confere que o link não mudou. Install, verify e uninstall fecham nos dois casos, no projeto e com `--global`.
21
+ - **I4, o `--verify` sempre dizia ok:** agora compara os arquivos com o recibo e com o pacote e sai com 1, `ok: false` e a lista `problems` (`no_receipt`, `bad_receipt`, `missing`, `not_a_file`, `modified`, `outdated`, `foreign`) para um alvo nunca instalado, uma skill adulterada ou um recibo trocado por lixo. Mantém as chaves do loop (`ok`, `version`, `digest`) e o exit 1 dele; o do loop só confere a versão do plano.
22
+ - **I5, o primeiro install sobrescrevia uma `SKILL.md` customizada e uma cópia idêntica virava "própria":** um arquivo que já existia sem entrada no recibo fica `left_alone` (diferente) ou só `unchanged` e fora do recibo (idêntico), e o `--uninstall` nunca o apaga. Um arquivo nosso que o usuário editou depois também deixa de ser atualizado.
23
+ - **I6, o comando do PowerShell falhava na política padrão do Windows cliente (Restricted):** a recusa do `update`, o help e os docs dizem `powershell -NoProfile -ExecutionPolicy Bypass -File scripts\dev_install.ps1` (o Bypass vale só para esse processo). UNVERIFIED sem um Windows real.
24
+ - **Menores:** um recibo com byte nulo vira erro claro, nunca traceback (m1); a trava `.simplicio-video/install.lock` (`0600`, espera de 10 s, o mesmo mecanismo do `login.lock`) serializa installs ao mesmo tempo, com teste de corrida com threads e com três processos (m2); a junção NTFS é vista como link pelos atributos de `lstat` também no Python 3.10 e 3.11 (m3, UNVERIFIED num Windows real); `update --force` reinstala só o nosso pacote (`--force-reinstall --no-deps`) quando não há versão mais nova, e usa o `--upgrade` normal com uma nova (m4); o help diz que com `--global` o `--host` é ignorado e que um `AGENTS.md` que já existe não recebe apontador (m6); o schema do recibo restringe o formato dos caminhos (m8); `-With local-tts,mcp` no PowerShell chega como lista e o script a junta (m9, UNVERIFIED); o `.gitignore` cobre `.claude/skills/simplicio-video*` (m10); um disco que falha no meio deixa um recibo que bate com o que foi escrito e nenhuma pasta órfã (m11); o `update` num Python sem pip (um `uv tool install`) diz `uv tool upgrade` ou `pipx upgrade` e sai com 2 (m12).
25
+ - **Ficaram de fora:** m5 (um erro do argparse com `--json` sai 2 sem documento, igual ao loop) e a diferença de `ensure_ascii` e do `schema` de `pruned_project` em relação ao loop (m8, só de forma, nenhuma chave); veja "Para depois" na segunda revisão.
26
+
27
+ ### Correções da segunda revisão independente do PR #117 (head a342a1c: 0 bloqueantes, 3 importantes, 10 menores)
28
+ - **I1, uma escrita que falha no meio de um update tirava o NOSSO arquivo do recibo:** com o disco cheio, uma `PermissionError` ou um `os.replace` que o Windows nega, o arquivo antigo continua lá, intacto e nosso, mas saía do recibo: o `--uninstall` o deixava para trás e o próximo `install` o tratava como alheio. O recibo agora mantém o que a execução não conseguiu reescrever, com o `sha256` antigo (`carry_forward` só pula o que a execução tornou nosso de novo). Testes: install v1, update v2 que falha, o recibo ainda lista o arquivo, o uninstall o remove e uma nova execução conserta; vale também para uma pasta de host que falha no `--global`.
29
+ - **I2, o texto do `update` do pip mentia sobre o que o `install --global` mexe:** o help, o `docs/how-to/install.md` e as duas cópias da skill diziam que só a `~/.claude/skills` era tocada; o `install --global` instala ou atualiza a skill nas **11 pastas de hosts** sob o home e cria as que faltam (sem sobrescrever o que o usuário editou). Os três textos foram corrigidos e a skill do pacote não cita mais o `schema/contract.schema.json` (não existe em lugar nenhum) nem um caminho interno sem dizer onde fica (`simplicio_video/data/...` no pacote). O varredor de caminhos da skill agora só aceita caminho com raiz no pacote que exista em `src/`.
30
+ - **I3, os 9 mutantes que sobreviveram à re-revisão agora morrem:** a recusa do recibo plantado antes de a trava criar o `install.lock` (M1); o `sha256` no `carry_forward` (M2); um arquivo do recibo que virou link não é apagado pelo uninstall (M3); um recibo FIFO não trava (M5, com prazo); um link abaixo da base gravada (M6); o limite de tamanho do `sha256` (M7); um recibo que é link (M8); um digest ausente nunca autoriza apagar (M9). Cada um tem teste vermelho e foi reexecutado com a mutação aplicada.
31
+ - **Menores:** (a) um `bases` forjado num recibo de projeto (um repositório com `.claude` apontando para o `~/.claude` e um recibo que grava esse caminho real como base) não apaga a instalação global: o uninstall de projeto agora respeita as 11 pastas do home como o `--prune-project-copies` já fazia (em vez de recusar `bases` fora do alvo, o que quebraria o `.claude` de dotfiles que é link legítimo); (b) `--global` com HOME ausente, relativo, `~`, `/` ou que não existe sai com 2 e uma mensagem clara, nunca cria uma pasta chamada `~`; (c) um recibo de uma versão sem `sha256` é recusado como recibo inválido, com a mensagem verdadeira (antes dizia "editado"); (d) o `--verify` com `.simplicio-video` como link diz isso com o próprio caminho, sem "Nada foi escrito" (o `--verify` nunca escreve).
32
+ - **Para depois (não feito de propósito, sem regressão):** TOCTOU entre a checagem e a escrita (a correção é abrir cada pasta por `dir_fd`); o `update` do pip chama `python -m pip` com o diretório atual no `sys.path` (vem da `main`, não deste PR); um erro do argparse com `--json` sai 2 sem documento (igual ao loop); `ensure_ascii` e o `schema` de `pruned_project` diferem do loop só na forma; a corrida de apagar o `install.lock`; `.simplicio-video` com modo `0700`.
33
+ - **Limpeza manual para quem rodou o build do head 2e3d95c:** apague à mão os arquivos que ele listava no recibo (`.claude/skills/simplicio-video*`, o `AGENTS.md` ou equivalente só se foi ele que o criou) e o `.simplicio-video/install-ownership.json`, e rode `simplicio-video install` de novo. Aquele build gravava o recibo sem `sha256`; o `install` e o `--uninstall` de hoje o recusam como inválido, de propósito, porque sem o digest não sabem o que ainda é deles.
34
+
35
+ ### Mudanças que quebram: `install` universal e `update` igual ao loop ([ADR-0020](docs/decisoes/ADR-0020-install-universal-e-update-igual-ao-loop.md))
36
+ Pedido do dono, em sequência: "Coloca install, update, doctor, login, mesma coisa que fizemos no simplicio-loop", "Só olha simplicio-loop", "Fazia igual estava no simplicio-loop", "Universal". O #116 tinha mantido o `install` como o `.venv` com uv e o `update` de um checkout como `git pull --ff-only`; os dois voltam atrás, sem compatibilidade.
37
+ - **`simplicio-video install` agora instala skills no host do agente** (como o `install` do loop), não o `.venv`. Saem `--python`, `--with`, `.venv/simplicio-install.json` e o JSON `simplicio.video-install/v1`. O `.venv` com uv passa a ser `bash scripts/dev_install.sh` (Linux e macOS) ou `powershell -NoProfile -ExecutionPolicy Bypass -File scripts\dev_install.ps1` (Windows; o Bypass vale só para esse processo, porque o Windows de cliente vem com a política Restricted); quem rodava `simplicio-video install --python 3.12 --with local-tts` roda `bash scripts/dev_install.sh --python 3.12 --with local-tts`.
38
+ - **`./install.sh` é um invólucro fino** de `scripts/dev_install.sh` (com as mesmas opções) e há um `install.ps1` equivalente. Nenhum dos dois usa o python do sistema: o uv traz o Python (o bug B1 do #116, `install.sh` num `python3` sem PyYAML, fica fechado por construção; um teste roda o `install.sh` com um `python3` que morre com `No module named 'yaml'`).
39
+ - **`update` num checkout git ou instalação editável RECUSA:** imprime `git pull` e `bash scripts/dev_install.sh` (no Windows, `powershell -NoProfile -ExecutionPolicy Bypass -File scripts\dev_install.ps1`) e sai com `exit 2`, como o do loop. O `git pull --ff-only`, o `git reset --keep`, o build de `web/` e a recusa de árvore suja saem. `--force` e `--dry-run` também recusam; `--check` continua 0, 10 ou 2, grava `update-check.json` e não liga mais para a árvore suja (nada é puxado).
40
+ - **`update` num pacote do pip reinstala as skills:** depois do `pip install --upgrade "simplicio-video==<versão>"` roda `simplicio-video install --global`, como o loop (se esse segundo passo falhar, o código é o dele, o sucesso não é registrado e a mensagem diz o comando à mão).
41
+ - **`install --check` sai com `10` quando falta criar ou atualizar uma skill** (e com `0` em dia). Num pacote do pip o `install` funciona (copia a skill do wheel) e não sai mais com 2.
42
+
43
+ ### `install` universal (as skills vão para o host)
44
+ - **Os 12 hosts do registro do loop, todos portados:** `claude`, `codex`, `cursor`, `vscode`, `grok`, `kiro`, `antigravity`, `opencode`, `gemini`, `aider`, `simplicio_agent` e `openclaw` (mais `--host all`). As skills (`simplicio-video` e `simplicio-video-social`) vão para `.claude/skills`; o arquivo de entrada do host (`AGENTS.md`, `GEMINI.md`, `CONVENTIONS.md`, `.github/copilot-instructions.md`, `.kiro/steering/simplicio-video.md`) só é criado se ainda não existir. Com `--global` (o `~`: `HOME`, depois `USERPROFILE`) o `install` põe a skill nas **11 pastas** do `skill_sync.py` do loop (`.claude/skills`, `.cursor/skills`, `.codex/skills`, `.grok/skills`, `.agents/skills`, `.copilot/skills`, `.vscode/simplicio-skills`, `.config/opencode/skills`, `.config/amp/skills`, `.kiro/steering` e `.simplicio-loop/skills`, as mesmas nos três sistemas), com a regra de posse da revisão do #117 abaixo (o loop sobrescreve e apaga nelas; aqui não). **O simplicio-video não tem hooks, então só skills** (o loop também copia hooks e regras de host; aqui as `rules` do `resynced` ficam vazias, por contrato com as chaves do loop). Hosts "listed" do catálogo do loop que só o `install_lib.py` do checkout dele escreve não foram portados (o `install` empacotado do loop também não os anuncia).
45
+ - **Flags e contrato do loop:** `--target`, `--global`, `--host`, `--dry-run`, `--check` (0 ou 10), `--json`, `--verify`, `--uninstall` (remove só o que o recibo registra) e `--prune-project-copies`. JSON `simplicio.video-install-plan/v1` com as mesmas chaves do `simplicio.loop-install-plan/v1` (`up_to_date`, `changes{created,updated,unchanged,left_alone}`, `owned`, `digest`, `host`, `version`, `resynced`); recibo de posse `.simplicio-video/install-ownership.json` (`simplicio.video-install-ownership/v1`); nunca sobrescreve o que não é dele (`left_alone`: outras skills, um `AGENTS.md` seu, um link simbólico). No fim, se o setup nunca rodou, ele roda num terminal e senão diz como rodar.
46
+ - **A skill vai dentro do pacote** (`src/simplicio_video/data/skills/`, fonte da verdade; `skills/` é o espelho, igual byte a byte por teste), então `pip install simplicio-video` basta. Para isso a skill ficou sem nome de cliente (os exemplos usam `acme-odontologia`), sem o identificador do dono e sem link relativo que só vale no checkout; a guarda de dados de cliente do #115 passou a cobri-la.
47
+ - **Diferenças de propósito em relação ao loop** (ADR-0020): `--prune-project-copies` sem `--global` é erro (exit 2) e o `prune` só poda o que o recibo do projeto registra; uma pasta que o install cria nunca é link (recusa, exit 2); `--verify`, `--uninstall` e o erro também imprimem um documento com `--json`; a escrita é atômica; o recibo e a leitura de arquivos não travam num FIFO; o recibo recusa caminho de Windows (letra de unidade, `\x`, `..\x`) em qualquer sistema.
48
+ - **PowerShell sem PowerShell:** `scripts/dev_install.ps1` e `install.ps1` foram escritos no Linux e **nunca foram executados**; só testes estáticos os leem. UNVERIFIED até alguém rodar `powershell -NoProfile -ExecutionPolicy Bypass -File scripts\dev_install.ps1 -DryRun` num Windows.
49
+ - **`scripts/smoke_so.py`** agora também roda o `install` num alvo temporário (`--check` 10, `--dry-run --json`, o `--verify --json` de um alvo nunca instalado que falha com 1, o install, o `--verify` que passa, o `--check --json` em dia e o `--uninstall`), sem `--global`, sem terminal no stdin e sem tocar no `~`: quatorze comandos.
50
+ - Código que saiu por falta de uso: `hostos.venv_python`, `find_uv`, `uv_candidates` e a dica do uv (o `dev_install` acha o uv sozinho).
51
+ - Docs: `docs/decisoes/ADR-0020-install-universal-e-update-igual-ao-loop.md` (novo; supersede a decisão do ADR-0017 sobre o checkout), `docs/host/packaging.md`, `docs/how-to/install.md`, `docs/how-to/testar-em-windows-e-macos.md`, quickstart do `AGENTS.md` e do `README.md`, `skills/simplicio-video/SKILL.md`. Novos: `.gitattributes` (LF nos `*.sh`) e `.simplicio-video/` no `.gitignore`.
52
+
53
+ ### Mudanças que quebram
54
+ - **`doctor --json` mudou de formato.** Era `{ok, checks[{name, status, detail (texto), fix}]}`; agora é `simplicio.doctor/v1`: `{schema, status, version, checks[{name, status, summary, fix, detail (objeto)}]}`. Sai `ok` (use `status`, que é o pior dos checks), o texto vira `summary` e `detail` vira um objeto. Os nomes `ffmpeg libass`, `disco livre`, `portas`, `workspace` e `workspace policy` viraram `ffmpeg-libass`, `disk`, `ports` e uma linha `setup`. O texto também mudou (`simplicio-video doctor: <status>`, uma linha por check, `fix:` embaixo). Workspace ausente deixou de ser falha: é aviso (nada no motor o lê).
55
+ - **`install --check` sai com `10`** quando há mudança pendente, e `0` em dia, como o `install --check` do loop (o do `.venv` saía com `1`). Quem testava `rc == 1` precisa trocar.
56
+ - **`update --force` mudou de sentido.** Antes seguia com árvore suja; agora reinstala a release do pip mesmo em dia e permite downgrade (como no loop). Num checkout o `update` recusa em qualquer modo (veja acima).
57
+ - **`update` recusado sai com `exit 2` (era `1`):** um checkout git e PEP 668 (e, no `--check`, sem upstream ou fora de um repositório git). Uma versão instalada mais nova que a última release (o PyPI sai antes do GitHub Release) é versão em dia: sai com `0`, como o loop. Falha de rede: `2` com `--check`, `1` sem ele. `update --check` saía sempre com `0`; agora sai com `0` (em dia), `10` (há atualização) ou `2` (erro).
58
+
59
+ ### install, update e doctor no contrato do loop
60
+ - **`install`:** `--check` (0 ou 10), `--dry-run` (não escreve nada, sai com 0) e `--json`, agora no contrato do `install` do loop (veja "`install` universal"). O `.venv` com uv é o `scripts/dev_install.sh`. Nada é criado em `site-packages`.
61
+ - **`update`:** `--check`, `--dry-run` e `--force`. Num checkout recusa (veja acima; o build de `web/` é do `dev_install`). Num pacote instalado por pip faz `python -m pip install --upgrade "simplicio-video==<última release>"` (PyPI), recusa PEP 668 com as quatro saídas e lê a última release do GitHub Releases (`gh release view -R simpletibr/simplicio-videos`, senão `api.github.com/.../releases/latest`; o `GH_TOKEN` só vai para `api.github.com`, e um redirect para outro host tira o cabeçalho). `SIMPLICIO_OFFLINE=1` bloqueia essa consulta e também o `git fetch` do checkout. `--check` grava `update-check.json` em `$SIMPLICIO_VIDEO_DATA` (padrão `~/.simplicio-video`), que o doctor lê sem rede.
62
+ - **`doctor`:** `doctor [all|login] [--json] [--online]` com as linhas `login`, `update`, `distribution`, `runtime`, `python`, `node`, `ffmpeg`, `ffmpeg-libass`, `disk`, `ports`, `GEMINI_API_KEY` e `setup`. Login ausente ou expirado é aviso; arquivo de login inseguro é falha. O disco é medido com `shutil.disk_usage` (o `os.statvfs` antigo não existe no Windows), num pacote instalado na pasta de dados e não em `site-packages`. Procura `ffmpeg`, `node` e `uv` também nos prefixos do Homebrew no macOS.
63
+ - **Sete schemas novos** em `src/simplicio_video/data/schemas/cli/`: `doctor`, `login`, `logout` e `auth-status` (com os `$id` do loop; o `auth-status` proíbe `access_token` e `refresh_token`), `update-check`, `install-plan` (`simplicio.video-install-plan/v1`, as chaves do plano do loop) e `install-ownership` (o recibo). O `install-result` do `.venv` saiu. Cada `--json` é conferido contra eles em `tests/packaging/test_contrato_ops.py`.
64
+
65
+ ### login, logout e auth status (espelho do loop)
66
+ - **`login [--json] [--no-browser]`** roda `simplicio login google` do Runtime e confere o arquivo compartilhado `~/.simplicio/login.json` (ou `SIMPLICIO_AUTH_FILE`), com a mesma trava `login.lock`. **`logout [--yes] [--json]`** apaga o arquivo (desloga o Runtime também, por isso sem `--yes` sai com `exit 2`). **`auth status [--json]`** mostra conta mascarada, validade, direitos em cache e versão do Runtime. Códigos de saída e `reason_code` do loop (0, 1 e 2).
67
+ - **O que o login não faz (decisão do dono, [ADR-0019](docs/decisoes/ADR-0019-login-compartilhado.md)):** não libera nem cobra nada no motor, não guarda credencial (o módulo `auth` só lê), não renova token, não tem `auth status --online`, não aceita `SIMPLICIO_247_LOGIN` e não entra no `plugin.json` nem no MCP. Sem Runtime, `login` é `UNVERIFIED` e mostra como instalar o Runtime (os comandos do `INSTALL.md` dele; o loop `2034e2d` ainda imprime o nome antigo da organização do Runtime).
68
+ - **Segurança:** nenhum token em stdout, stderr, JSON, log nem argumento; e-mail mascarado; o processo filho do Runtime recebe ambiente mínimo (sem `GH_TOKEN`, chaves de API nem `SIMPLICIO_LOGIN_TOKEN`). Linux e macOS recusam arquivo legível por grupo ou outros, link simbólico, FIFO, pasta, arquivo de outro usuário e pasta gravável por outros. No Windows o modo não vale e as ACLs **não** são verificadas; link simbólico e junção continuam recusados e `--no-browser` recusa com `exit 2` e `no_browser_unsupported`.
69
+
70
+ ### Revisão independente do PR #116 (achados corrigidos, cada um com teste vermelho antes)
71
+ - **Bloqueante: o `./install.sh` quebrava numa máquina nova.** Ele roda `python3 -m simplicio_video install` com o python3 do sistema antes de o `.venv` existir, e o `install` importava o `setup`, que importa o PyYAML no topo: `install --check` morria com `ModuleNotFoundError` num Python sem PyYAML (macOS com as ferramentas do Xcode, Debian mínimo). `workspace_dir` foi para `paths.py` (só biblioteca padrão), e um teste roda `install --check`, `--dry-run`, `--json` e o install de verdade num interpretador que bloqueia o PyYAML, o jsonschema e qualquer terceiro, e importa nele cada módulo que o install puxa no topo.
72
+ - **Nenhuma exceção sai de `doctor`, `login`, `logout` e `auth status`.** `Path.is_file()` levanta `PermissionError` no Python 3.12 e 3.13 (o `shutil.which` engolia): uma pasta do `PATH` sem permissão, ou um `~/.simplicio` de outro dono depois de `sudo` (comum no macOS), derrubava os comandos com traceback. A busca pula a pasta ilegível e a leitura, a trava e o logout dão `login_permissions` com a correção. Um teste passa entradas hostis (pasta sem permissão, `SIMPLICIO_AUTH_FILE` apontando para pasta, fifo, dispositivo, laço de links, socket ou nome longo, HOME ausente, workspace ilegível, Runtime que não executa) por todos os comandos, em texto e em `--json`, e confere o schema de cada documento.
73
+ - **`HOME` antes de `USERPROFILE` em todo sistema**, como o Runtime e o loop (no Windows este CLI lia `USERPROFILE` primeiro e, com as duas diferentes, leria e apagaria outro arquivo que o Runtime grava, dizendo `shared_with_runtime: true`). O smoke usava as duas iguais e escondia o problema: agora são pastas diferentes. Guia de Windows e `packaging.md` atualizados.
74
+ - **`login.json` corrompido ou hostil:** `access_expires_at: 1e999` (`OverflowError`), JSON muito aninhado (`RecursionError`) e `999999999999` (ano 33658) derrubavam `auth status`, `doctor` e `login`. Agora todo número ou data que não é um instante entre 1970 e o ano 9999 é `login_invalid`, a leitura para em 1 MiB (acima disso é `login_invalid`) e a data é aritmética sobre a época (o `fromtimestamp` falha depois do ano 3000 no Windows).
75
+ - **`update-check.json` corrompido não derruba mais o doctor:** `checked_at` inválido (texto, número enorme, lista), `latest` com escape ANSI ou argumento do pip, JSON aninhado ou grande demais viram aviso com a dica `update --check`; `read_check` só devolve as chaves do schema e o `detail` do doctor não copia mais chave desconhecida (um `access_token` no cache repetia o valor e violava o próprio schema).
76
+ - **`SIMPLICIO_OFFLINE=1` bloqueia toda a rede, também no checkout:** o `git fetch` do `update --check`, do `update` e do `doctor --online` (medido: 1 chamada) não roda mais (`update --check` sai com `2`, `update` com `1`, o doctor avisa). O `update --dry-run` nunca roda `git fetch` (ele regravava `FETCH_HEAD` e as refs `origin/*`): só mostra o plano. Todo git do update usa `--no-optional-locks`.
77
+ - **`logout --yes` só apaga um login.** Com `SIMPLICIO_AUTH_FILE=~/.ssh/id_rsa` ele apagava a chave e deixava um `id_rsa.lock`. Agora só apaga um arquivo comum, pequeno e com a forma de login (veja a segunda revisão abaixo: a do `StoredAuth` do Runtime), conferido antes e de novo sob a trava; o resto sai com `exit 2`, `REFUSED` e o `reason_code` novo `not_a_login_file`, sem apagar e sem criar o `login.lock`.
78
+ - **Menores:** versão instalada mais nova que a última release sai `0` (era `2`, "recusando um downgrade"); a versão do pip é lida com regra estrita (`X.Y` a `X.Y.Z.W`, `v` opcional, `.postN`; `v0.5.0 --index-url=...` e `1!2.0.0` são recusados) e o argv é remontado de números; o ambiente do filho do `login` é uma lista fechada de nomes exatos, sem o prefixo livre `LC_*` e `XDG_*`; a saída do git, do node, do ffmpeg e do Runtime é lida em UTF-8 com `replace` (no Windows o codec do console quebrava com o `Í` do CHANGELOG), e um teste confere o `encoding` de toda leitura de texto e de todo subprocesso de texto; `install --json` imprime um documento com `error` também no erro (e hoje, no contrato do loop, com `status` `error`); o PATHEXT vem do ambiente passado e não do `os.environ`; a gravação do `update-check.json` é atômica e não deixa temporário; e as 4 mutações que tinham sobrevivido (sem `O_NOFOLLOW`, gravação não atômica, pasta sticky de outro dono aceita, logout sem a trava) ganharam teste.
79
+
80
+ ### Segunda revisão independente do PR #116 (cada achado com teste vermelho antes)
81
+ - **`logout --yes` não apaga mais um link simbólico (resto do I6).** Com `SIMPLICIO_AUTH_FILE` apontando para um link (um `~/.bashrc` de um repositório de dotfiles, por exemplo, ou um link quebrado ou para uma pasta), a checagem de forma era pulada, a trava era criada e o link era removido. Agora um link simbólico (e um ponto de reparse do tipo link no Windows) sai com `exit 2`, `REFUSED` e `login_symlink` ANTES de criar a trava, sem tocar no link nem no alvo e sem `.lock`, igual à leitura do login, que já recusava link. O help, o schema do `logout` e o `packaging.md` dizem isso.
82
+ - **A forma de login é a do `StoredAuth` do Runtime** (`access_token` texto e `access_expires_at` número; `refresh_token` e `verification` são opcionais lá): o JSON de credenciais do gcloud (só `refresh_token`) tinha sido apagado como se fosse um login.
83
+ - **`update-check.json` que é FIFO não trava mais o doctor** (a leitura passava de 20 s): os arquivos de estado (`update-check.json`, o recibo do install, o YAML do workspace) são abertos com `O_NONBLOCK` e conferidos com `fstat` no mesmo descritor; o que não é arquivo comum vale como cache inválido (aviso) ou como ausente.
84
+ - **O motivo do git aparece, e git antigo funciona:** o stderr do git era descartado, então `dubious ownership` (checkout de outro usuário) ou um git anterior à 2.15 (que não conhece `--no-optional-locks`) liam como "não é um repositório git". Agora a recusa mostra o que o git disse (uma linha, cortada, sem escapes de terminal), um `git status` que falha não vale como árvore limpa, e um git que não conhece `--no-optional-locks` é chamado de novo uma vez sem ela.
85
+ - **`update --check --dry-run`:** uma regra só nas duas distribuições: o dry-run só mostra o plano e sai com `0` (antes: `0` no checkout e `10` no pip). O `--check` sozinho continua respondendo `10`.
86
+ - **Versão instalada de desenvolvimento ou pré-release** (`0.5.0.dev1`, `0.5.0rc1`) aparecia "em dia" frente à release final: a comparação segue a PEP 440 (dev < a < b < rc < final < post, `+local` não conta), sem aceitar pré-release como alvo de upgrade.
87
+ - **O teste que confere o `encoding` de toda leitura de texto voltou a pegar `path.open()` sem encoding** (tinha enfraquecido depois do commit vermelho), com testes do próprio verificador.
88
+ - **Lacunas de teste achadas por mutação:** erro ao abrir o `login.lock` (`login_permissions`), a leitura que para em 1 MiB, o git sempre com `--no-optional-locks` (e o `.git/index` intacto) e o `except` de `utc_stamp` (reduzido ao `TypeError`, o único que alguma entrada alcança).
89
+ - **Fica de fora, de propósito (follow-up):** ambiente do filho do `login` sem `XAUTHORITY`, `COMPUTERNAME`, `HOSTNAME`, `WSL_*`; escape de terminal no domínio do e-mail mascarado; `PermissionError` do `setup` quando o workspace é de outro usuário; bordas da ordem do HOME (`HOME=""`).
90
+
91
+ ### Linux, macOS e Windows
92
+ - **Sem premissa POSIX escondida** (módulo novo `hostos.py`): Python do venv em `Scripts\python.exe` ou `bin/python`, `HOME` e depois `USERPROFILE` (a ordem do Runtime), programas achados no PATH com PATHEXT (`simplicio`, `simplicio.exe`, `simplicio.cmd`) e em `~/.simplicio/bin`, **nunca no diretório atual** (o `shutil.which` procura nele primeiro no Windows), `O_NOFOLLOW` via `getattr`, trava `fcntl` ou `msvcrt`, `uv` em `~/.local/bin`, `~/.cargo/bin` e Homebrew, substituto de `open` no `--no-browser` do macOS.
93
+ - **Testes dos três sistemas no Linux:** `tests/packaging/` simula `linux`, `darwin` e `win32` (`sys.platform`, `platform.system`, `PureWindowsPath`, `msvcrt` falso, PATHEXT, ponto de reparse), com a fixture `caixa` (HOME, USERPROFILE e PATH selados, Runtime falso em Python, e uma armadilha que impede qualquer `simplicio` fora de `tmp_path`, porque a máquina de desenvolvimento tem um Runtime de verdade em `~/.simplicio/bin`). Os testes que precisam de arquivos POSIX de verdade são marcados `posix_real`, para a mesma suíte rodar num Windows ou macOS de verdade sem falhar à toa.
94
+ - **`scripts/smoke_so.py`** (Python 3.10 ou superior, biblioteca padrão no topo) roda nove comandos num HOME, USERPROFILE e PATH isolados numa pasta temporária (sem `simplicio` no PATH, sem rede), valida cada JSON contra o schema empacotado, imprime uma tabela Markdown (SO, Python, comando, exit esperado e obtido, ok ou falhou) e sai com 1 se algo falhar. Guia: [testar em Windows e macOS](docs/how-to/testar-em-windows-e-macos.md).
95
+ - **UNVERIFIED:** **Windows e macOS reais não foram rodados.** Só o Linux rodou (a suíte e a fumaça). Também UNVERIFIED: `msvcrt.locking` × `LockFileEx` do Runtime no Windows, as ACLs do Windows, um Runtime que chama `/usr/bin/open` pelo caminho absoluto no macOS e o `simplicio login google` de verdade (os testes usam um Runtime falso; o Runtime real nunca foi chamado). O pacote `simplicio-video` ainda não estava no PyPI em 17/10/2026 (404), então o ramo pip do `update` depende da primeira publicação.
96
+ - Docs: `docs/host/packaging.md`, `docs/how-to/install.md`, `docs/how-to/testar-em-windows-e-macos.md`, `docs/decisoes/ADR-0019-login-compartilhado.md` (novo), nota de revisão no ADR-0017, quickstart do `AGENTS.md`, `skills/simplicio-video/SKILL.md` e `docs/reference/` (regenerada: `SIMPLICIO_AUTH_FILE`, `GH_TOKEN`, `GITHUB_TOKEN`, `PIP_BREAK_SYSTEM_PACKAGES` e `PATHEXT` descritas).
97
+ - **Fica de fora, de propósito:** hooks e regras de host (o video não tem), `update` de binário, renovação e escrita do login, `auth status --online`, `plugin.json` e MCP, `doctor` de operators e map-store do loop.
98
+
99
+ ### Pacote pronto para o PyPI (o que muda para quem instala pelo pip)
100
+ - **`simplicio-video init` e `video.init` (MCP) não gravam mais dentro do `site-packages`.** Sem checkout, `paths.home()` caía no diretório de dados do pacote e o contrato saía em `.../site-packages/simplicio_video/data/clients/...` (quebra em instalação somente leitura e suja o pacote). Agora, fora de um checkout, o `init` da CLI grava `./clients/<cliente>/<campanha>/contract.yaml` na pasta atual (a de quem digitou o comando). Já o `video.init` do MCP **não** grava na pasta onde o servidor foi iniciado (`/`, `$HOME`, a pasta da IDE: o cliente LLM não a controla): num pacote instalado `out` é obrigatório e absoluto, e sem ele a tool devolve um erro em português pedindo o `out` e não grava nada; a descrição da tool diz isso. No checkout e com `--out` nada muda. A regra mora em `scaffold.default_out` e `scaffold.sem_checkout`.
101
+ - **Nenhum dado de cliente viaja no pacote.** O template `assistencia-tecnica-games` trazia telefone, endereço, @ do Instagram, alt do logo e a cidade de um cliente real, e o padrão `brand-lockup-soft` (com o `preview.png`) trazia nome, @ e cidade de outro. Os defaults viram placeholders evidentes: `(00) 00000-0000`, `Rua Exemplo, 123 · Cidade`, `@suaempresa`, `Logo`, `Assistência técnica na sua cidade` e, no lockup, `MARCA` / `EXEMPLO` / `@empresa` / `Cidade · UF`. Quem usava o template ou o padrão sem passar esses campos agora recebe os placeholders (os contratos em `clients/` passam todos os valores e não mudam). O `preview.png` do lockup, o `catalog.json` e a tabela do `motion/README.md` foram regenerados com `preview.sh` e `catalog.mjs`. A procedência dos padrões e dos templates (`clients/<cliente>/...`) virou texto genérico. O id do padrão `service-illustrations-wjr` fica: contratos de cliente o referenciam (renomear é mudança de contrato, decisão do dono).
102
+ - **Guarda hermética** (`tests/test_dados_cliente_no_pacote.py`): varre `src/simplicio_video`, o wheel e o sdist inteiro atrás de nomes, @, telefone, e-mail, CPF e CNPJ, em texto, em nome de arquivo e no hash das prévias que mostraram marca de cliente. Cada linha é decodificada antes de comparar (entidades HTML, escapes `\uXXXX` e `\xNN`, percent-encoding), perde acento e caixa, e telefone, CPF e CNPJ são achados pelos dígitos, com qualquer pontuação (CPF e CNPJ só com dígito verificador válido); a conta e o @ do dono e qualquer @ que ninguém liberou são achados; a prévia antiga também é fixada pelo hash dos pixels (salvar a mesma imagem de outro jeito não escapa). Os placeholders (`(00) 00000-0000`, `Rua Exemplo, 123 · Cidade`, `@suaempresa`, `exemplo.com`) e números técnicos (tempos, versões, `viewBox`, timestamps) não acusam. A lista de termos fica em `tests/dados_cliente_guard.py`, fora do pacote. O golden da composição de assistência técnica (`tests/test_compile.py`) compara com o `video-01` legado trocando só as strings de cliente pelos placeholders.
103
+ - **Código morto de venda saiu do pacote:** `prospect.py`, `venda.py` (cobrança Pix e webhook), `ugc.py` e `layout.py` (só o `prospect` o importava), mais `templates/prospect-roteamento.json` e, nos quatro templates de venda, `contract.base.yaml` (marca d'água e @ do dono) e `setores.json`. Nada no CLI, no MCP nem no motor os importava (o CLI já recusava os subcomandos desde a #77). Saíram também os testes exclusivos (`test_prospect.py`, `test_prospect_institucional.py`, `test_venda.py`, `test_ugc.py`); a cobertura do motor que morava neles voltou em `tests/test_templates_empacotados.py` (`{{padrao:<bloco>}}` e cada template com composição, validado e compilado com um contrato genérico). A varredura de imports de módulo morto agora é pela árvore sintática (pega import multilinha, `importlib` e `__import__`) e inclui `layout`. Quem importava `simplicio_video.prospect|venda|ugc|layout` à mão perde o módulo; o histórico do git (até a 0.4.0) e o repositório de operação guardam o código. Ficam `publish.py` e `realoficial.py`, que ainda têm dependente (`test_contrato_sem_drive.py` e `commands/setup.py`).
104
+ - **Metadados do `pyproject.toml`:** `setuptools>=77`, licença como expressão SPDX (`license = "AGPL-3.0-or-later"`, `license-files = ["LICENSE", "NOTICE"]`; a tabela `{ text = ... }` está depreciada e some em 2027), autor `Wesley Simplicio` (sem e-mail), palavras-chave, classificadores (Beta, Console, Developers, **só POSIX :: Linux**: macOS e Windows ainda não foram confirmados em máquina real; Python 3.11 a 3.13; Multimedia :: Video) e `[project.urls]` (Homepage, Repository, Issues, Changelog). A versão não mudou.
105
+ - **`PYPI.md` é a página do PyPI** (`readme` do pacote): instalação (`pip`, `pipx`, extra `[mcp]`), requisitos (Python >= 3.10, Node >= 22, ffmpeg com libass, rede e cerca de 470 MB medidos num HOME limpo no primeiro render), primeiros passos (`setup`, `doctor`, `init`, `validate`, `run`; o `doctor` sai com erro até rodar o `setup`), o que não faz (não posta nem publica, não chama LLM no caminho padrão), plataformas e licença, com todos os links absolutos. Só afirma o que existe na `main`: a voz `local` diz o que o extra `[local-tts]` não instala (`SIMPLICIO_TTS_PY` e os modelos do Kokoro, que o pacote não baixa); o esqueleto do `init` não é vendido como primeiros passos (preencher os `TODO` não basta: o `validate` aponta o que falta, e o tutorial e a receita são o caminho); e macOS e Windows seguem como não confirmados em máquina real, sem citar `scripts/smoke_so.py` nem testes com sistema simulado, que só chegam com o PR de operação. O teste confere links, âncoras e caminhos entre crases contra `origin/main`. O `README.md` segue sendo a página do GitHub.
106
+ - **sdist:** `MANIFEST.in` põe só o `CHANGELOG.md` além do que o setuptools já inclui (`src/`, `PYPI.md`, `LICENSE`, `NOTICE`, `pyproject.toml`). **A suíte não vai no sdist** (`prune tests`): ela depende de `clients/`, `docs/`, `scripts/` e do git (200 falhas e 11 erros medidos rodando-a de um sdist) e traz nomes de cliente e fixtures com formato de chave, e o PyPI é imutável. O `README.md` do GitHub também fica de fora (`exclude README.md`; o readme do pacote é o `PYPI.md`), e o próprio `MANIFEST.in` não vai no sdist: o `python -m build` faz o wheel a partir do sdist e relê o arquivo lá, onde o que ele exclui já saiu, e cada `exclude` que não acha nada vira um aviso. O bytecode de um checkout sujo não vai nem pelo glob de `data/` (`exclude-package-data` no `pyproject.toml`, que vale também para o wheel; o `global-exclude` avisaria em todo build limpo). Testes lentos constroem o sdist de uma cópia do checkout com bytecode plantado, conferem a raiz do que ele leva e rodam a mesma guarda de dado de cliente sobre o sdist inteiro; e constroem o sdist e o wheel a partir dele numa cópia limpa, sem nenhum aviso do build. Falham (não pulam) se faltar `setuptools>=77`. Quem empacota roda os testes do checkout.
107
+ - **Outros:** `NOTICE` com URLs absolutas no lugar de caminhos de `docs/` que o pacote não traz; o `Dockerfile` copia `PYPI.md`, `LICENSE` e `NOTICE` (o `pip install .` da imagem lê o readme e os `license-files`; sem eles o setuptools só avisa e gera um wheel sem o readme e sem as licenças, o que a AGPL não aceita) e trabalha em `/workspace`, o volume (o `init` grava em `./clients/...`, que antes caía em `/home/simplicio` e sumia com o `--rm`); o `--help` e o início rápido do README usam `clients/<cliente>/<campanha>` no lugar dos clientes reais; a referência gerada (`docs/reference/`) não lista mais `ABACATEPAY_*`, `SIMPLICIO_DRIVE_DESTINO` e `SIMPLICIO_VOICE_REGEN`.
108
+ - **Revisão independente do PR #115 (1 bloqueante e 5 importantes; cada achado com teste vermelho antes).** K1: o sdist levava a suíte inteira e o `README.md` (nomes de cliente, o endereço sem número e um terceiro prospect): `prune tests` e `exclude README.md`, com teste sobre o sdist construído. I1: a guarda era uma lista de bloqueio fácil de burlar (entidade HTML, escape `\u`, telefone com espaços, CPF sem pontuação, `@` do dono, prévia reencodada): endurecida, cada caso é um teste que a versão antiga deixava passar. I2: o `{{padrao:}}` e a composição dos templates que nasceram do `prospect` ficaram sem teste: restaurados, com prova por mutação. I3: `video.init` num pacote instalado gravava na pasta do servidor: agora pede `out`. I4: o `PYPI.md` afirmava o que só existe no PR de operação e dizia que `[local-tts]` e os `TODO` bastavam: corrigido. Menores: texto velho do `prospect` nos templates, `layout` e import multilinha na varredura, docstring e `WORKDIR` do Dockerfile. **Não feitos, de propósito:** I5 (`install` e `publish.readme_path` em `site-packages`: PR de operação), `publish.py` e o id `service-illustrations-wjr`, Python 3.10, TestPyPI e o resto dos menores (M3, M7, M8: ajuda e backends num pip install, o nome do dono no wheel).
109
+ - **Fora deste PR, de propósito:** `install`, `update` e `status` ainda tratam o diretório de dados do pacote como se fosse um checkout (PR de operação); fontes duplicadas (Inter 8 vezes); licença do GSAP; decisão sobre o histórico do repositório público; TestPyPI e o workflow de release. **UNVERIFIED:** Python 3.10 (piso declarado, sem interpretador para testar); macOS e Windows em máquina real; a página do PyPI renderizada de verdade (só `twine check --strict` e `readme_renderer` locais).
110
+
111
+ ## 0.4.0 — 2026-10-16
112
+
113
+ Resumo: troca de personagem agnóstica de fornecedor (`swap`), paralelismo com asyncio e tarefas em segundo plano (`jobs`), trilhas MoneyPrinterTurbo e Toonflow, catálogos de 50 formatos e 50 ângulos de anúncio, plano de postagem sem postar (`social`), biblioteca do Openverse com revisão por pedido e ativo no contrato, busca na internet pelo TinyFish (`busca`) e kit para medir a troca em GPU de 6 GB. A fábrica (kernel, host de plugins, board, studio, media) saiu do motor.
114
+
115
+ ### Openverse no contrato e no render
116
+ - **Campo novo e opcional no contrato:** um asset (`assets[]` ou `marca.logo`, imagem ou áudio) pode declarar `openverse: {id, pedido}`. O schema `simplicio.video-contract/v1` continua v1 (campo aditivo, só aceita `id` UUID e `pedido` de 1 a 500 caracteres, sem chave extra). Contrato sem o campo se comporta exatamente como antes (o `validate` nem abre a biblioteca; o render lê o índice uma vez, depois de compilar, para comparar os bytes da composição).
117
+ - **`validate` (e por isso `run` e `render`) passa a recusar, offline e com mensagem clara:** id que não existe na biblioteca; arquivo com sha256 diferente do da biblioteca (trocado ou alterado); sem veredito aprovado para o par exato (id, sha256, pedido, proveniência), com a dica quando a aprovação existe para outro pedido ou deixou de valer porque autor, licença ou origem mudaram; índice inválido; licença com restrição (`nc`, `nd`, `sa`) sem o `--aceito-restricao` gravado no export; crédito ausente em `CREDITS-openverse.md`; **arquivo em `assets/openverse/` sem o bloco** (copiar à mão não burla o portão) e qualquer asset com os mesmos bytes de um ativo da biblioteca sem o bloco; bloco em arquivo fora de `assets/openverse/`. Sem rede, sem LLM, nada gravado na biblioteca. A regra de aprovação não foi duplicada: `openverse.verify_asset` (nova, pública) reaproveita `_revisao` (o último veredito do par), `_check_export_rights` e o marcador do crédito; o glue do contrato fica em `openverse_contract.py`.
118
+ - **O render registra a procedência.** `render.manifest.json` (e `preview.manifest.json`) ganha a chave opcional `openverse`: `creditos`, `creditos_sha256` e, por ativo, id, sha256, tipo, licença, pedido revisado, quem aprovou, canal e data da aprovação, `aceito_restricao`; título, autor e URLs saem só como `untrusted_*` (dado de terceiros). Os créditos do vídeo vão para `<video>.CREDITS-openverse.md` ao lado do MP4 (e da prévia), gerados do índice com as mesmas sanitizações do export (sem HTML, link solto nem quebra de linha): a regra de atribuição CC BY vale para o vídeo entregue. Os hashes dos ativos já entram no `inputs_sha256` (o arquivo é copiado para a composição); mesma entrada, mesmo manifesto e mesmos créditos. Contrato sem Openverse não ganha chave nem arquivo.
119
+ - **`simplicio-video openverse library verify <contrato> [--json]`:** roda o mesmo portão, lista por ativo o que está ok e o que falta e sai com 1 se falta algo; sem rede e sem tool MCP nova (o agente usa `video.validate`; `plugin.json` e a lista de tools MCP não mudam).
120
+ - **O export grava o aceite da restrição:** o registro de exportação ganha `aceito_restricao` e `licenca`, a licença aceita (só quando a licença tem restrição e o `--aceito-restricao` foi passado; o aceite vale só para essa licença e o export repetido com outra licença grava um registro novo). O schema do índice (`library.schema.json`) e os schemas dos manifestos (`render-manifest`, `preview-manifest`) ganharam o campo, ainda na v1 (aditivo). A mensagem de licença restrita diz "repita o export com --aceito-restricao".
121
+ - **Revisão independente do PR #111 (achados corrigidos, cada um com teste vermelho antes).**
122
+ - **Bloqueante: `placas_video[].file` levava ativo de `assets/openverse/` ao vídeo sem bloco, sem revisão e sem crédito.** Agora a placa passa pelo mesmo portão (nunca carrega o bloco: arquivo em `assets/openverse/` ou com bytes da biblioteca é recusado com "declare em `assets[]` com o bloco `openverse`"), e o render confere a **composição compilada**: depois do `build`, todo arquivo do workdir com o sha256 de um item da biblioteca precisa ser o `destino` de um asset declarado e aprovado com esse sha256, e todo `destino` declarado precisa ter exatamente o sha256 da procedência. Isso fecha também a cópia exata na pasta do template e a troca do arquivo entre o portão e a cópia; `render_preview`, `write_manifest` e `deliver` usam o mesmo `info["files"]`, então o manifesto nunca credita o que não está no vídeo. Falha: `SystemExit` em português, sem texto da internet.
123
+ - **`destino` repetido** em `assets[]`, `marca.logo` e `placas_video[].file` é erro do `validate` (o último copiado vencia e o manifesto creditava o arquivo errado).
124
+ - **O aceite da restrição vale para a licença aceita:** o registro de exportação grava `licenca` e `verify_asset` exige igualdade (aceitar `by-sa` não vale para `by-nc` depois de um `get --atualizar`).
125
+ - **Regra da pasta sem diferença de caixa:** `assets/OpenVerse` conta (`casefold` e NFC). Use o arquivo exportado como está: recorte e escala na composição (CSS), nunca um derivado em disco (`by-nd` não permite).
126
+ - Menores: `library verify` roda o schema do contrato antes (não diz mais "tudo certo" num contrato que o `validate` recusa); os créditos do vídeo são gravados por `mkstemp` + `os.replace` (um link no nome é trocado, não seguido); o `render.manifest.json` antigo é apagado antes de gravar o novo (um ativo que deixou de valer não deixa o manifesto antigo ao lado de um MP4 novo); o teste dos contratos dos clientes agora roda com a biblioteca com um item e os arquivos dos assets criados numa cópia temporária; SKILL explica que nenhum template embutido referencia áudio externo; comentário impreciso de `contract.py` corrigido.
127
+ - **Follow-up, sem correção neste PR:** índice ilegível desliga a regra "mesmos bytes" para a cópia à mão (só aviso); a regra da pasta fora da pasta do contrato olha só os dois últimos níveis; `additionalProperties: false` nos itens de `openverse.ativos` do manifesto e `arquivo` como derivado do título; custo do hash de assets grandes a cada `validate`; o marcador do crédito é só id+sha256 (uma linha de crédito antiga, de outra licença, continua passando na pasta; o crédito do vídeo sai certo, gerado do índice).
128
+ - **Limites conhecidos:** a narração (`voz.providers.file.dir`) não passa pelo portão (o `voice` recodifica e corta a fala, então o arquivo vira outro): não use ativo do Openverse como voz; nenhum template embutido referencia áudio externo; a aprovação é conferida na biblioteca da máquina (`OPENVERSE_LIBRARY_DIR`); o motor de áudio (`build.mjs`) não mixa um áudio externo sozinho, então um áudio do Openverse declarado só toca se um template ou bloco referenciar o arquivo (o portão e os créditos valem igual); o backend `colab` manual só gera o bundle (sem manifesto nem créditos ao lado do MP4: vale o `CREDITS-openverse.md` de `assets/openverse/`); uma cópia recodificada (outros bytes) não é detectada; o índice não é fronteira de segurança (quem edita o disco edita tudo). Docs: README (seção Openverse, fluxo completo), `docs/recursos.md`, AGENTS.md e `skills/simplicio-video/SKILL.md`.
129
+
130
+ ### Busca na internet (TinyFish)
131
+ - `simplicio-video busca consulta|pagina|status|log` e a tool MCP `video.busca` (`consulta`, `pagina`, `status`, `log`; nada de `agent`, `browser` nem `monitor`). Usa o CLI `tinyfish` (npm `@tiny-fish/cli`, versão testada e fixada 0.50.1 em `tools.py`), que o motor **nunca instala**: `busca status` mostra o comando (`npm install -g @tiny-fish/cli@0.50.1`, `tinyfish auth login` ou `... | tinyfish auth set`). Zero tokens: nenhuma chamada de LLM e nenhuma biblioteca de rede no motor.
132
+ - **Consulta e página.** `consulta "<texto>"` chama `tinyfish search query` (`--dominios`, `--excluir`, `--idioma`, `--limite` padrão 5 e máximo 20, aplicado no motor, `--atualizar`); `pagina <url>` chama `tinyfish fetch content get <url> --format markdown` (uma URL por chamada, `--max-bytes` padrão 20 KB). Cada resultado sai com `untrusted_fonte` (a URL) e `consultado_em` (a data), o que um fato de cliente precisa para citar fonte.
133
+ - **Privacidade.** A consulta e a URL são enviadas a um terceiro (TinyFish), e o help diz isso. Antes de gastar uma chamada o motor recusa segredo (`AIzaSy`, `AQ.`, `sk-`, `sk_live_`, `ghp_`, `hf_`, `npm_`, `glpat-`, `Bearer`, JWT, chave privada, valor de variável com a palavra `KEY`/`SECRET`/`TOKEN`/`PASSWORD` no nome, URL com `usuário:senha@` ou credencial na query ou no fragmento) sempre, e e-mail, CPF e CNPJ (sem pontuação só com dígito verificador válido) salvo `--permitir-dado-pessoal`, que existe só no terminal (nem o MCP nem o plugin o têm).
134
+ - **Gasto.** Contador local por dia UTC (`busca.contador.json`, escrita atômica sob trava, reserva a chamada antes de executar, chamada que falha também conta, contador adulterado recusa em vez de zerar) com teto `--max-chamadas-dia`, `SIMPLICIO_BUSCA_MAX_DIA` ou 20; passou do teto, recusa com mensagem clara sem chamar nada. Cache por hash da consulta, com a data real (repetir não gasta e funciona offline; resultado com 7 dias ou mais avisa; `SIMPLICIO_OFFLINE=1` só serve o cache, o que também impede o gate de chamar o TinyFish de verdade por engano).
135
+ - **Procedência.** `busca.registro.jsonl` (`simplicio.busca-registro/v1`, uma linha por consulta ou página, mesmo vinda do cache): quando, consulta ou URL, versão do CLI, URLs mostradas, sha256 e tamanho do que o CLI devolveu e do que foi entregue, canal (terminal ou mcp). Sem registro gravado, o resultado não é entregue. `busca log` lista; linha quebrada é contada e pulada.
136
+ - **Dado de terceiros.** Título, trecho, texto de página, descrição, autor e URLs saem só em campos `untrusted_*` com `aviso_untrusted` no cabeçalho (texto, JSON, CLI e MCP). Antes de gravar ou mostrar o texto perde HTML, `<script>`, comentários, caracteres de controle, ocultos e de direção, e link que não seja http/https, e é cortado (título 300, trecho 1000, página 20 KB em bytes UTF-8 sem partir caractere); só URL http/https de host com nome público sobrevive (sem IP, `localhost`, `usuário:senha@` nem os sufixos `.internal`, `.local`, `.lan`, `.localdomain`, `.localhost`, `nip.io` e `sslip.io`: lista curta, não garantia). A limpeza das tags repete até estabilizar (tirar uma tag pode juntar as pontas em outra, como em `<<b>script>`) e o que sobra de um `<` de abertura é descartado. Só os primeiros 400 mil caracteres de uma página entram na limpeza e as expressões regulares têm limites de tamanho (testado com entradas feitas para travar o motor).
137
+ - **Chamada do binário.** Só por lista de argumentos (sem shell), sem entrada padrão, com tempo máximo (60 s a busca, 120 s a página) e teto de saída (2 MB e 8 MB; passou, mata o grupo de processos), com ambiente de lista fechada (`PATH`, `HOME`, `LANG`, proxy e certificados, `TINYFISH_API_KEY` se existir, e `NO_COLOR` e `TINYFISH_NO_TELEMETRY` definidos). A chave nunca é lida, impressa nem gravada; o `key_preview` do `tinyfish auth status` (12 primeiros e 4 últimos caracteres da chave) é descartado.
138
+ - **Regra no AGENTS.md:** fato de cliente só entra com fonte e data vindas do registro da busca, depois de ler a página; a busca não substitui a coleta do cliente. Skill `skills/simplicio-video/SKILL.md` e README (seção "Busca na internet (TinyFish)") atualizados.
139
+ - `tools.py` registra `tinyfish` (npm, 0.50.1, licença **não declarada** no pacote: sem campo `license` nem arquivo LICENSE); `status` lista a ferramenta e o uso do teto; `plugin.json` ganha quatro verbos fechados (`video.busca.consulta|pagina|status|log`, com o texto livre depois de `--`) e a capacidade `external:tinyfish`; dados em `src/simplicio_video/data/busca/` (`tinyfish.json` com fonte, data e confiança de cada fato, e os schemas `registro`, `cache` e `contador`); `SIMPLICIO_BUSCA_MAX_DIA` e `TINYFISH_API_KEY` descritas em `docs/reference/config.md`.
140
+ - **Revisão independente do PR #112** (1 bloqueante e 4 importantes, mais menores; cada achado com teste vermelho antes):
141
+ - **Bloqueante.** O `status` geral lia a versão do `tinyfish` com `subprocess.run` sem `env=`: o binário de terceiros recebia o ambiente inteiro (162 variáveis medidas, com `GEMINI_API_KEY` e `GITHUB_TOKEN`, e sem `TINYFISH_NO_TELEMETRY`), até com `SIMPLICIO_OFFLINE=1`. Agora usa o ambiente fechado do `busca` (11 variáveis medidas, telemetria desligada) e a versão continua visível. Mesmo padrão ainda existe para `hypit`, `ffmpeg` e `node` no `status` (anterior ao PR, fora do escopo): ver follow-ups.
142
+ - **`javascript:` sobrevivia** em colchetes aninhados, parênteses em dois níveis, rótulo com mais de 500 caracteres e definição com quebra de linha. Uma passada final, sem depender da gramática Markdown, tira os dois pontos de `javascript:`, `vbscript:`, `data:` e `file:` com alvo colado (inclui a forma por entidade, `&#106;avascript:`). Critério: não mexe em texto comum (`data: 5 itens`), em palavra maior (`metadata:x`) nem em URL http(s) com `File:` ou `data:` no caminho ou na query (`/wiki/File:Foo.jpg`).
143
+ - **Credencial na URL.** Confere query e fragmento, com o nome do parâmetro por sufixo (`access_token`, `X-Amz-Signature`, `X-Goog-Signature`, `private_token`, `code`, camelCase incluído); recusa antes de gastar e antes de reservar o contador.
144
+ - **Procedência no redirecionamento.** `final_url` não vazio e recusado (IP, nome interno, `usuário:senha@`, IDN) não cai mais de volta na URL pedida: o conteúdo não é entregue nem guardado, o registro leva `url_final_recusada: true` (schemas atualizados) e o erro diz "redirecionamento para URL recusada".
145
+ - **Mutantes vivos.** Testes novos prendem "registro antes de entregar" (registro que é diretório recusa a entrega), "URL validada antes de gastar" (contador inexistente ou intacto), "cache editado é limpo de novo na entrega" e `_guard` (valor de credencial do ambiente recusa a gravação).
146
+ - **Menores.** U+2028 e U+2029 viram quebra de linha e U+034F, U+180E, U+2800 e U+3164 saem do texto; ReDoS: rótulo de link de no máximo 200 caracteres e as regex de link rodam uma vez (`"<<<<<b>b>b>b>b>" + "[" * 1_000_000` caiu de 11,8 s para 1,05 s, com teto de 3 s no teste); nome de variável casa por palavra (`PIP_KEYRING_PROVIDER` não é segredo) e entram `sk_live_`/`rk_live_`, `hf_`, `npm_`, `glpat-`, `bearer` em qualquer caixa e chave privada em qualquer caixa; `-h`/`--help` só valem antes de `--` no `cli.py`; o argv do binário leva `--` antes da consulta ou da URL; o motor roda com `simplicio_video.busca` bloqueado (o texto do help foi para `busca_ajuda.py` e o `build_parser` não importa mais o módulo); `untrusted_erro` leva o texto de terceiros dos erros (CLI e MCP) e `cli_versao` do cache é validada; cache com `total_cli` não numérico ou `parametros` de outra consulta vira consulta nova em vez de `ValueError`; Ctrl+C durante a chamada mata o `tinyfish`; o help diz que o preço é UNVERIFIED e o que o `busca status` roda (`--version` e `auth status`, locais, sem rede pela leitura do pacote).
147
+ - **Follow-up, não feito:** `cache/` e `busca.registro.jsonl` não têm rotação, e `log()` lê o arquivo inteiro. **UNVERIFIED:** o argv com `--` não foi exercitado contra o binário real (só lido: o commander respeita `--` e o próprio pacote usa `search query --pretty -- <query>`); o status geral ainda roda `hypit`, `ffmpeg` e `node` com o ambiente inteiro (anterior ao PR).
148
+ - **Fumaça com o binário real:** duas chamadas, uma busca e uma leitura de `https://example.com`, para conferir os formatos (fixtures sanitizadas em `tests/fixtures/busca/`); saldo da carteira igual antes e depois e tarifas Search 0 e Fetch 0 USD (uma segunda leitura das tarifas voltou `Rates: unavailable`). Os testes usam um `tinyfish` falso e nunca o binário real nem a rede.
149
+ - **UNVERIFIED / fora do escopo.** `--include-domains` não foi exercitado numa chamada real; erros HTTP do TinyFish (401, 402, 429), página atrás de login ou anti-bot e página muito grande não foram vistos; limites de taxa, termos de uso e retenção das consultas no TinyFish não foram lidos; a licença do pacote não está declarada. `agent`, `browser` e `monitor` ficam de fora de propósito (cobrados por passo ou minuto, com login e efeitos). A checagem de dado pessoal é um freio: telefone, nome e endereço não são detectados.
150
+
151
+ ### Biblioteca de imagens e áudio (Openverse)
152
+ - `simplicio-video openverse search|get|library list|show|review|export|credits` e a tool MCP `video.openverse` (`search`, `list`, `show`, `folha`, `review`; baixar e exportar só pelo terminal). Busca imagens e áudio no [Openverse](https://openverse.org/), baixa para uma biblioteca local (`OPENVERSE_LIBRARY_DIR`, padrão `~/.simplicio-video/openverse-library`, com `index.json` versionado e arquivos nomeados pelo sha256) e só exporta o que foi **aprovado para o pedido**, com a linha de crédito. Zero tokens: nenhuma chamada de LLM.
153
+ - **Revisão por par (ativo, pedido).** `library review --folha` gera uma folha determinística para o revisor (agente ou pessoa) decidir: imagem com dimensões, proporção, formato real, nitidez (variância do Laplaciano), brilho médio e miniatura; áudio com duração, taxa de amostragem, loudness (ebur128), fração de silêncio, clipping e espectrograma; mais uma pista textual (palavras do pedido no título e nas tags, que não é veredito) e o que falta conferir. `--aprovar` e `--reprovar` gravam id, sha256, proveniência, pedido normalizado, veredito, motivo, quem revisou, o canal (terminal, mcp ou plugin) e a data. Aprovar para um pedido não vale para outro, nem para outro id com os mesmos bytes; arquivo novo (outro sha256) ou autor, licença ou origem trocados invalidam a aprovação; aprovar exige a folha do par; o último veredito vale. O `export` recusa não revisado, reprovado, autor ausente (CC BY), licença desconhecida, `nc`/`nd`/`sa` sem `--aceito-restricao`, arquivo alterado e sobrescrita de arquivo com bytes diferentes (mesma regra do `publish`); acrescenta título, autor, licença e URLs a `CREDITS-openverse.md`.
154
+ - **Licenças.** Padrão `cc0,pdm,by`; `by-sa`, `by-nc`, `by-nd` (e `by-nc-sa`, `by-nc-nd`) só por `--licencas` explícito, com aviso. A licença vem das fontes e o Openverse manda conferir na origem: o item guarda a `foreign_landing_url`. **Isto não é parecer jurídico.** Item sem licença conhecida nunca é baixado. A API pode devolver o que não foi pedido: o motor descarta licença fora do pedido, sem licença, `mature` e sem URL.
155
+ - **Download seguro.** Só https (porta 443); o host é resolvido e endereços privados, loopback, link-local e reservados são recusados antes e depois de cada redirecionamento (até 5), com conexão no IP validado; limite de 25 MB (imagem) e 50 MB (áudio) lido em blocos, com prazo total e conferência do tamanho anunciado; tipo pela assinatura dos bytes (nunca pelo Content-Type); nome do arquivo derivado do sha256; sha256 conferido depois de gravar; o ffmpeg só abre o arquivo da biblioteca, com demuxer forçado e só o protocolo `file`.
156
+ - **Cache e limites.** A busca é cacheada por hash da consulta, com data (repetir sai do cache e funciona offline; `--atualizar` consulta de novo). Sem credencial: 20 por página. Lido na API em 2026-10-16: limites anônimos de 20 por minuto e 200 por dia (cabeçalhos `x-ratelimit-*`; o código-fonte público traz outros padrões). `OPENVERSE_CLIENT_ID` e `OPENVERSE_CLIENT_SECRET` (OAuth2 client credentials) são opcionais, só por variável de ambiente, nunca em argumento, índice, cache, folha ou saída (filtro de redação).
157
+ - Revisão independente (achados corrigidos, cada um com teste vermelho antes): o mascaramento de formato de chave não alterava só mensagens, mas também URLs e títulos gravados no cache e no índice (`risk-assessment` virava `ri***`): agora só texto digitado pelo usuário e mensagens são mascarados, com limite de palavra, e dados da API ficam exatos; o prazo total do download passou a contar desde a conexão e a leitura usa `read1`, para um servidor que manda um byte por vez não travar o `get`; `Content-Length` com dígito não ASCII não derruba mais o download; a saída do ffmpeg é decodificada com `replace` (tag de metadado em outra codificação quebrava a folha) e os números de loudness, silêncio e clipping só vêm de linhas com o prefixo do próprio filtro (um metadado hostil não falsifica a folha); a API do Openverse não segue redirecionamento (o `urllib` reenviaria o token ao outro host) e tem teto de corpo; `get` confere o sha256 do arquivo (não só o tamanho) e avisa quando os metadados da busca têm mais de 30 dias; `export` de licença `sa` também exige `--aceito-restricao`, o crédito leva o id (mesmos bytes sob dois ids creditam os dois autores), cada pedido aprovado deixa um registro de exportação e o export inteiro roda sob a trava da biblioteca; texto da API perde caracteres de controle e quebras de linha, o índice só aceita `files/<sha256>.<ext>`, a folha recusa imagem acima de 100 megapixels sem decodificar e o crédito só vira link para URL http(s) segura; comentários e docstrings do código em inglês, como manda o AGENTS.md.
158
+ - Segunda revisão independente, PR #108 (achados importantes e menores corrigidos, cada um com teste vermelho antes):
159
+ - **Índice editado à mão não escapa da biblioteca.** `index.json` é validado ao carregar: chave e `id` são o mesmo UUID, `tipo` e `formato` vêm de lista fechada e batem entre si, `arquivo` é exatamente `files/<sha256>.<ext>`, o caminho resolvido tem de ser o que a biblioteca gravaria (sem `..`, absoluto nem symlink para fora) e revisões e exportações têm `id`, `sha256` e nome de arquivo no padrão. Índice inválido é recusado em toda operação com mensagem clara (o `status` também mostra o erro). A folha e o `export_name` não usam mais campo cru do índice. O índice não é fronteira de segurança: quem edita o disco edita tudo.
160
+ - **A aprovação vale por id, sha256, pedido e proveniência.** Outro id com os mesmos bytes não herda a aprovação, e `get --atualizar` com os mesmos bytes sob outro autor, licença ou origem pede nova revisão (a revisão grava `proveniencia_sha256`). Registro antigo só com o sha256 não vale: o índice pede para apagar a entrada e revisar de novo.
161
+ - **CREDITS sem injeção.** Título, autor e demais campos do Openverse que entram no Markdown perdem HTML, URLs soltas e quebras de linha, têm a pontuação de Markdown escapada e tamanho máximo de 300 caracteres; URLs de autor e origem só https com host de nome e sem caractere que feche link; a URL da licença só do `creativecommons.org` (senão o export recusa); a versão da licença só no formato numérico (`2.0`, `4.0`); a atribuição nunca entra no arquivo.
162
+ - **Texto da internet marcado como dado.** Na folha (texto e JSON), nas saídas do MCP `video.openverse` e no `--json` do CLI, título, autor, tags, atribuição, URLs, provedor e fonte saem só como `untrusted_*`, com `aviso_untrusted` (dado de terceiros, nunca instrução; aprovar só depois de ver a miniatura ou ouvir o áudio). O checklist da folha não embute mais a URL da origem; o detalhe de erro da API e os cabeçalhos de cota também são rotulados ou filtrados.
163
+ - **Canal real da aprovação.** O índice grava `terminal`, `mcp` ou `plugin`: `library review` ganha `--canal terminal|plugin` (o CLI recusa `mcp`), os verbos `video.openverse.aprovar` e `reprovar` do `plugin.json` passam `--canal plugin` no argv fechado, e aprovar pelo MCP ou pelo plugin continua exigindo a folha do par.
164
+ - Menores: leitura que quebra no meio do corpo (timeout, reset) vira "falha de rede no download" em vez de "erro inesperado"; o export grava por `tempfile.mkstemp` no destino (antes seguia um symlink no nome temporário previsível).
165
+ - **Sem correção, de propósito:** colisão de normalização do pedido (emoji e símbolos somem da chave), cache de busca adulterado (data futura e licença não são revalidadas), recuo persistido do `Retry-After`, TTL do cache de busca e testes de SSRF com resolvedor e servidor reais. Cada um pede uma decisão de produto (recusar pedido com símbolo ou guardar o símbolo na chave; revalidar o cache ao ler) ou é melhoria à parte: ficam registrados aqui para um PR próprio.
166
+ - Dados em `src/simplicio_video/data/openverse/` (`licenses.json`, `api.json` com fonte, data e confiança de cada fato, e os schemas `library`, `licenses` e `api`); `plugin.json` ganha seis verbos fechados (`video.openverse.search|list|show|folha|aprovar|reprovar`); `status` mostra a biblioteca e se as variáveis OAuth2 existem (nunca o valor); `swap_providers/http.py` ganha `form` e os cabeçalhos da resposta (aditivo).
167
+ - **UNVERIFIED / fora do escopo.** O fluxo OAuth2 com credencial real e o download direto do `url` nas fontes não foram exercitados (só 3 requisições anônimas de leitura e uma miniatura); o áudio do Freesound vem como a prévia mp3 que o Openverse indica no `url`. Não está integrado ao `contract.yaml`/schema do render (o export deixa os arquivos em `assets/openverse/` com os créditos). CLIP local (extra `[review]`) fica como evolução. O Openverse não endossa nem certifica este projeto.
168
+
169
+ ### Correções na receita do social e na saída de tarefas
170
+ - **`social recipe` não reescreve mais a legenda aprovada.** A receita resolvia os campos do plano e depois passava a troca de marcadores sobre o resultado, então `{plan}`, `{step.x}`, `{video_name}` e `{video_sha256_short}` escritos DENTRO da legenda, do título ou do nome do vídeo viravam caminho, número de passo ou nome de arquivo, e a publicação pública podia sair diferente do que o usuário aprovou. Agora o texto do plano (legenda, título, contas, nome e caminho do vídeo) entra como dado, e só os modelos do `providers.json` passam pela troca de marcadores, em uma única passada que não reprocessa o que inseriu (a troca em cadeia também reprocessava o caminho do plano). Os espaços reservados que o próprio motor escreve (`passo N`) ganham o número na construção. Testes: legenda e título com `{plan}`, `{step.x}`, `{{`, `}}`, `%s`, `$(...)`, crase, quebra de linha, tab e emoji saem idênticos byte a byte na função, no CLI em JSON, no CLI em texto e no MCP, nos dois provedores; a receita hostil é igual à comum fora dos dados.
171
+ - **Chave local de aceite sem corrida.** Dois `plan --aceito-unverified` ao mesmo tempo estouravam `FileExistsError` (traceback) ao criar a chave. A chave agora sai inteira de um arquivo temporário privado e entra no lugar com `os.link` (atômico, nunca sobrescreve); quem perde a corrida relê a chave vencedora. Chave truncada vira erro claro do `social`, sem sobrescrever.
172
+ - **`jobs`: ordem da saída.** A linha de progresso (`\r`) ficava guardada até o fim da saída e saía DEPOIS das linhas reais que vieram depois dela, e o `error` de uma tarefa que falhou podia mostrar uma barra de progresso velha no lugar da mensagem. Ao chegar uma linha real, o progresso pendente é escrito antes dela (log, `tail` e leitura do JSON do resultado); no fim sai o último pendente, e os intermediários continuam colapsados em um só.
173
+ - `social.py`: comentários e docstrings em inglês (AGENTS.md), sem mudar comportamento; um teste vigia o arquivo. Mensagens de erro e textos de ajuda seguem em pt-BR.
174
+
175
+ ### Kit de medição da troca de personagem em GPU de 6 GB
176
+ - Material de operação e de teste, sem mudar o motor: how-to em `docs/how-to/troca-personagem-gpu/` (passo a passo para Windows com GPU NVIDIA de 6 GB, prompt para a sessão da GPU, resultados dos testes em CPU e planilha) e seis scripts autônomos em `scripts/kit_gpu/`. Também funciona fora do repositório, copiando as duas pastas.
177
+ - Só testado em Linux com CPU: Windows, NVIDIA, ComfyUI e os modelos seguem sem teste, e as ressalvas UNVERIFIED e as licenças ficam como estavam. `numpy`/`opencv` (e `torch`) são só dos scripts, fora do `pyproject.toml`. Nenhuma mídia entra no repositório.
178
+
179
+ ### Redes sociais sem postar (social)
180
+ - `simplicio-video social providers|plan|check|recipe` e a tool MCP `video.social` (só `providers`, `plan`, `check` e `recipe`; qualquer ação de publicar é recusada). O motor não posta ([ADR-0018](docs/decisoes/ADR-0018-social-planejar-sem-postar.md)): planeja, confere e documenta; quem publica é o agente, com as ferramentas MCP do Real Oficial (padrão) ou do Zernio e o sim explícito do usuário por postagem.
181
+ - `plan` recusa vídeo inexistente ou que não seja MP4, mede com `ffprobe` e confere duração, proporção, tamanho, legenda, título e hashtags contra `data/social/limits.json` (`source_url`, `read_on` e `confidence` por linha; só a duração do YouTube Shorts foi conferida na página oficial, o resto é UNVERIFIED e pede `--aceito-unverified`). Grava `social.plan.json` determinístico, sem horário de geração e sem chave ou token; não sobrescreve sem `--force`.
182
+ - `check` confere sha256, tamanho, integridade do plano e se o agendamento ainda está no futuro. `recipe` imprime a sequência exata de chamadas MCP por provedor (modelo de dados em `data/social/providers.json`): cotar ou prever, mostrar, consentimento, publicar; o motor se recusa a gerar receita que publique antes do consentimento.
183
+ - Skill `skills/simplicio-video-social/SKILL.md` com o fluxo e as regras de consentimento; `plugin.json` ganha quatro verbos fechados (`video.social.providers|plan|check|recipe`).
184
+ - Lacuna registrada: o Real Oficial não recebe MP4 local por MCP (a receita pede o `clip_id`); o fluxo do Zernio está em boa parte UNVERIFIED.
185
+ - Revisão do PR #107: `check` e `recipe` revalidam o plano contra o vídeo (`ffprobe`) e a tabela de limites e recusam plano que não seja o que `plan` geraria (o `plan_id` é só soma de integridade); o aceite UNVERIFIED é assinado (HMAC) com chave local. A trava de consentimento vale para a sequência completa do `providers.json`, executa `requires` e tem piso no código; `providers.json` adulterado faz o motor recusar a receita. Real Oficial sem `--clip-id` bloqueia a receita com o motivo (texto, JSON, MCP; saída 1). `youtube` (vídeo) separado de `youtube_shorts` (180 s e proporção 9:16 ou 1:1 só no Shorts, com um quadro de folga). Conta, legenda e título com cara de segredo são recusados; `--at` no passado ou além de 30 dias é recusado; sem `--ai-generated` a receita pergunta; o plano não segue symlink no `.tmp`; MOV renomeado para `.mp4` é recusado. Testes: varredura AST de importação dinâmica, fluxo sem socket, sequência com lista fixa e mutação.
186
+
187
+ ### Troca de personagem (swap)
188
+ - `simplicio-video swap providers|estimate|run|status` e a tool MCP `video.swap` (só `providers` e `estimate`; gastar é só pelo terminal). Orquestração única em `src/simplicio_video/swap.py` e um adaptador por fornecedor em `src/simplicio_video/swap_providers/`: `gemini` (Interactions API, conferido na documentação), `fal`, `wavespeed`, `kie` e `alibaba` (**UNVERIFIED**: escritos da documentação pública, sem conferência na API real) e `fake` para testes.
189
+ - `--autorizo` é obrigatório; sem `--yes` só estima (dry-run, sem rede); `--max-usd` (padrão US$ 2) aborta antes de submeter; adaptador UNVERIFIED pede `--aceito-unverified`. A chave só entra pela variável de ambiente do provedor e nunca vai a argumento, log ou manifesto.
190
+ - Corta o vídeo em pedaços do tamanho que o provedor aceita, remonta o áudio original quando o provedor não o preserva, normaliza fps e duração e emenda. Grava `swap.manifest.json` com hashes, custo previsto e medido, latência por etapa, tentativas e o texto da autorização.
191
+ - Tabela de preços por adaptador com `source_url`, `read_on` (2026-10-15) e `confidence`, e câmbio de referência (R$ 5,0521 por US$, PTAX de 2026-10-15) em campo separado. `status` lista quais provedores têm a variável da chave definida (nunca o valor).
192
+
193
+ - Revisão independente do PR #103: a emenda usa nomes relativos e escapa apóstrofo no caminho; se algo falhar depois do download, os pedaços já gerados e pagos ficam numa pasta `<saída>.swap-recovery` (caminho na mensagem de erro e em `recovery_dir` do manifesto), nunca apagados; o manifesto é gravado logo após cada `submit` (com o handle) e também em Ctrl+C (`interrupted`, código 130) e em qualquer exceção, sem traceback.
194
+ - `submit` não é repetido após erro de rede nem após resposta 2xx sem JSON (a requisição pode ter sido aceita e cobrada; nenhum provedor tem chave de idempotência aqui): o erro avisa do risco e o pedaço fica com `possibly_charged: true` no manifesto. Respostas 429/5xx continuam com nova tentativa. Erro de cota ("You exceeded your current quota") e de plano grátis (`limit: 0`, qualquer redação) nunca repetem.
195
+ - A redação de segredos reconhece chaves pelo formato (`AIzaSy...`, `AQ....`) além das variáveis de ambiente, em log, manifesto e mensagem de erro. Chave com espaço ou caractere de controle é recusada. A chave do Gemini só vai a `*.googleapis.com` por https, e `SIMPLICIO_GEMINI_BASE` exige https (http só em localhost). `--max-usd` recusa `nan`, `inf` e negativo.
196
+ - `plugin.json`: o verbo `video.swap` deixou de aceitar `args` livre (que permitia `run` pago pelo runtime). Agora são dois verbos fechados e sem gasto: `video.swap` (só `estimate`, com `provider`, `video`, `ref`) e `video.swap.providers`.
197
+
198
+ ### Paralelismo (asyncio) e tarefas em segundo plano
199
+ - `swap run --concurrency N` (padrão 3; cada adaptador pode limitar a menos: os UNVERIFIED ficam em 2; 1 = serial): os pedaços do vídeo são enviados e consultados em paralelo (asyncio sobre o cliente HTTP da biblioteca padrão, cada chamada bloqueante numa thread daemon, sem dependência nova). A emenda e o manifesto seguem a ordem do vídeo, não a de conclusão: a saída tem o mesmo sha256 da serial. Se um pedaço falha, os outros são cancelados e o erro diz qual (`pedaço 2/3: ...`); `--timeout` vale por pedaço; Ctrl+C cancela limpo (estado `interrupted`, sem `.swap-work`, sem thread, handles pagos no manifesto). As regras do #103 continuam: manifesto gravado após cada submit, pedaços pagos preservados em `.swap-recovery`, submit nunca repetido após erro de rede. O ffmpeg (corte, normalização, emenda) segue serial.
200
+ - O manifesto registra `concurrency` (pedido, efetivo, limite do adaptador), `latency.total_s` por pedaço e `timing` (`wall_s`, `sum_chunks_s`, `speedup`, `saved_s`): o tempo total contra a soma dos tempos dos pedaços.
201
+ - `voice --concurrency N` (padrão 4, só provedor de rede: `gemini`): as falas são geradas em paralelo e o resto (ffmpeg, lock) segue a ordem das falas, então o `timing.lock.json` e os WAVs são byte a byte os do modo serial. Respeita cache e `only`. Provedores locais (CPU) ficam seriais.
202
+ - `simplicio-video jobs submit|status|list|cancel|result|clean` e a tool MCP `video.jobs`: tarefas em segundo plano num processo separado (runner asyncio por tarefa, grupo de processos próprio, sem daemon e sem porta de rede), com estado em JSON atômico em `<dados>/jobs/<id>/`. Lista fechada: `swap-run` (gasta: confirmado na submissão com `--autorizo --yes`, só pelo terminal) e `voice`. O MCP lista, consulta, lê o resultado, cancela e só submete `voice` com provedor local (`file`, `local`, `voxcpm`, `openvoice`); não há como confirmar gasto por ele. Runner morto vira `lost` (a tarefa que sobrou é encerrada); tarefas terminadas há mais de 7 dias são removidas. Argumentos com chave de API são recusados e a redação do swap vale para estado e log.
203
+ - `scripts/bench_concurrency.py`: benchmark com latência SIMULADA (adaptador `fake`, Gemini de voz trocado; sem rede). Medido aqui (mediana de 3, latência 1,0 s por pedaço e por fala, ffmpeg real): swap com 3 pedaços, serial 6,015 s contra paralelo 3,197 s (1,88x; só a fase dos pedaços, pelo manifesto: 2,74x); voice com 8 falas, serial 9,653 s contra paralelo (4) 3,613 s (2,67x). Saída idêntica nos dois (sha256 do MP4 e dos pedaços; `timing.lock.json` byte a byte). O ganho é de sobrepor espera, não de CPU: o render e o ffmpeg continuam seriais porque asyncio não acelera CPU e mais processos só disputariam os mesmos núcleos.
204
+
205
+ - Revisão independente do PR #106 (bloqueantes e importantes corrigidos, cada um com teste vermelho antes):
206
+ - **B1** swap: o `submit` de um pedaço fica protegido do cancelamento. Quando outro pedaço falha (ou Ctrl+C) durante o upload, o pedaço espera até `SUBMIT_DRAIN_S` (10 s) pelo handle que o provedor devolver e o grava no manifesto antes de repropagar o cancelamento; se não terminar, o pedaço fica `possibly_charged: true` e `state: cancelled_during_submit`.
207
+ - **B2** jobs: o grupo de processos de uma tarefa só recebe sinal depois de provada a identidade (pid, start time e boot id gravados em `task_start`/`task_boot` e conferidos). Sem prova (pgid reciclado, outro boot, estado antigo sem identidade) nada é morto: a tarefa vira `lost` e o erro diz que o grupo não foi encerrado. `list`, `status` e `submit` deixam de matar processo alheio.
208
+ - **I1** jobs: a saída da tarefa é lida em blocos de 64 KiB, sem esperar `\n`. Barra de progresso com `\r` e linhas acima de 64 KiB não travam mais o runner (o pipe nunca enche); a chave partida na fronteira de um corte continua apagada.
209
+ - **I2** voice: depois de uma falha, as falas já geradas (e pagas) entram no cache; a rodada seguinte paga só as que faltam, como no serial (12 chamadas contra 7 antes, agora 7). Nenhuma fala nova começa depois da primeira falha, as em voo terminam e são mantidas. O erro reportado é o da fala de menor índice (M3) e a chave do pré-cache passou a ser a mesma da chave real (M4).
210
+ - **I3** o CLI inteiro volta a importar no Windows: nenhum atributo específico de plataforma no import (`signal.SIGKILL` resolvido em tempo de uso, `fcntl` importado onde é usado). `jobs` no Windows recusa com mensagem clara (precisa de grupos de processos e sinais POSIX).
211
+ - **I4** sem `/proc` (macOS) o start time vem de `ps -o lstart=`; sem nenhuma prova de identidade, `cancel` não sinaliza o pid e pede para conferir à mão.
212
+ - **I5** swap: uma execução por pasta de saída, com `flock` em `.swap.lock` (a segunda recusa com mensagem clara em vez de sobrescrever o `swap.manifest.json`); o manifesto agora é gravado com arquivo temporário e `os.replace`. `jobs submit swap-run` também recusa uma segunda tarefa ativa na mesma pasta. O nome do manifesto não mudou.
213
+ - Menores: M1 `jobs submit` recusa argumento com formato de chave mesmo fora do ambiente; M2 o retry síncrono morto do swap foi removido e os testes de cota exercitam o caminho real; M5 o limite das threads órfãs está documentado em `aio.py`; M6 `video.jobs cancel` no MCP só envia o pedido (não bloqueia até 25 s). Sem correção: M7 (`status` não mostra `jobs`).
214
+ - `scripts/bench_concurrency.py` e seu teste: a prova de paralelismo deixou de ser o relógio (o teste antigo afirmava `speedup > 1,2` e falhou 4 de 5 rodadas com 8 laços ocupando 4 núcleos) e passou a ser `max_in_flight` (o máximo de chamadas em voo ao mesmo tempo: 1 no serial, a concorrência pedida no paralelo; nas rodadas paralelas nenhum trabalho termina antes de todos estarem em voo). O ganho de tempo é só um número reportado, sem assert de relógio.
215
+ - Benchmark depois das correções (mediana de 3, latência simulada de 1,0 s): swap serial 6,26 s contra paralelo 3,303 s (1,895x, saída idêntica); voice serial 9,742 s contra paralelo 3,793 s (2,568x, lock idêntico).
216
+
217
+ ### Formatos de anúncio
218
+ - `simplicio-video formats list|show|prompt` e o tool MCP `video.formats`. Biblioteca dos 50 formatos da pasta "Swipe File - 50 Formatos" do Drive (`src/simplicio_video/data/formats/formats.json`): cada um com a descrição, a estrutura, os limites, o objetivo e o link da pasta com o nome do arquivo de exemplo.
219
+ - `formats prompt <id> --copia <arquivo|->` monta o pedido para adaptar uma copy ao formato (instruções em `data/formats/instrucoes.md` + copy + formato). O CLI não chama modelo: quem adapta é o LLM.
220
+ - As descrições são estruturais, escritas a partir do nome do formato. Ficam com `verificado: false` até conferir o arquivo no Drive.
221
+ ### Ângulos de anúncio
222
+ - `simplicio-video list angles [--grupo problema|prova|desejo|decisao|estrategia] [--json]` e o tool MCP `video.list` com `what=angles`. Catálogo de 50 ângulos em `src/simplicio_video/data/angles/angles.json`: 10 por grupo, cada um com gatilho, quando usar, gancho de exemplo (só com marcadores de fato, nunca número ou promessa) e cuidado.
223
+ ### Trilha MoneyPrinterTurbo
224
+ - `simplicio-video moneyprinter clone|setup|serve|where|status` e a tool MCP `video.moneyprinter` (só `where` e `clone` na pasta padrão; `setup`, `serve`, `status` e `clone <pasta>` ficam no terminal). Checkout fixado do [MoneyPrinterTurbo](https://github.com/harry0703/MoneyPrinterTurbo) (MIT) em `tools.py`. Trilha externa de apoio, como toonflow e opencut: não substitui o `contract.yaml -> MP4`.
225
+ - `setup` cria um venv isolado em `MONEYPRINTER_DATA_DIR` (padrão `~/.simplicio-video/moneyprinter-data`), instala o `requirements.txt` do upstream (Python 3.11+), copia `config.example.toml` para `config.toml` sem preencher chave nenhuma e nunca sobrescreve um `config.toml` existente. `status` mostra só se o arquivo existe e quais chaves estão preenchidas.
226
+ - `serve` sobe a WebUI (porta 8501) e, com `--api`, a API (8080) em grupos de processos próprios. O upstream escuta em `0.0.0.0` por padrão na API, então o host é forçado para `127.0.0.1` por argumento (uvicorn em `app.asgi:app`, sem depender do `listen_host` do config); `--lan` é o único jeito de escutar em todas as interfaces.
227
+ - Revisão do PR #104: o `serve` ignora sinais repetidos durante a parada e repete a parada de cada servidor, trata SIGHUP (terminal fechado) como Ctrl+C e faz a varredura SIGKILL também do servidor que já saiu, para nenhum dos dois ficar órfão. Quando um servidor cai sozinho, diz qual foi em stderr e devolve código positivo.
228
+ - `serve --api` com `app.api_key` vazio avisa que a API fica sem login e recusa `CORS_ALLOWED_ORIGINS` com `*` nesse caso. Conferido no upstream (pino `4b7b965`): o CORS vem fechado por padrão, então outro site não lê a API; o risco que sobra é qualquer programa que alcance a porta usar as suas chaves.
229
+ - `status` lê o `config.toml` com `tomllib` (chaves pontuadas, entre aspas, tabelas inline, maiúsculas, `access_key_id`, `[[tabelas]]`), sem inventar nomes de dentro de um valor; o leitor por linha ficou de reserva para o Python 3.10 e TOML inválido. O `config.toml` criado pelo `setup` fica com modo 0600, o `setup` avisa quando o checkout não está no commit fixado, erros de arquivo e de processo viram `moneyprinter: ...` sem traceback, argumentos a mais em `clone`, `where` e `status` são recusados e o `setup` só exige Python 3.11 ao criar o venv.
230
+ ### Trilha Toonflow
231
+ - `simplicio-video toonflow clone|serve --lan|where` e a tool MCP `video.toonflow` (clone na pasta padrão e where; `serve` só no terminal). Checkout fixado do [Toonflow](https://github.com/HBAI-Ltd/Toonflow-app) (MIT) em `tools.py`; `serve` faz `bun install --frozen-lockfile`, `build:server` e `start:server`. O Toonflow escuta em `0.0.0.0:3000` sem login, então `serve` recusa sem `--lan`. Dados em `TOONFLOW_DATA_DIR` (padrão `~/.simplicio-video/toonflow-data`), fora do checkout.
232
+ - Conhecido, fora deste trecho: os wrappers MCP de `video.montage`, `video.opencut`, `video.clone` e `video.edit` falham sempre com `TypeError` (o `_capture` passa `log=` a funções que não o aceitam). Corrigir exige capturar a saída dos subprocessos, porque eles escrevem no canal stdio do MCP e alguns não terminam (`opencut dev`, `montage serve`). Fica para issue própria.
233
+
234
+ ### #31 Gate local
235
+ - `make check` roda o gate offline: checagens de ownership (`scripts/check_ownership.py`) e de TDD (`scripts/check_tdd.py`), pouso serializado (`scripts/land.sh`) e hooks em `.githooks/`. Sem GitHub Actions ([ADR-0005](docs/decisoes/ADR-0005-gate-sem-ci.md)).
236
+
237
+ ### #43 Pacote de operação
238
+ - `./install.sh`, `simplicio-video install`, `update`, `doctor` e `setup`, com `Dockerfile` e `compose.yaml` só para build local ([ADR-0017](docs/decisoes/ADR-0017-instalacao-atualizacao.md)).
239
+
240
+ ### #44 Docs
241
+ - Estrutura em `docs/` por tipo de documento: tutoriais, how-to, referência gerada, decisões (ADRs), host, plugins e factory.
242
+ - `docs/reference/` é gerado a partir do `--help` e das schemas; `make docs` falha se ficar desatualizado.
243
+ - `scripts/check_docs.py`: links relativos, âncoras, front matter, órfãos, pendências deixadas em texto e mermaid, offline.
244
+ - `docs/glossary.md` com os termos do projeto.
245
+ - Tutorial "Primeiro vídeo" e índices de tutoriais, how-to, decisões, host e plugins.
246
+
247
+ ### #46 Licenças
248
+ - `scripts/licenses.py` confere as licenças do ambiente contra a allowlist (MIT, Apache-2.0, BSD, ISC, PSF, MPL-2.0), aceita exceções justificadas e checa o isolamento de dependências AGPL ([docs/host/licenses.md](docs/host/licenses.md)). `web/` ainda não entra no scan.
249
+
250
+ ### #72 Saída em JSON
251
+ - `validate`, `run` e `render` aceitam `--json` com objeto estável e erros com código (`CONTRATO_NAO_ENCONTRADO`, `CONTRATO_INVALIDO`, `RENDER_FALHOU`, `FERRAMENTA_AUSENTE`).
252
+
253
+ ### #73 Versão e status
254
+ - `simplicio-video --version --json` e `simplicio-video status` (texto e `--json`), para o looping.
255
+
256
+ ### #74 Dados dentro do pacote
257
+ - Schemas, templates e motion do motor ficam em `src/simplicio_video/data/`, dentro do pacote.
258
+
259
+ ### #75 Sem Drive no motor
260
+ - O bloco `drive` saiu do contrato e do motor. Contrato com `drive` falha no `validate`; a entrega fica fora do motor.
261
+
262
+ ### #76 Marca como entrada do contrato
263
+ - Marca d'água e crédito final são entradas do contrato (`marca.dagua`, `marca.credito`), usadas por `render --preview`.
264
+
265
+ ### #77 Motor sem vendas
266
+ - O CLI do motor não expõe mais os subcomandos de venda (`prospect`, `venda`, `ugc`, `publish`). Os módulos continuam no repositório.