boost-skill-cli 1.0.394__tar.gz → 1.0.396__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 (622) hide show
  1. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.lighthouserc.json +1 -1
  2. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/PKG-INFO +1 -1
  3. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/_version.py +2 -2
  4. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_skill_cli.egg-info/PKG-INFO +1 -1
  5. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_skill_cli.egg-info/SOURCES.txt +3 -0
  6. boost_skill_cli-1.0.396/docs/roadmap/items/lighthouse-scored-a-page-nobody-is-served.md +64 -0
  7. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap.html +62 -1
  8. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/page_budget.py +25 -7
  9. boost_skill_cli-1.0.396/scripts/serve_docs.py +148 -0
  10. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/setup.cfg +1 -0
  11. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_page_budget.py +20 -0
  12. boost_skill_cli-1.0.396/tests/unit/test_serve_docs.py +197 -0
  13. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.gitattributes +0 -0
  14. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.gitignore +0 -0
  15. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.gitleaks.toml +0 -0
  16. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.htmlvalidate.json +0 -0
  17. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.lycheeignore +0 -0
  18. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.markdownlint-cli2.jsonc +0 -0
  19. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.pre-commit-config.yaml +0 -0
  20. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.stylelintrc.json +0 -0
  21. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.vale/styles/boost/Terminology.yml +0 -0
  22. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.vale/styles/config/vocabularies/boost/accept.txt +0 -0
  23. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.vale.ini +0 -0
  24. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/CLAUDE.md +0 -0
  25. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/CODE_OF_CONDUCT.md +0 -0
  26. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/CONTRIBUTING.md +0 -0
  27. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/LICENSE +0 -0
  28. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/MANIFEST.in +0 -0
  29. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/Makefile +0 -0
  30. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/README.md +0 -0
  31. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/SECURITY.md +0 -0
  32. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost +0 -0
  33. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/__init__.py +0 -0
  34. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/__main__.py +0 -0
  35. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/cli.py +0 -0
  36. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/cliparse.py +0 -0
  37. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/__init__.py +0 -0
  38. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/_common.py +0 -0
  39. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/bmad.py +0 -0
  40. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/configuration.py +0 -0
  41. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/discovery.py +0 -0
  42. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/hooks.py +0 -0
  43. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/info.py +0 -0
  44. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/intelligence.py +0 -0
  45. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/pkg.py +0 -0
  46. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/quality.py +0 -0
  47. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/run.py +0 -0
  48. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/safety.py +0 -0
  49. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/taps.py +0 -0
  50. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/team.py +0 -0
  51. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/__init__.py +0 -0
  52. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/adapters.py +0 -0
  53. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/agents.py +0 -0
  54. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/ai.py +0 -0
  55. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/capabilities.py +0 -0
  56. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/catalog.py +0 -0
  57. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/chat.py +0 -0
  58. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/claude_settings.py +0 -0
  59. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/complete.py +0 -0
  60. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/config.py +0 -0
  61. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/dense.py +0 -0
  62. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/ed25519.py +0 -0
  63. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/embed.py +0 -0
  64. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/faithfulness.py +0 -0
  65. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/frontmatter.py +0 -0
  66. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/gitutil.py +0 -0
  67. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/imperative.py +0 -0
  68. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/injectscan.py +0 -0
  69. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/installscan.py +0 -0
  70. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/integrity.py +0 -0
  71. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/journal.py +0 -0
  72. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/localembed.py +0 -0
  73. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/lockfile.py +0 -0
  74. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/logs.py +0 -0
  75. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/mcp.py +0 -0
  76. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/mcpdecl.py +0 -0
  77. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/mcphost.py +0 -0
  78. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/minisign.py +0 -0
  79. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/nethttp.py +0 -0
  80. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/output.py +0 -0
  81. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/paths.py +0 -0
  82. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/policy.py +0 -0
  83. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/projectlock.py +0 -0
  84. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/provenance.py +0 -0
  85. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/rag.py +0 -0
  86. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/registry.py +0 -0
  87. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/resolve.py +0 -0
  88. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/rules.py +0 -0
  89. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/scopes.py +0 -0
  90. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/secretscan.py +0 -0
  91. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/selfupdate.py +0 -0
  92. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/serve.py +0 -0
  93. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/stackprobe.py +0 -0
  94. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/staleness.py +0 -0
  95. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/store.py +0 -0
  96. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/trustaudit.py +0 -0
  97. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/typosquat.py +0 -0
  98. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/updatediff.py +0 -0
  99. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/util.py +0 -0
  100. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/workflows.py +0 -0
  101. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/data/registries.json +0 -0
  102. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/errors.py +0 -0
  103. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/spin.py +0 -0
  104. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
  105. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_skill_cli.egg-info/entry_points.txt +0 -0
  106. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_skill_cli.egg-info/requires.txt +0 -0
  107. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_skill_cli.egg-info/top_level.txt +0 -0
  108. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/codecov.yml +0 -0
  109. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/.claude/settings.local.json +0 -0
  110. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/DEBUGGING.md +0 -0
  111. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/adapters.html +0 -0
  112. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/architecture/README.md +0 -0
  113. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/architecture/c4-components-core.md +0 -0
  114. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/architecture/c4-containers.md +0 -0
  115. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/architecture/c4-context.md +0 -0
  116. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/architecture/c4-dynamic-install.md +0 -0
  117. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/distill.gif +0 -0
  118. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/doctor.gif +0 -0
  119. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/explain.gif +0 -0
  120. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/hooks.gif +0 -0
  121. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/install.gif +0 -0
  122. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/pulse.gif +0 -0
  123. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/search.gif +0 -0
  124. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/tap.gif +0 -0
  125. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/distill.tape +0 -0
  126. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/doctor.tape +0 -0
  127. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/explain.tape +0 -0
  128. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/hooks.tape +0 -0
  129. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/install.tape +0 -0
  130. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/pulse.tape +0 -0
  131. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/search.tape +0 -0
  132. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/tap.tape +0 -0
  133. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel.html +0 -0
  134. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/chat.html +0 -0
  135. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/commands.html +0 -0
  136. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/demo-index.json +0 -0
  137. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/demo.gif +0 -0
  138. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/demo.html +0 -0
  139. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/demo.tape +0 -0
  140. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/design-roadmap.html +0 -0
  141. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/eval-latest.json +0 -0
  142. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/eval.html +0 -0
  143. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/index.html +0 -0
  144. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/mcp-hub.html +0 -0
  145. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/rag-architecture.md +0 -0
  146. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D01.md +0 -0
  147. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D02.md +0 -0
  148. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D03.md +0 -0
  149. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D04.md +0 -0
  150. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D05.md +0 -0
  151. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D06.md +0 -0
  152. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D07.md +0 -0
  153. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D08.md +0 -0
  154. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D09.md +0 -0
  155. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D10.md +0 -0
  156. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D11.md +0 -0
  157. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D12.md +0 -0
  158. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D13.md +0 -0
  159. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D14.md +0 -0
  160. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D15.md +0 -0
  161. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D16.md +0 -0
  162. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D17.md +0 -0
  163. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D18.md +0 -0
  164. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D19.md +0 -0
  165. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D20.md +0 -0
  166. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D21.md +0 -0
  167. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D22.md +0 -0
  168. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D23.md +0 -0
  169. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D24.md +0 -0
  170. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D25.md +0 -0
  171. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D26.md +0 -0
  172. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/a11y-sweep-flakes-on-color-contrast.md +0 -0
  173. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
  174. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/actionlint-skips-shellcheck-silently.md +0 -0
  175. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/adapter-conformance-langgraph-leg-never-ran.md +0 -0
  176. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/agents-field-records-the-request-not-the-links.md +0 -0
  177. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/ai-bridge-silent-failure-logging.md +0 -0
  178. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/ambiguous-tap-short-name-resolution.md +0 -0
  179. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
  180. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
  181. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
  182. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/bm25-index-is-one-json-blob.md +0 -0
  183. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/boost-run-live-agents.md +0 -0
  184. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
  185. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
  186. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/browse-crashes-selecting-a-rule-or-workflow.md +0 -0
  187. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
  188. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/cache-the-catalog-entry-set-across-rag-queries.md +0 -0
  189. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
  190. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/chat-cites-sources-by-a-number-it-never-prints.md +0 -0
  191. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/chat-command-grounded-conversational-search.md +0 -0
  192. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/ci-job-timeout-minutes.md +0 -0
  193. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/ci-summary-step-fails-itself.md +0 -0
  194. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/ci-time-is-now-runner-queueing.md +0 -0
  195. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/clean-env-install-smoke-pip-and-pipx.md +0 -0
  196. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/code-scanning-rule-can-be-restored.md +0 -0
  197. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/codeql-job-rename-stranded-merge-protection.md +0 -0
  198. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/command-carousel-page.md +0 -0
  199. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/command-reference-docs-site.md +0 -0
  200. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/completions-complete-only-command-names.md +0 -0
  201. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/complexity-and-dead-code-radar-xenon-vulture.md +0 -0
  202. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/consolidate-skill-staleness-drift-logic-into-cor.md +0 -0
  203. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
  204. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
  205. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/crash-listing-branch-untested.md +0 -0
  206. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/crash-recorder-error-paths-core-logs-py.md +0 -0
  207. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/demo-cannot-open-its-own-pr.md +0 -0
  208. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/demo-gif-workflow-has-never-succeeded.md +0 -0
  209. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/dense-search-fallback-and-stale-tap-pruning.md +0 -0
  210. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/dependabot-missing-pip-ecosystem.md +0 -0
  211. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/dependabot-regeneration-drops-platform-pins.md +0 -0
  212. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/dependabot-root-pip-entry-duplicates-requirements.md +0 -0
  213. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
  214. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/docsite-chrome-and-content-audit.md +0 -0
  215. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
  216. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
  217. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/end-of-options-guard-on-git-commands.md +0 -0
  218. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/eval-corpus-cannot-see-real-retrieval.md +0 -0
  219. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/eval-corpus-is-96x-smaller-than-a-real-install.md +0 -0
  220. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/eval-corpus-is-one-strangers-repo.md +0 -0
  221. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/eval-corpus-pins-have-no-refresh-path.md +0 -0
  222. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/eval-corpus-was-not-actually-pinned.md +0 -0
  223. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/eval-deduped-ranked-lists-by-name.md +0 -0
  224. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
  225. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/extract-mcp-http-servers-out-of-configuration-py.md +0 -0
  226. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
  227. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/fix-self-update-version-detection-dead-branch.md +0 -0
  228. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
  229. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
  230. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
  231. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
  232. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
  233. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/gemini-cli-agent-target.md +0 -0
  234. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/github-community-health-files.md +0 -0
  235. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/github-pages-deploy-is-broken-every-push.md +0 -0
  236. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/golden-set-grades-by-name-not-by-skill.md +0 -0
  237. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
  238. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
  239. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/html-validation-html-validate.md +0 -0
  240. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/info-rejects-the-qualified-name-it-recommends.md +0 -0
  241. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/install-docs-never-mentioned-upgrading.md +0 -0
  242. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/install-from-path-bypasses-policy-and-pin-checks.md +0 -0
  243. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/install-resolves-skill-dependencies.md +0 -0
  244. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
  245. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/installed-skill-trust-audit.md +0 -0
  246. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
  247. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/internal-architecture-diagrams.md +0 -0
  248. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
  249. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/journal-rotation-race-and-handle-leak.md +0 -0
  250. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/keyless-dense-tier-local-static-embeddings.md +0 -0
  251. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/keyless-semantic-search-for-everyone.md +0 -0
  252. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/langchain-integration-explainer-page.md +0 -0
  253. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/langchain-langgraph-langsmith-integration.md +0 -0
  254. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
  255. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/license-compliance-scanning.md +0 -0
  256. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
  257. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/lint-tap-misscopes-rule-workflow-entries.md +0 -0
  258. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
  259. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
  260. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/lock-invariant-cannot-parse-extras-pins.md +0 -0
  261. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
  262. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
  263. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/lowest-version-resolution-uv-resolution-lowest-d.md +0 -0
  264. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/main-has-no-branch-protection.md +0 -0
  265. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/main-ruleset-ref-pattern-has-literal-quotes.md +0 -0
  266. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/make-lint-masks-actionlint-failures.md +0 -0
  267. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
  268. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
  269. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/markdownlint-lints-the-fuzz-corpus.md +0 -0
  270. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-aware-skills.md +0 -0
  271. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-check-skills-before-starting-a-task.md +0 -0
  272. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
  273. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-install-skips-the-injection-scan.md +0 -0
  274. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
  275. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-one-benefit-nameable-task.md +0 -0
  276. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
  277. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-search-before-reinventing.md +0 -0
  278. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-search-cost-was-understated.md +0 -0
  279. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-servers-ignore-install-scope.md +0 -0
  280. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
  281. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
  282. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/merge-queue-would-deadlock-most-required-checks.md +0 -0
  283. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/merged-loop-branches-are-never-pruned.md +0 -0
  284. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
  285. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mutation-gate-was-the-whole-critical-path.md +0 -0
  286. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
  287. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
  288. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
  289. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mutation-shard-floor-is-one-file.md +0 -0
  290. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mypy-strict-mode-for-commands.md +0 -0
  291. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/near-duplicate-items-eat-the-result-slots.md +0 -0
  292. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/negative-limit-inverts-log-pulse-output.md +0 -0
  293. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/onboard-overwrites-generated-files-without-confirm.md +0 -0
  294. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
  295. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/one-commit-can-cut-two-releases.md +0 -0
  296. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
  297. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
  298. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
  299. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/path-traversal-unsanitized-rule-workflow-name.md +0 -0
  300. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/pep585-604-modernization-sweep.md +0 -0
  301. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
  302. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/pin-the-lint-toolchain.md +0 -0
  303. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/post-deploy-always-defeated-by-skipped-setup.md +0 -0
  304. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
  305. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/pre-release-python-canary-3-14t-free-threaded.md +0 -0
  306. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/prerequisites-and-semantic-search-setup.md +0 -0
  307. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/project-scope-across-every-command.md +0 -0
  308. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/project-scope-symlink-escape-on-write.md +0 -0
  309. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/promote-nav-footer-into-the-shared-style-system.md +0 -0
  310. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
  311. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/property-based-tests-hypothesis-on-the-parsers.md +0 -0
  312. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
  313. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/prune-ignored-dirs-during-scan-dir-walk.md +0 -0
  314. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/publish-gate-ignores-pip-audit-and-metadata.md +0 -0
  315. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/publish-trigger-was-reachable-from-a-fork.md +0 -0
  316. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/pytest-tmpdir-cve-blocked-by-py39-floor.md +0 -0
  317. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/python-floor-moves-to-312.md +0 -0
  318. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
  319. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
  320. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
  321. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
  322. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/rel-time-tests-race-the-wall-clock.md +0 -0
  323. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/release-verifies-the-wrong-commit.md +0 -0
  324. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/required-checks-can-declare-a-check-that-deadlocks-prs.md +0 -0
  325. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/required-checks-config-drift.md +0 -0
  326. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/resolve-vendored-duplicate-copies.md +0 -0
  327. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
  328. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
  329. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/roadmap-html-goes-stale-on-every-rebase.md +0 -0
  330. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/roadmap-page-weight-grows-without-bound.md +0 -0
  331. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/roadmap-perf-budget-has-no-local-guard.md +0 -0
  332. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
  333. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/ruff-016-widens-the-default-rule-set.md +0 -0
  334. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
  335. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
  336. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
  337. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
  338. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/sbom-declares-the-wrong-version.md +0 -0
  339. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
  340. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/sbom-release-event-never-fires.md +0 -0
  341. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
  342. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/scheduled-toolchain-lock-regeneration.md +0 -0
  343. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/scorecard-findings-triage.md +0 -0
  344. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
  345. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/secret-and-pii-scanning-of-installed-skills.md +0 -0
  346. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
  347. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/security-linting-bandit-via-ruff-s-rules.md +0 -0
  348. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/self-update-broken-for-pip-pipx-installs.md +0 -0
  349. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/serve-py-traversal-guards-untested.md +0 -0
  350. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/shift-left-gate-pre-commit-pre-commit-ci.md +0 -0
  351. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
  352. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
  353. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
  354. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/startup-and-import-time-budget-x-importtime.md +0 -0
  355. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/stop-re-serializing-entry-meta-on-every-search.md +0 -0
  356. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/structured-json-log-output-mode.md +0 -0
  357. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
  358. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/surface-every-docs-page-from-the-guide.md +0 -0
  359. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/sync-deletes-unowned-broken-symlinks.md +0 -0
  360. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/sync-relinks-into-every-agent-ignoring-scope.md +0 -0
  361. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
  362. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
  363. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/typo-detection-codespell.md +0 -0
  364. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
  365. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/unify-tilde-two-copies-have-a-boundary-bug.md +0 -0
  366. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/uninstall-has-no-confirmation-prompt.md +0 -0
  367. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
  368. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/update-diff-before-apply.md +0 -0
  369. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
  370. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/update-reinstall-widens-agent-scope.md +0 -0
  371. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
  372. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/widen-the-ruff-rule-surface-b-sim-c4-perf-ruf.md +0 -0
  373. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
  374. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/wire-bdd-suite-into-ci.md +0 -0
  375. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
  376. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
  377. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
  378. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/workspace-scope-install.md +0 -0
  379. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/zip-strict-audit.md +0 -0
  380. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/zizmor-pin-is-a-yanked-release.md +0 -0
  381. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/eslint.config.mjs +0 -0
  382. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/README.md +0 -0
  383. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/__init__.py +0 -0
  384. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/baseline.json +0 -0
  385. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/faithfulness.py +0 -0
  386. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/golden_set.json +0 -0
  387. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/make_corpus.py +0 -0
  388. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/make_golden.py +0 -0
  389. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/metrics.py +0 -0
  390. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/run_evals.py +0 -0
  391. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/examples/README.md +0 -0
  392. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/examples/adapt-demo.sh +0 -0
  393. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/examples/boost-run-prototype.sh +0 -0
  394. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/index.html +0 -0
  395. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/noxfile.py +0 -0
  396. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/pyproject.toml +0 -0
  397. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/coverage-tools.in +0 -0
  398. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/coverage-tools.txt +0 -0
  399. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/lint-tools.in +0 -0
  400. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/lint-tools.txt +0 -0
  401. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/mutation-tools.in +0 -0
  402. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/mutation-tools.txt +0 -0
  403. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/platform-pins.lock +0 -0
  404. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/release-tools.in +0 -0
  405. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/release-tools.txt +0 -0
  406. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/test-tools.in +0 -0
  407. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/test-tools.txt +0 -0
  408. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/a11y_check.py +0 -0
  409. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/bench_cli.sh +0 -0
  410. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/build_command_reference.py +0 -0
  411. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/build_demo_index.py +0 -0
  412. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/build_registries.py +0 -0
  413. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/build_roadmap.py +0 -0
  414. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/build_scale_corpus.py +0 -0
  415. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/check_anchors.py +0 -0
  416. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/check_licenses.py +0 -0
  417. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/check_required_checks.py +0 -0
  418. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/ensure_eval_corpus.sh +0 -0
  419. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/eval_corpus.py +0 -0
  420. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/eval_explain.py +0 -0
  421. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/eval_gate.py +0 -0
  422. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/eval_recommend.py +0 -0
  423. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/eval_retrieval.py +0 -0
  424. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/eval_stats_summary.py +0 -0
  425. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/import_budget.py +0 -0
  426. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/lock_toolchain.py +0 -0
  427. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/mutation_gate.py +0 -0
  428. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/mutation_shards.py +0 -0
  429. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/mutation_weights.json +0 -0
  430. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/perf_gate.py +0 -0
  431. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/post_deploy_smoke.py +0 -0
  432. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/publish_eval_json.py +0 -0
  433. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/release_guard.py +0 -0
  434. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/release_preflight.py +0 -0
  435. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/sonar-project.properties +0 -0
  436. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/style/README.md +0 -0
  437. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/style/boost.css +0 -0
  438. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/style/boost.js +0 -0
  439. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/style/demo.html +0 -0
  440. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/adapt.feature +0 -0
  441. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/browse.feature +0 -0
  442. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/count.feature +0 -0
  443. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/discover.feature +0 -0
  444. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/doctor.feature +0 -0
  445. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/environment.py +0 -0
  446. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/explain.feature +0 -0
  447. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/index.feature +0 -0
  448. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/install.feature +0 -0
  449. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/list.feature +0 -0
  450. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/mcp.feature +0 -0
  451. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/search.feature +0 -0
  452. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/steps/cli_steps.py +0 -0
  453. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/steps/discovery_steps.py +0 -0
  454. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/steps/mcp_steps.py +0 -0
  455. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/steps/quality_steps.py +0 -0
  456. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/conftest.py +0 -0
  457. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/eval/baseline.json +0 -0
  458. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/eval/explain.jsonl +0 -0
  459. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/eval/golden-natural.jsonl +0 -0
  460. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/eval/golden.jsonl +0 -0
  461. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/eval/recommend.jsonl +0 -0
  462. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/eval/taps-scale.txt +0 -0
  463. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/eval/taps.txt +0 -0
  464. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_capabilities_policy.py +0 -0
  465. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_adapt.py +0 -0
  466. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_bmad.py +0 -0
  467. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_chat.py +0 -0
  468. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_configuration.py +0 -0
  469. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_discovery.py +0 -0
  470. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_hooks.py +0 -0
  471. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_info.py +0 -0
  472. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_intelligence.py +0 -0
  473. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_pkg.py +0 -0
  474. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_quality.py +0 -0
  475. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_taps.py +0 -0
  476. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_team.py +0 -0
  477. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_everyday_loop.py +0 -0
  478. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_integrity_enforce.py +0 -0
  479. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_property_parsers.py +0 -0
  480. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_run.py +0 -0
  481. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_tap_signing.py +0 -0
  482. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_workspace_scope.py +0 -0
  483. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/README.md +0 -0
  484. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/01-typical.md +0 -0
  485. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/02-lossy-version.md +0 -0
  486. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/03-lossy-numbers.md +0 -0
  487. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/04-lists.md +0 -0
  488. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/05-nested.md +0 -0
  489. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/06-empty-block.md +0 -0
  490. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/07-unterminated.md +0 -0
  491. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/08-none.md +0 -0
  492. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/09-unbalanced-quote.md +0 -0
  493. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/10-keywords.md +0 -0
  494. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/11-crlf.md +0 -0
  495. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/12-bom.md +0 -0
  496. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/01-shorthand.txt +0 -0
  497. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/02-https.txt +0 -0
  498. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/03-ssh.txt +0 -0
  499. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/04-traversal.txt +0 -0
  500. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/05-empty.txt +0 -0
  501. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/06-space.txt +0 -0
  502. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/07-slash.txt +0 -0
  503. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/08-bare-host.txt +0 -0
  504. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/fuzz_frontmatter.py +0 -0
  505. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/fuzz_registry.py +0 -0
  506. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/make_fixture.py +0 -0
  507. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/perf/test_benchmarks.py +0 -0
  508. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/smoke.sh +0 -0
  509. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_a11y_check.py +0 -0
  510. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_adapters.py +0 -0
  511. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_adapters_multi.py +0 -0
  512. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_adapters_runner.py +0 -0
  513. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_agents.py +0 -0
  514. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_ai.py +0 -0
  515. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_capabilities.py +0 -0
  516. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_catalog.py +0 -0
  517. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_chat.py +0 -0
  518. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_check_anchors.py +0 -0
  519. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_check_licenses.py +0 -0
  520. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_claude_settings.py +0 -0
  521. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_cliparse.py +0 -0
  522. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_codeql_analysis_key.py +0 -0
  523. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_command_reference_fresh.py +0 -0
  524. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_community_health_files.py +0 -0
  525. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_complete.py +0 -0
  526. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_config.py +0 -0
  527. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_content_dedupe.py +0 -0
  528. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_dedup_trust.py +0 -0
  529. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_demo_index.py +0 -0
  530. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_dense.py +0 -0
  531. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_dense_fallback.py +0 -0
  532. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_dense_fix_hint.py +0 -0
  533. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_dense_shards.py +0 -0
  534. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_dense_status.py +0 -0
  535. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_dependabot_config.py +0 -0
  536. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_docs_pages_linked.py +0 -0
  537. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_docsite_chrome.py +0 -0
  538. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_ed25519.py +0 -0
  539. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_embed.py +0 -0
  540. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_embed_local.py +0 -0
  541. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_entry_key.py +0 -0
  542. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_errors_and_cli_table.py +0 -0
  543. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_eval_baseline.py +0 -0
  544. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_eval_corpus.py +0 -0
  545. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_eval_faithfulness.py +0 -0
  546. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_eval_gate.py +0 -0
  547. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_eval_grading.py +0 -0
  548. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_eval_metrics.py +0 -0
  549. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_eval_stats_summary.py +0 -0
  550. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_faithfulness.py +0 -0
  551. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_frontmatter.py +0 -0
  552. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_fuzz_targets.py +0 -0
  553. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_gitleaks_config.py +0 -0
  554. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_gitutil.py +0 -0
  555. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_imperative.py +0 -0
  556. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_import_budget.py +0 -0
  557. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_injectscan.py +0 -0
  558. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_installscan.py +0 -0
  559. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_integrity.py +0 -0
  560. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_journal.py +0 -0
  561. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_localembed.py +0 -0
  562. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_localembed_e2e.py +0 -0
  563. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_lockfile.py +0 -0
  564. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_logs.py +0 -0
  565. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_marketing_counts.py +0 -0
  566. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mcp.py +0 -0
  567. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mcp_install_scan.py +0 -0
  568. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mcpdecl.py +0 -0
  569. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mcphost.py +0 -0
  570. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_minisign.py +0 -0
  571. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mutation_hardening.py +0 -0
  572. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mutation_shards.py +0 -0
  573. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mutation_subfile_shards.py +0 -0
  574. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mutmut_source_paths.py +0 -0
  575. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_nethttp.py +0 -0
  576. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_output.py +0 -0
  577. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_paths.py +0 -0
  578. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_perf_gate.py +0 -0
  579. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_pkg_confusions.py +0 -0
  580. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_pkg_injection.py +0 -0
  581. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_pkg_secrets.py +0 -0
  582. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_platform_pins.py +0 -0
  583. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_policy.py +0 -0
  584. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_post_deploy_smoke.py +0 -0
  585. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_project_mcp_sidecar.py +0 -0
  586. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_projectlock.py +0 -0
  587. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_provenance.py +0 -0
  588. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_rag.py +0 -0
  589. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_rag_fusion.py +0 -0
  590. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_registries_fresh.py +0 -0
  591. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_registry.py +0 -0
  592. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_registry_categories.py +0 -0
  593. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_release_guard.py +0 -0
  594. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_release_preflight.py +0 -0
  595. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_required_checks.py +0 -0
  596. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_resolve.py +0 -0
  597. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_roadmap_fresh.py +0 -0
  598. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_rules.py +0 -0
  599. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_scale_corpus.py +0 -0
  600. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_scopes.py +0 -0
  601. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_secretscan.py +0 -0
  602. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_selfupdate.py +0 -0
  603. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_serve.py +0 -0
  604. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_spin.py +0 -0
  605. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_stackprobe.py +0 -0
  606. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_staleness.py +0 -0
  607. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_store.py +0 -0
  608. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_token_parity.py +0 -0
  609. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_toolchain_lock.py +0 -0
  610. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_trustaudit.py +0 -0
  611. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_typosquat.py +0 -0
  612. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_updatediff.py +0 -0
  613. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_util.py +0 -0
  614. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_version.py +0 -0
  615. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_workflow_concurrency.py +0 -0
  616. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_workflow_timeouts.py +0 -0
  617. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_workflows.py +0 -0
  618. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/visual/a11y_check.mjs +0 -0
  619. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/visual/console_check.mjs +0 -0
  620. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/visual/package-lock.json +0 -0
  621. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/visual/package.json +0 -0
  622. {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/visual/visual_check.mjs +0 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "ci": {
3
3
  "collect": {
4
- "startServerCommand": "python3 -m http.server 8099 --bind 127.0.0.1",
4
+ "startServerCommand": "python3 scripts/serve_docs.py --port 8099 --bind 127.0.0.1",
5
5
  "startServerReadyPattern": "Serving HTTP",
6
6
  "url": [
7
7
  "http://127.0.0.1:8099/docs/index.html",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.394
3
+ Version: 1.0.396
4
4
  Summary: boost — Homebrew for AI coding skills
5
5
  Author: Jonathan Reyes
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '1.0.394'
22
- __version_tuple__ = version_tuple = (1, 0, 394)
21
+ __version__ = version = '1.0.396'
22
+ __version_tuple__ = version_tuple = (1, 0, 396)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boost-skill-cli
3
- Version: 1.0.394
3
+ Version: 1.0.396
4
4
  Summary: boost — Homebrew for AI coding skills
5
5
  Author: Jonathan Reyes
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -253,6 +253,7 @@ docs/roadmap/items/langchain-langgraph-langsmith-integration.md
253
253
  docs/roadmap/items/layering-guard-import-linter.md
254
254
  docs/roadmap/items/license-compliance-scanning.md
255
255
  docs/roadmap/items/lighthouse-ci-on-the-pages-site.md
256
+ docs/roadmap/items/lighthouse-scored-a-page-nobody-is-served.md
256
257
  docs/roadmap/items/lint-tap-misscopes-rule-workflow-entries.md
257
258
  docs/roadmap/items/list-rules-and-workflows.md
258
259
  docs/roadmap/items/localize-the-stored-bm25-snippet.md
@@ -428,6 +429,7 @@ scripts/post_deploy_smoke.py
428
429
  scripts/publish_eval_json.py
429
430
  scripts/release_guard.py
430
431
  scripts/release_preflight.py
432
+ scripts/serve_docs.py
431
433
  style/README.md
432
434
  style/boost.css
433
435
  style/boost.js
@@ -597,6 +599,7 @@ tests/unit/test_scopes.py
597
599
  tests/unit/test_secretscan.py
598
600
  tests/unit/test_selfupdate.py
599
601
  tests/unit/test_serve.py
602
+ tests/unit/test_serve_docs.py
600
603
  tests/unit/test_spin.py
601
604
  tests/unit/test_stackprobe.py
602
605
  tests/unit/test_staleness.py
@@ -0,0 +1,64 @@
1
+ ---
2
+ id: lighthouse-scored-a-page-nobody-is-served
3
+ board: code
4
+ section: docsite
5
+ status: shipped
6
+ category: Docs · Performance
7
+ complexity: S
8
+ impact: High
9
+ wow: 5
10
+ note: the page was never the slow part — the harness sent 3.27x the bytes Pages sends
11
+ order: 97
12
+ owner: fix/lighthouse-serves-uncompressed
13
+ pr: 455
14
+ title: The performance gate was measuring a page nobody is served
15
+ ---
16
+ <b>The board's Lighthouse score was decided by a missing HTTP header.</b> The gate serves the docs
17
+ with <code>python3 -m http.server</code>, which has never sent <code>Content-Encoding</code>. GitHub
18
+ Pages answers <code>content-encoding: gzip</code> for the same URL &mdash; checked against the live
19
+ site. So every performance number this project has ever recorded for
20
+ <code>roadmap.html</code> was measured on a document <b>3.27&times;</b> larger than the one a visitor
21
+ receives.
22
+
23
+ <b>The failing run says so itself.</b> In its own artifact,
24
+ <code>uses-text-compression</code> scores <b>0</b> with an estimated saving of 404&nbsp;KiB, and
25
+ <code>transferSize</code> 567,874 sits against <code>resourceSize</code> 567,685 &mdash; the bytes on
26
+ the wire are the bytes on disk. Lighthouse throttles to <b>1,474.56&nbsp;kbps</b>, where 566&nbsp;KB
27
+ is <b>3.08&nbsp;s</b> of download; the observed FCP was <b>3.63&nbsp;s</b>. There is nothing left
28
+ over to explain.
29
+
30
+ <b>And the score decomposes exactly.</b> FCP&nbsp;3,638&nbsp;ms scores 0.31 (&times;10) &middot;
31
+ SI&nbsp;3,638&nbsp;ms 0.86 (&times;10) &middot; LCP&nbsp;3,858&nbsp;ms 0.53 (&times;25) &middot;
32
+ TBT&nbsp;100&nbsp;ms 0.98 (&times;30) &middot; CLS&nbsp;0 1.00 (&times;25), which totals
33
+ <b>79.35 &rarr; 0.79</b>, the reported figure to the digit. The entire 21-point deficit is FCP and
34
+ LCP. Both are transfer-bound. Neither is about the page.
35
+
36
+ <b>This is why two rounds of optimisation moved nothing.</b>
37
+ [[roadmap-perf-budget-has-no-local-guard]] records collapsing card bodies into
38
+ <code>&lt;details&gt;</code>, which cut laid-out body text 33% and moved the score by <b>0.00</b>,
39
+ and trimming 3,066 characters of prose, which also moved it by <b>0.00</b>. Both changed
40
+ <i>layout</i> work while the score was being decided by <i>transfer</i>. <code>content-visibility:
41
+ auto</code> bought 0.01 &mdash; about all that was on the table, because TBT already scored 0.98.
42
+ The conclusions drawn from those experiments were sound about what they measured and wrong about
43
+ what they implied: the floor was lowered 0.85&nbsp;&rarr;&nbsp;0.80 and the raise back was declared
44
+ "gated on making the page genuinely faster", when the page was never the slow part.
45
+
46
+ <b>It also names the cheap local proxy that card called not obvious.</b> It is markup bytes &mdash;
47
+ the dimension <code>scripts/page_budget.py</code> already measures, shipped by the same PR that
48
+ declared the budget non-predictive. Compression is a near-constant factor here (roadmap.html 3.27&times;,
49
+ index.html 3.38&times;, boost.css 2.99&times;), so bytes on disk track bytes on the wire, and bytes on
50
+ the wire are what FCP is spending.
51
+
52
+ <b>What shipped.</b> <code>scripts/serve_docs.py</code> &mdash; a stdlib static server that
53
+ compresses exactly what Pages compresses (text, JS, JSON, XML, SVG; never images or fonts) and only
54
+ when the client asks, so the raw path stays reachable. On the audited page that is
55
+ <b>597,782&nbsp;&rarr;&nbsp;184,126&nbsp;B</b>, or <b>3.24&nbsp;s&nbsp;&rarr;&nbsp;1.00&nbsp;s</b> of
56
+ download on Lighthouse's link. Nothing else about the harness changed &mdash; not even HTTP/1.1
57
+ keep-alive, which was left off on purpose so the score move has one cause and not two.
58
+
59
+ <b>What it deliberately is not.</b> A way to make the number look better. It is the opposite: the
60
+ number now describes bytes someone is actually sent, so a floor raised against it means something.
61
+ Twenty-two unit tests pin the behaviour, including that HEAD and GET agree on
62
+ <code>Content-Length</code>, that an image is left alone, and that the rc's
63
+ <code>startServerReadyPattern</code> still matches the banner &mdash; a drift there does not fail the
64
+ job, it hangs it until timeout.
@@ -125,7 +125,7 @@
125
125
  <div class="stat"><b>16</b><span>Shipped</span></div>
126
126
  <div class="stat"><b>1</b><span>Next up</span></div>
127
127
  <div class="stat"><b>7</b><span>Planned</span></div>
128
- <div class="stat"><b>209</b><span>Loop finds</span></div>
128
+ <div class="stat"><b>210</b><span>Loop finds</span></div>
129
129
  <!-- /ROADMAP:stats -->
130
130
  </div>
131
131
  </section>
@@ -7152,6 +7152,67 @@ value is that its code runs.</p>
7152
7152
  <span class="m">the eval.html genre, pointed at the LangChain stack — and it can only document what has shipped</span>
7153
7153
  </div>
7154
7154
  </article>
7155
+
7156
+ <article class="cap rcard" id="lighthouse-scored-a-page-nobody-is-served">
7157
+ <div class="head"><span class="pill shipped">Shipped</span><span class="cat">Docs · Performance</span></div>
7158
+ <h3>The performance gate was measuring a page nobody is served</h3>
7159
+ <details class="cardbody"><summary>Write-up</summary>
7160
+ <p><b>The board's Lighthouse score was decided by a missing HTTP header.</b> The gate serves the docs
7161
+ with <code>python3 -m http.server</code>, which has never sent <code>Content-Encoding</code>. GitHub
7162
+ Pages answers <code>content-encoding: gzip</code> for the same URL &mdash; checked against the live
7163
+ site. So every performance number this project has ever recorded for
7164
+ <code>roadmap.html</code> was measured on a document <b>3.27&times;</b> larger than the one a visitor
7165
+ receives.
7166
+
7167
+ <b>The failing run says so itself.</b> In its own artifact,
7168
+ <code>uses-text-compression</code> scores <b>0</b> with an estimated saving of 404&nbsp;KiB, and
7169
+ <code>transferSize</code> 567,874 sits against <code>resourceSize</code> 567,685 &mdash; the bytes on
7170
+ the wire are the bytes on disk. Lighthouse throttles to <b>1,474.56&nbsp;kbps</b>, where 566&nbsp;KB
7171
+ is <b>3.08&nbsp;s</b> of download; the observed FCP was <b>3.63&nbsp;s</b>. There is nothing left
7172
+ over to explain.
7173
+
7174
+ <b>And the score decomposes exactly.</b> FCP&nbsp;3,638&nbsp;ms scores 0.31 (&times;10) &middot;
7175
+ SI&nbsp;3,638&nbsp;ms 0.86 (&times;10) &middot; LCP&nbsp;3,858&nbsp;ms 0.53 (&times;25) &middot;
7176
+ TBT&nbsp;100&nbsp;ms 0.98 (&times;30) &middot; CLS&nbsp;0 1.00 (&times;25), which totals
7177
+ <b>79.35 &rarr; 0.79</b>, the reported figure to the digit. The entire 21-point deficit is FCP and
7178
+ LCP. Both are transfer-bound. Neither is about the page.
7179
+
7180
+ <b>This is why two rounds of optimisation moved nothing.</b>
7181
+ [[roadmap-perf-budget-has-no-local-guard]] records collapsing card bodies into
7182
+ <code>&lt;details&gt;</code>, which cut laid-out body text 33% and moved the score by <b>0.00</b>,
7183
+ and trimming 3,066 characters of prose, which also moved it by <b>0.00</b>. Both changed
7184
+ <i>layout</i> work while the score was being decided by <i>transfer</i>. <code>content-visibility:
7185
+ auto</code> bought 0.01 &mdash; about all that was on the table, because TBT already scored 0.98.
7186
+ The conclusions drawn from those experiments were sound about what they measured and wrong about
7187
+ what they implied: the floor was lowered 0.85&nbsp;&rarr;&nbsp;0.80 and the raise back was declared
7188
+ "gated on making the page genuinely faster", when the page was never the slow part.
7189
+
7190
+ <b>It also names the cheap local proxy that card called not obvious.</b> It is markup bytes &mdash;
7191
+ the dimension <code>scripts/page_budget.py</code> already measures, shipped by the same PR that
7192
+ declared the budget non-predictive. Compression is a near-constant factor here (roadmap.html 3.27&times;,
7193
+ index.html 3.38&times;, boost.css 2.99&times;), so bytes on disk track bytes on the wire, and bytes on
7194
+ the wire are what FCP is spending.
7195
+
7196
+ <b>What shipped.</b> <code>scripts/serve_docs.py</code> &mdash; a stdlib static server that
7197
+ compresses exactly what Pages compresses (text, JS, JSON, XML, SVG; never images or fonts) and only
7198
+ when the client asks, so the raw path stays reachable. On the audited page that is
7199
+ <b>597,782&nbsp;&rarr;&nbsp;184,126&nbsp;B</b>, or <b>3.24&nbsp;s&nbsp;&rarr;&nbsp;1.00&nbsp;s</b> of
7200
+ download on Lighthouse's link. Nothing else about the harness changed &mdash; not even HTTP/1.1
7201
+ keep-alive, which was left off on purpose so the score move has one cause and not two.
7202
+
7203
+ <b>What it deliberately is not.</b> A way to make the number look better. It is the opposite: the
7204
+ number now describes bytes someone is actually sent, so a floor raised against it means something.
7205
+ Twenty-two unit tests pin the behaviour, including that HEAD and GET agree on
7206
+ <code>Content-Length</code>, that an image is left alone, and that the rc's
7207
+ <code>startServerReadyPattern</code> still matches the banner &mdash; a drift there does not fail the
7208
+ job, it hangs it until timeout.</p></details>
7209
+ <div class="meta">
7210
+ <span class="m">Complexity <b>S</b></span>
7211
+ <span class="m hi">Impact <b>High</b></span>
7212
+ <span class="m">Wow <b class="wow">★★★★★</b></span>
7213
+ <span class="m">the page was never the slow part — the harness sent 3.27x the bytes Pages sends</span>
7214
+ </div>
7215
+ </article>
7155
7216
  <!-- /ROADMAP:cards -->
7156
7217
 
7157
7218
  </div>
@@ -35,6 +35,15 @@ fire on the next shipped card and be raised reflexively, which is worse than no
35
35
  check: it teaches people that the number is noise. These are set to catch a step
36
36
  change — roughly a doubling — not ordinary growth.
37
37
 
38
+ TWO NUMBERS GATE, NOT ONE. `test_the_board_still_has_headroom_to_grow` fails the
39
+ board at 80% of its ceiling, so the number that actually stops a build is
40
+ `elements * 0.8`, not `elements`. Choosing the ceiling without that factor is
41
+ how the first pair of numbers here missed its own stated intent: 10,000 was set
42
+ against a measured 7,484, which reads as 1.34x but gated at 8,000 — 516 elements
43
+ of usable room, about ten cards, for a budget whose docstring said it bounded a
44
+ doubling. It was reached in a day. Pick the ceiling so that FOUR FIFTHS of it is
45
+ the step change worth waking up for.
46
+
38
47
  Run: python3 scripts/page_budget.py [-v]
39
48
  """
40
49
  from __future__ import annotations
@@ -64,11 +73,18 @@ class Budget(NamedTuple):
64
73
 
65
74
 
66
75
  #: Per-page ceilings; ``*`` is the default for any page without its own row.
67
- #: Measured 2026-08-02 (bytes / elements / depth):
68
- #: roadmap.html 525,472 / 7,484 / 10 · commands.html 86,026 / 1,512 / 8
69
- #: index.html 58,352 / 488 / 12 · mcp-hub.html 51,162 / 607 / 10
70
- #: design-roadmap 45,931 / 727 / 10 · eval.html 36,320 / 528 / 10
71
- #: carousel.html 27,829 / 328 / 14 · adapters.html 23,559 / 306 / 11
76
+ #: Measured 2026-08-03 (bytes / elements / depth):
77
+ #: roadmap.html 565,883 / 7,951 / 10 · commands.html 86,070 / 1,512 / 8
78
+ #: index.html 63,239 / 488 / 12 · mcp-hub.html 51,163 / 607 / 10
79
+ #: design-roadmap 48,187 / 746 / 10 · eval.html 36,321 / 528 / 10
80
+ #: carousel.html 27,830 / 328 / 14 · adapters.html 23,560 / 306 / 11
81
+ #: demo.html 21,348 / 119 / 9 · chat.html 11,681 / 126 / 10
82
+ #:
83
+ #: The board moved 7,484 -> 7,951 elements in the 24 hours after these ceilings
84
+ #: shipped, which is the growth rate they were written to tolerate rather than a
85
+ #: step change — and it was enough to reach the 8,000 gate. Regenerate this block
86
+ #: with `python3 scripts/page_budget.py -v` when you raise a ceiling; a stale
87
+ #: measurement is what makes the next raise a guess.
72
88
  #:
73
89
  #: Depth is uniform and tight on purpose. Every page here nests 8-14 deep and
74
90
  #: none has any reason to go deeper, so unlike bytes and elements it is not a
@@ -76,9 +92,11 @@ class Budget(NamedTuple):
76
92
  #: and the roadmap board is no more nested than the smallest page on the site.
77
93
  BUDGETS: Dict[str, Budget] = {
78
94
  "roadmap.html": Budget(
79
- kbytes=720, elements=10_000, depth=20,
95
+ kbytes=1_200, elements=16_000, depth=20,
80
96
  why="the code board — already 5x Lighthouse's DOM-size failure "
81
- "threshold, so this bounds a step change, not ordinary growth"),
97
+ "threshold, so this bounds a step change, not ordinary growth; "
98
+ "raised deliberately 2026-08-03 from 720/10,000, which gated at "
99
+ "8,000 and was reached by ordinary card growth in a day"),
82
100
  "commands.html": Budget(
83
101
  kbytes=180, elements=3_000, depth=20,
84
102
  why="generated from COMMANDS, so it grows a block per new command"),
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env python3
2
+ """Serve the repo over HTTP the way GitHub Pages serves it: compressed.
3
+
4
+ WHY THIS EXISTS. The `lighthouse` job scored `docs/roadmap.html` at 0.79 against
5
+ a 0.80 floor — three runs, 0.79 every time, so not the sampling luck that the
6
+ floor was lowered to 0.80 to escape. Pulled from that job's own artifact, the
7
+ score decomposes exactly:
8
+
9
+ FCP 3,638 ms score 0.31 x10 SI 3,638 ms score 0.86 x10
10
+ LCP 3,858 ms score 0.53 x25 TBT 100 ms score 0.98 x30
11
+ CLS 0 score 1.00 x25 -> 3.1 + 8.6 + 13.25 + 29.4 + 25 = 79.35
12
+
13
+ The whole 21-point deficit is FCP and LCP. Both are transfer-bound, and the same
14
+ report says why: `uses-text-compression` scores **0**, with `transferSize`
15
+ 567,874 against `resourceSize` 567,685 — the document arrives uncompressed,
16
+ because `python3 -m http.server` has never sent `Content-Encoding`. Lighthouse
17
+ throttles to 1,474.56 kbps, so 567,685 bytes is 3.08 s of download for the HTML
18
+ alone, which is the 3.6 s FCP with nothing left to explain.
19
+
20
+ GitHub Pages, meanwhile, answers `content-encoding: gzip` for that exact URL —
21
+ checked against the live site, not assumed. Lighthouse estimates gzip takes the
22
+ document to 173,407 B and the stylesheet to 9,831 B, saving 404 KiB and 1,950 ms.
23
+
24
+ So the job was scoring a page 3.3x larger than the one any visitor receives, and
25
+ every conclusion drawn from it inherited that. Two rounds of work had already
26
+ gone into "making the page faster" — collapsing card bodies into `<details>`
27
+ (0.00) and trimming 3,066 characters of prose (0.00) — and neither could have
28
+ moved the number, because both changed *layout* work while the score was being
29
+ decided by *transfer* bytes. `content-visibility: auto` bought 0.01, which is
30
+ about all that was available: TBT already scores 0.98.
31
+
32
+ WHAT THIS IS NOT. It is not a way to make the number look better. It is the
33
+ opposite — it makes the number mean something, by measuring the bytes that are
34
+ actually sent. If the page is genuinely slow once compressed, this reports that,
35
+ and the floor should be raised until it hurts.
36
+
37
+ WHAT IT COMPRESSES. The types Pages compresses: text/*, JavaScript, JSON, XML
38
+ and SVG. Never images or fonts, which are already compressed and would only cost
39
+ CPU. And only when the client asks — a client that sends no `Accept-Encoding`
40
+ gets the raw bytes, which is what makes the uncompressed path still reachable.
41
+
42
+ Run: python3 scripts/serve_docs.py [--port 8099] [--bind 127.0.0.1]
43
+ """
44
+ from __future__ import annotations
45
+
46
+ import argparse
47
+ import gzip
48
+ import io
49
+ import os
50
+ from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
51
+ from typing import Optional
52
+
53
+ #: Compressed by GitHub Pages, and worth compressing: markup, styles, scripts
54
+ #: and data. `image/svg+xml` is in because SVG is text; every other image type
55
+ #: and every font is deliberately out — already-compressed bytes only get bigger.
56
+ COMPRESSIBLE = (
57
+ "text/",
58
+ "application/javascript",
59
+ "application/json",
60
+ "application/xml",
61
+ "application/xhtml+xml",
62
+ "image/svg+xml",
63
+ )
64
+
65
+ #: gzip's default. Level 9 costs measurably more CPU for ~1% fewer bytes, and a
66
+ #: harness that is slower than the thing it measures gets switched off.
67
+ LEVEL = 6
68
+
69
+ #: `.lighthouserc.json` waits for this substring before it starts collecting.
70
+ #: `test_serve_docs.py` pins the two together, because the failure mode when
71
+ #: they drift is a job that hangs until it times out rather than one that says
72
+ #: what went wrong.
73
+ READY = "Serving HTTP"
74
+
75
+
76
+ def compressible(ctype: Optional[str]) -> bool:
77
+ """True if `ctype` is a type Pages would compress."""
78
+ if not ctype:
79
+ return False
80
+ return ctype.split(";")[0].strip().startswith(COMPRESSIBLE)
81
+
82
+
83
+ class GzipHandler(SimpleHTTPRequestHandler):
84
+ """`SimpleHTTPRequestHandler`, plus the `Content-Encoding` Pages sends.
85
+
86
+ `protocol_version` is left at the base class's HTTP/1.0 on purpose. Raising
87
+ it to 1.1 would enable keep-alive and cut handshakes, which moves the same
88
+ metrics compression moves — and then the score change this PR reports would
89
+ have two causes and no way to separate them. One variable at a time.
90
+ """
91
+
92
+ def send_head(self): # type: ignore[override]
93
+ """Return the body to send, gzipped when the client asked and it helps.
94
+
95
+ Overriding `send_head` rather than `do_GET` keeps HEAD honest: the base
96
+ class calls this for both verbs, so a HEAD reports the same
97
+ `Content-Length` a GET would actually deliver.
98
+ """
99
+ path = self.translate_path(self.path)
100
+ if os.path.isdir(path):
101
+ return super().send_head() # directory index: not worth it
102
+ accepted = self.headers.get("Accept-Encoding", "")
103
+ ctype = self.guess_type(path)
104
+ if "gzip" not in accepted or not compressible(ctype):
105
+ return super().send_head()
106
+ try:
107
+ with open(path, "rb") as fh:
108
+ raw = fh.read()
109
+ mtime = os.stat(path).st_mtime
110
+ except OSError:
111
+ return super().send_head() # 404/403 wording stays the base
112
+ # mtime=0: the gzip header otherwise carries a timestamp, which would
113
+ # make two runs of the same file differ byte for byte and turn any
114
+ # future "did the payload change?" check into noise.
115
+ body = gzip.compress(raw, LEVEL, mtime=0)
116
+ self.send_response(200)
117
+ self.send_header("Content-Type", ctype)
118
+ self.send_header("Content-Encoding", "gzip")
119
+ self.send_header("Content-Length", str(len(body)))
120
+ self.send_header("Last-Modified", self.date_time_string(mtime))
121
+ self.end_headers()
122
+ return io.BytesIO(body)
123
+
124
+ def log_message(self, fmt, *args):
125
+ """Quiet. Three Lighthouse runs over two pages is a lot of 200 lines."""
126
+
127
+
128
+ def main(argv=None) -> int:
129
+ ap = argparse.ArgumentParser(prog="serve_docs.py", description=__doc__)
130
+ ap.add_argument("--port", type=int, default=8099)
131
+ ap.add_argument("--bind", default="127.0.0.1")
132
+ ap.add_argument("--directory", default=os.getcwd())
133
+ args = ap.parse_args(argv)
134
+
135
+ os.chdir(args.directory)
136
+ httpd = ThreadingHTTPServer((args.bind, args.port), GzipHandler)
137
+ print("%s on %s port %d (gzip)" % (READY, args.bind, args.port), flush=True)
138
+ try:
139
+ httpd.serve_forever()
140
+ except KeyboardInterrupt:
141
+ pass
142
+ finally:
143
+ httpd.server_close()
144
+ return 0
145
+
146
+
147
+ if __name__ == "__main__":
148
+ raise SystemExit(main())
@@ -14,6 +14,7 @@ also_copy =
14
14
  CODE_OF_CONDUCT.md
15
15
  evals/
16
16
  Makefile
17
+ .lighthouserc.json
17
18
 
18
19
  [egg_info]
19
20
  tag_build =
@@ -149,3 +149,23 @@ class TestTheShippedPages:
149
149
  assert elements < ceiling * 0.8, (
150
150
  "roadmap.html is at %d of %d elements — raise the ceiling in "
151
151
  "BUDGETS deliberately" % (elements, ceiling))
152
+
153
+ @pytest.mark.skipif(not (_ROOT / "docs" / "roadmap.html").exists(),
154
+ reason="board absent")
155
+ def test_the_board_has_byte_headroom_too(self):
156
+ """Bytes had the ceiling but not the warning — the same hole, one over.
157
+
158
+ The element ceiling gets an early warning at 80% so the raise is a
159
+ decision; `kbytes` had none, so it would have gone from green straight
160
+ to a red required job with no step in between. When this was written the
161
+ board sat at 565,883 B — 78.6% of the then-720 kB ceiling, 10,117 B
162
+ short of it, which is two to six more cards at the 1.8-5.5 kB the four
163
+ then queued each added.
164
+ """
165
+ m = _load()
166
+ nbytes, _e, _d = m.measure(
167
+ (_ROOT / "docs" / "roadmap.html").read_text(encoding="utf-8"))
168
+ ceiling = m.BUDGETS["roadmap.html"].kbytes * 1000
169
+ assert nbytes < ceiling * 0.8, (
170
+ "roadmap.html is at %d kB of %d kB — raise the ceiling in BUDGETS "
171
+ "deliberately" % (nbytes // 1000, ceiling // 1000))
@@ -0,0 +1,197 @@
1
+ """Unit tests: scripts/serve_docs.py — serving docs the way Pages serves them.
2
+
3
+ WHY THIS FILE EXISTS. The `lighthouse` job scored `roadmap.html` 0.79 three
4
+ times against a 0.80 floor while `uses-text-compression` scored 0 and
5
+ `transferSize` equalled `resourceSize` — the harness served the document
6
+ uncompressed, which GitHub Pages does not. These tests pin the properties that
7
+ makes true: compressible types are compressed, already-compressed types are left
8
+ alone, a client that does not ask still gets raw bytes, and the headers describe
9
+ the bytes actually sent.
10
+
11
+ NO SOCKET IS BOUND. The handler is driven over an in-memory pair of buffers
12
+ instead of a listening port. That is not only for the sandboxes that refuse to
13
+ bind one — a test that needs a free port is a test that fails on a busy machine
14
+ for reasons having nothing to do with the code under test.
15
+ """
16
+ from __future__ import annotations
17
+
18
+ import gzip
19
+ import importlib.util
20
+ import io
21
+ import json
22
+ from pathlib import Path
23
+
24
+ import pytest
25
+
26
+ _ROOT = Path(__file__).resolve().parents[2]
27
+ _SCRIPT = _ROOT / "scripts" / "serve_docs.py"
28
+
29
+ pytestmark = pytest.mark.skipif(
30
+ not _SCRIPT.exists(), reason="repo-root script not reachable")
31
+
32
+
33
+ def _load():
34
+ spec = importlib.util.spec_from_file_location("serve_docs", _SCRIPT)
35
+ assert spec and spec.loader
36
+ mod = importlib.util.module_from_spec(spec)
37
+ spec.loader.exec_module(mod)
38
+ return mod
39
+
40
+
41
+ class _Wire(io.BytesIO):
42
+ """A write buffer the handler is allowed to `close()` without losing it."""
43
+
44
+ def close(self):
45
+ # Not discarding the bytes is the whole point: the handler closes its
46
+ # `wfile` in `finish()`, and a real BytesIO would drop the response.
47
+ pass
48
+
49
+
50
+ class _Socket:
51
+ """Just enough socket for `BaseHTTPRequestHandler.setup()`."""
52
+
53
+ def __init__(self, request: bytes):
54
+ self._in = io.BytesIO(request)
55
+ self.out = _Wire()
56
+
57
+ def makefile(self, mode="r", *args, **kwargs):
58
+ return self.out if "w" in mode else self._in
59
+
60
+ def close(self):
61
+ pass
62
+
63
+ # `BaseHTTPRequestHandler.finish()` may flush and shut the connection down.
64
+ def shutdown(self, how):
65
+ pass
66
+
67
+ def sendall(self, data):
68
+ self.out.write(data)
69
+
70
+
71
+ def _request(mod, target, accept_encoding=None, method="GET"):
72
+ """Run one request through `GzipHandler`; return `(headers, body)`."""
73
+ lines = ["%s %s HTTP/1.0" % (method, target), "Host: 127.0.0.1"]
74
+ if accept_encoding:
75
+ lines.append("Accept-Encoding: %s" % accept_encoding)
76
+ raw = ("\r\n".join(lines) + "\r\n\r\n").encode()
77
+ sock = _Socket(raw)
78
+ mod.GzipHandler(sock, ("127.0.0.1", 41234), None)
79
+ head, _sep, body = sock.out.getvalue().partition(b"\r\n\r\n")
80
+ headers = {}
81
+ for line in head.decode("latin-1").split("\r\n")[1:]:
82
+ if ":" in line:
83
+ k, _c, v = line.partition(":")
84
+ headers[k.strip().lower()] = v.strip()
85
+ return headers, body
86
+
87
+
88
+ @pytest.fixture
89
+ def site(tmp_path, monkeypatch):
90
+ """A tiny two-file site as the process CWD, plus the loaded module."""
91
+ (tmp_path / "page.html").write_text("<p>%s</p>" % ("hello " * 400),
92
+ encoding="utf-8")
93
+ # A PNG header followed by noise: already-compressed bytes, so gzipping it
94
+ # would spend CPU to make it bigger.
95
+ (tmp_path / "pic.png").write_bytes(
96
+ b"\x89PNG\r\n\x1a\n" + bytes(range(256)) * 8)
97
+ monkeypatch.chdir(tmp_path)
98
+ return _load(), tmp_path
99
+
100
+
101
+ class TestWhatGetsCompressed:
102
+ def test_markup_is_gzipped_and_round_trips(self, site):
103
+ mod, root = site
104
+ headers, body = _request(mod, "/page.html", "gzip")
105
+ assert headers["content-encoding"] == "gzip"
106
+ assert gzip.decompress(body) == (root / "page.html").read_bytes()
107
+
108
+ def test_the_length_header_describes_the_bytes_sent(self, site):
109
+ # A Content-Length taken from the uncompressed file is how a client
110
+ # ends up waiting for bytes that already arrived.
111
+ mod, _root = site
112
+ headers, body = _request(mod, "/page.html", "gzip")
113
+ assert int(headers["content-length"]) == len(body)
114
+
115
+ def test_compression_actually_shrinks_the_document(self, site):
116
+ mod, _root = site
117
+ _h, gz = _request(mod, "/page.html", "gzip")
118
+ _h2, raw = _request(mod, "/page.html")
119
+ assert len(gz) < len(raw) / 4, (
120
+ "the point of this harness is the size difference: %d vs %d"
121
+ % (len(gz), len(raw)))
122
+
123
+ def test_an_image_is_not_compressed(self, site):
124
+ # Already-compressed bytes: gzip costs CPU and adds bytes, and Pages
125
+ # does not do it either.
126
+ mod, _root = site
127
+ headers, _body = _request(mod, "/pic.png", "gzip")
128
+ assert "content-encoding" not in headers
129
+
130
+ def test_a_client_that_does_not_ask_gets_raw_bytes(self, site):
131
+ # The uncompressed path has to stay reachable — it is what `curl` with
132
+ # no header gets, and what any tool measuring raw weight expects.
133
+ mod, _root = site
134
+ headers, body = _request(mod, "/page.html")
135
+ assert "content-encoding" not in headers
136
+ assert body.startswith(b"<p>hello")
137
+
138
+ def test_a_head_reports_the_compressed_length(self, site):
139
+ # HEAD and GET must agree, or a client sizes the response wrong. This
140
+ # is why the override is on `send_head` and not on `do_GET`.
141
+ mod, _root = site
142
+ get_h, get_body = _request(mod, "/page.html", "gzip")
143
+ head_h, head_body = _request(mod, "/page.html", "gzip", method="HEAD")
144
+ assert head_body == b""
145
+ assert head_h["content-length"] == get_h["content-length"]
146
+ assert int(head_h["content-length"]) == len(get_body)
147
+
148
+ def test_a_missing_file_is_still_a_404(self, site):
149
+ mod, _root = site
150
+ sock = _Socket(b"GET /nope.html HTTP/1.0\r\nAccept-Encoding: gzip\r\n\r\n")
151
+ mod.GzipHandler(sock, ("127.0.0.1", 41234), None)
152
+ assert b"404" in sock.out.getvalue().split(b"\r\n")[0]
153
+
154
+
155
+ class TestTheTypeTable:
156
+ @pytest.mark.parametrize("ctype", [
157
+ "text/html", "text/html; charset=utf-8", "text/css",
158
+ "application/javascript", "application/json", "image/svg+xml",
159
+ ])
160
+ def test_text_shaped_types_compress(self, ctype):
161
+ assert _load().compressible(ctype)
162
+
163
+ @pytest.mark.parametrize("ctype", [
164
+ "image/png", "image/webp", "font/woff2", "application/zip", "", None,
165
+ ])
166
+ def test_binary_types_do_not(self, ctype):
167
+ assert not _load().compressible(ctype)
168
+
169
+
170
+ class TestTheHarnessAgrees:
171
+ def test_the_ready_line_matches_what_lighthouse_waits_for(self):
172
+ """A drift here hangs the job until it times out instead of failing.
173
+
174
+ `startServerReadyPattern` is a regex lighthouse-ci watches stdout for
175
+ before it starts collecting. If the script's banner stops matching, the
176
+ job does not say "banner changed" — it waits, then dies of timeout.
177
+ """
178
+ rc = json.loads(
179
+ (_ROOT / ".lighthouserc.json").read_text(encoding="utf-8"))
180
+ collect = rc["ci"]["collect"]
181
+ assert collect["startServerReadyPattern"] in _load().READY
182
+
183
+ def test_the_rc_starts_this_script(self):
184
+ rc = json.loads(
185
+ (_ROOT / ".lighthouserc.json").read_text(encoding="utf-8"))
186
+ assert "serve_docs.py" in rc["ci"]["collect"]["startServerCommand"], (
187
+ "plain `http.server` is what served the page uncompressed in the "
188
+ "first place")
189
+
190
+ def test_the_port_the_rc_serves_is_the_port_it_audits(self):
191
+ # Two numbers in one file that have to match, and nothing checked them.
192
+ rc = json.loads(
193
+ (_ROOT / ".lighthouserc.json").read_text(encoding="utf-8"))
194
+ collect = rc["ci"]["collect"]
195
+ port = collect["startServerCommand"].split("--port")[1].split()[0]
196
+ for url in collect["url"]:
197
+ assert ":%s/" % port in url, url