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.
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.lighthouserc.json +1 -1
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/PKG-INFO +1 -1
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/_version.py +2 -2
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_skill_cli.egg-info/PKG-INFO +1 -1
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_skill_cli.egg-info/SOURCES.txt +3 -0
- boost_skill_cli-1.0.396/docs/roadmap/items/lighthouse-scored-a-page-nobody-is-served.md +64 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap.html +62 -1
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/page_budget.py +25 -7
- boost_skill_cli-1.0.396/scripts/serve_docs.py +148 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/setup.cfg +1 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_page_budget.py +20 -0
- boost_skill_cli-1.0.396/tests/unit/test_serve_docs.py +197 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.gitattributes +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.gitignore +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.gitleaks.toml +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.htmlvalidate.json +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.lycheeignore +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.markdownlint-cli2.jsonc +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.pre-commit-config.yaml +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.stylelintrc.json +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.vale/styles/boost/Terminology.yml +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.vale/styles/config/vocabularies/boost/accept.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/.vale.ini +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/CLAUDE.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/CODE_OF_CONDUCT.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/CONTRIBUTING.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/LICENSE +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/MANIFEST.in +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/Makefile +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/README.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/SECURITY.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/__init__.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/__main__.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/cli.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/cliparse.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/__init__.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/_common.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/bmad.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/configuration.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/discovery.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/hooks.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/info.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/intelligence.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/pkg.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/quality.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/run.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/safety.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/taps.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/commands/team.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/__init__.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/adapters.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/agents.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/ai.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/capabilities.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/catalog.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/chat.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/claude_settings.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/complete.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/config.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/dense.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/ed25519.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/embed.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/faithfulness.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/frontmatter.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/gitutil.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/imperative.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/injectscan.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/installscan.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/integrity.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/journal.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/localembed.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/lockfile.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/logs.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/mcp.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/mcpdecl.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/mcphost.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/minisign.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/nethttp.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/output.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/paths.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/policy.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/projectlock.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/provenance.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/rag.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/registry.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/resolve.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/rules.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/scopes.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/secretscan.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/selfupdate.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/serve.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/stackprobe.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/staleness.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/store.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/trustaudit.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/typosquat.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/updatediff.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/util.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/core/workflows.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/data/registries.json +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/errors.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_cli/spin.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_skill_cli.egg-info/dependency_links.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_skill_cli.egg-info/entry_points.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_skill_cli.egg-info/requires.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/boost_skill_cli.egg-info/top_level.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/codecov.yml +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/.claude/settings.local.json +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/DEBUGGING.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/adapters.html +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/architecture/README.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/architecture/c4-components-core.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/architecture/c4-containers.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/architecture/c4-context.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/architecture/c4-dynamic-install.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/distill.gif +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/doctor.gif +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/explain.gif +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/hooks.gif +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/install.gif +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/pulse.gif +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/search.gif +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/gifs/tap.gif +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/distill.tape +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/doctor.tape +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/explain.tape +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/hooks.tape +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/install.tape +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/pulse.tape +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/search.tape +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel/tapes/tap.tape +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/carousel.html +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/chat.html +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/commands.html +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/demo-index.json +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/demo.gif +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/demo.html +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/demo.tape +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/design-roadmap.html +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/eval-latest.json +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/eval.html +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/index.html +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/mcp-hub.html +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/rag-architecture.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D01.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D02.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D03.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D04.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D05.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D06.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D07.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D08.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D09.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D10.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D11.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D12.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D13.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D14.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D15.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D16.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D17.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D18.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D19.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D20.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D21.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D22.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D23.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D24.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D25.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/BOOST-D26.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/a11y-sweep-flakes-on-color-contrast.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/accessibility-audit-pa11y-ci-axe-core.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/actionlint-skips-shellcheck-silently.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/adapter-conformance-langgraph-leg-never-ran.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/ai-bridge-silent-failure-logging.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/ambiguous-tap-short-name-resolution.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/atomic-corruption-safe-lock-file-writes.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/atomic-skill-install-temp-dir-swap.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/autonomous-ship-workflow-and-isolated-worktree.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/bm25-index-is-one-json-blob.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/boost-run-live-agents.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/bring-commands-under-mutation-testing.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/broken-link-and-anchor-checking-lychee.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/build-provenance-slsa-attestations.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/capability-manifest-and-least-privilege-policy.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/chat-command-grounded-conversational-search.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/ci-job-timeout-minutes.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/ci-summary-step-fails-itself.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/ci-time-is-now-runner-queueing.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/code-scanning-rule-can-be-restored.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/codeql-job-rename-stranded-merge-protection.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/command-carousel-page.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/command-reference-docs-site.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/completions-complete-only-command-names.md +0 -0
- {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
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/coverage-dashboard-codecov-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/coverage-guided-fuzzing-atheris-oss-fuzz.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/crash-listing-branch-untested.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/demo-cannot-open-its-own-pr.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/demo-gif-workflow-has-never-succeeded.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/dependabot-missing-pip-ecosystem.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/dependabot-regeneration-drops-platform-pins.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/dependabot-root-pip-entry-duplicates-requirements.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/dependency-cve-gate-pip-audit.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/docsite-chrome-and-content-audit.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/docstring-coverage-interrogate.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/doctor-checks-rules-and-workflows.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/eval-corpus-cannot-see-real-retrieval.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/eval-corpus-is-one-strangers-repo.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/eval-corpus-was-not-actually-pinned.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/eval-deduped-ranked-lists-by-name.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/extension-free-tests-core-dense-py.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/finish-mutation-hardening-across-core.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/fork-safe-network-proxy-handler.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/framework-adapter-langgraph.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/framework-adapter-multi-agent.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/framework-adapters-boost-adapt.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/frontmatter-scalar-over-coercion.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/gemini-cli-agent-target.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/github-community-health-files.md +0 -0
- {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
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/golden-set-statistical-power.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/hash-pinned-reproducible-toolchain-uv-lock.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/html-validation-html-validate.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/install-docs-never-mentioned-upgrading.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/install-resolves-skill-dependencies.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/install-scope-user-or-project.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/installed-skill-trust-audit.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/integrity-verification-boost-verify.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/internal-architecture-diagrams.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/invocation-pid-logging-for-crash-correlation.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/journal-rotation-race-and-handle-leak.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/keyless-dense-tier-local-static-embeddings.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/keyless-semantic-search-for-everyone.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/langchain-integration-explainer-page.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/langchain-langgraph-langsmith-integration.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/layering-guard-import-linter.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/license-compliance-scanning.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/lighthouse-ci-on-the-pages-site.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/lint-tap-misscopes-rule-workflow-entries.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/list-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/localize-the-stored-bm25-snippet.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/lock-invariant-cannot-parse-extras-pins.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/lockfile-enforcement-and-commit-pinning.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/log-timestamps-mislabeled-utc.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/main-has-no-branch-protection.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/make-lint-masks-actionlint-failures.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/make-the-roadmaps-discoverable.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/markdown-consistency-markdownlint-cli2.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/markdownlint-lints-the-fuzz-corpus.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-aware-skills.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-hub-diagram-node-text-overflow.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-install-skips-the-injection-scan.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-launch-objc-fork-safety.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-one-benefit-nameable-task.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-register-names-server-before-env.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-search-before-reinventing.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-search-cost-was-understated.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-servers-ignore-install-scope.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mcp-startup-self-harden-fork-safety.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/memoize-config-load-in-process.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/merged-loop-branches-are-never-pruned.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/modernization-smells-refurb-pyupgrade.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mutation-hardening-core-frontmatter-py.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mutation-hardening-core-gitutil-py.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mutation-hardening-core-store-py.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mutation-shard-floor-is-one-file.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/mypy-strict-mode-for-commands.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/negative-limit-inverts-log-pulse-output.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/onboard-overwrites-generated-files-without-confirm.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/one-command-every-env-nox.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/one-commit-can-cut-two-releases.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/one-shared-atomic-write-helper.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/package-metadata-validation-twine-check-friends.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/patch-coverage-gate-diff-cover.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/path-traversal-unsanitized-rule-workflow-name.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/pep585-604-modernization-sweep.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/performance-regression-gate-pytest-benchmark.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/pin-the-lint-toolchain.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/post-deploy-smoke-headless-load-check.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/prerequisites-and-semantic-search-setup.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/project-scope-across-every-command.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/project-scope-symlink-escape-on-write.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/prompt-injection-scanning-of-skill-markdown.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/prose-and-terminology-linting-vale.md +0 -0
- {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
- {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
- {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
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/python-floor-moves-to-312.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/quality-dashboard-sonarcloud-free-for-oss.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/ranx-significance-monitor.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/reconcile-the-theme-drift.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/refresh-the-marketing-surface.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/release-verifies-the-wrong-commit.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/required-checks-config-drift.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/resolve-vendored-duplicate-copies.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/retrieval-quality-eval-harness.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/reuse-helpers-kill-minor-dead-work.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/roadmap-page-weight-grows-without-bound.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/robust-tag-argument-parsing.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/rule-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/runner-egress-monitoring-stepsecurity-harden-run.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/runtime-explain-faithfulness-guardrail.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/sbom-aware-scanning-osv-scanner.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/sbom-declares-the-wrong-version.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/sbom-on-every-release-cyclonedx-syft.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/sbom-release-event-never-fires.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/scan-and-sync-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/scheduled-toolchain-lock-regeneration.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/scorecard-findings-triage.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/second-type-checker-pyright.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/secret-scanning-gitleaks-push-protection.md +0 -0
- {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
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/serve-py-traversal-guards-untested.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/single-imperative-rule-extractor.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/single-tech-stack-prober.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/split-oversized-command-modules.md +0 -0
- {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
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/structured-json-log-output-mode.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/supply-chain-posture-openssf-scorecard.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/sync-deletes-unowned-broken-symlinks.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/tap-signing-and-provenance-sigstore-minisign.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/theme-asset-linting-stylelint-eslint.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/typo-detection-codespell.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/typosquat-and-name-confusion-detection.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/uninstall-has-no-confirmation-prompt.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/untrack-generated-build-noise.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/update-diff-before-apply.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/update-refreshes-rules-and-workflows.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/update-reinstall-widens-agent-scope.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/visual-regression-pass-on-the-guide.md +0 -0
- {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
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/windows-in-the-ci-matrix.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/wire-bdd-suite-into-ci.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/workflow-install-native-materialization.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/workflow-linting-actionlint.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/workflow-sast-zizmor.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/workspace-scope-install.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/zip-strict-audit.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/docs/roadmap/items/zizmor-pin-is-a-yanked-release.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/eslint.config.mjs +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/README.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/__init__.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/baseline.json +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/faithfulness.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/golden_set.json +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/make_corpus.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/make_golden.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/metrics.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/evals/run_evals.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/examples/README.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/examples/adapt-demo.sh +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/examples/boost-run-prototype.sh +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/index.html +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/noxfile.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/pyproject.toml +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/coverage-tools.in +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/coverage-tools.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/lint-tools.in +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/lint-tools.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/mutation-tools.in +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/mutation-tools.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/platform-pins.lock +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/release-tools.in +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/release-tools.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/test-tools.in +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/requirements/test-tools.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/a11y_check.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/bench_cli.sh +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/build_command_reference.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/build_demo_index.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/build_registries.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/build_roadmap.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/build_scale_corpus.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/check_anchors.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/check_licenses.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/check_required_checks.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/ensure_eval_corpus.sh +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/eval_corpus.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/eval_explain.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/eval_gate.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/eval_recommend.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/eval_retrieval.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/eval_stats_summary.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/import_budget.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/lock_toolchain.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/mutation_gate.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/mutation_shards.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/mutation_weights.json +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/perf_gate.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/post_deploy_smoke.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/publish_eval_json.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/release_guard.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/scripts/release_preflight.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/sonar-project.properties +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/style/README.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/style/boost.css +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/style/boost.js +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/style/demo.html +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/adapt.feature +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/browse.feature +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/count.feature +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/discover.feature +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/doctor.feature +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/environment.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/explain.feature +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/index.feature +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/install.feature +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/list.feature +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/mcp.feature +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/search.feature +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/steps/cli_steps.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/steps/discovery_steps.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/steps/mcp_steps.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/bdd/features/steps/quality_steps.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/conftest.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/eval/baseline.json +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/eval/explain.jsonl +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/eval/golden-natural.jsonl +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/eval/golden.jsonl +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/eval/recommend.jsonl +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/eval/taps-scale.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/eval/taps.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_capabilities_policy.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_adapt.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_bmad.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_chat.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_configuration.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_discovery.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_hooks.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_info.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_intelligence.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_pkg.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_quality.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_taps.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_cli_team.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_everyday_loop.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_integrity_enforce.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_property_parsers.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_run.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_tap_signing.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/functional/test_workspace_scope.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/README.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/01-typical.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/02-lossy-version.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/03-lossy-numbers.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/04-lists.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/05-nested.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/06-empty-block.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/07-unterminated.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/08-none.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/09-unbalanced-quote.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/10-keywords.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/11-crlf.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/frontmatter/12-bom.md +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/01-shorthand.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/02-https.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/03-ssh.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/04-traversal.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/05-empty.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/06-space.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/07-slash.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/corpus/registry/08-bare-host.txt +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/fuzz_frontmatter.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/fuzz/fuzz_registry.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/make_fixture.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/perf/test_benchmarks.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/smoke.sh +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_a11y_check.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_adapters.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_adapters_multi.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_adapters_runner.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_agents.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_ai.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_capabilities.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_catalog.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_chat.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_check_anchors.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_check_licenses.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_claude_settings.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_cliparse.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_codeql_analysis_key.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_command_reference_fresh.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_community_health_files.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_complete.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_config.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_content_dedupe.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_dedup_trust.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_demo_index.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_dense.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_dense_fallback.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_dense_fix_hint.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_dense_shards.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_dense_status.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_dependabot_config.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_docs_pages_linked.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_docsite_chrome.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_ed25519.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_embed.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_embed_local.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_entry_key.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_errors_and_cli_table.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_eval_baseline.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_eval_corpus.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_eval_faithfulness.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_eval_gate.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_eval_grading.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_eval_metrics.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_eval_stats_summary.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_faithfulness.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_frontmatter.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_fuzz_targets.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_gitleaks_config.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_gitutil.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_imperative.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_import_budget.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_injectscan.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_installscan.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_integrity.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_journal.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_localembed.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_localembed_e2e.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_lockfile.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_logs.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_marketing_counts.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mcp.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mcp_install_scan.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mcpdecl.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mcphost.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_minisign.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mutation_hardening.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mutation_shards.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mutation_subfile_shards.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_mutmut_source_paths.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_nethttp.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_output.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_paths.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_perf_gate.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_pkg_confusions.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_pkg_injection.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_pkg_secrets.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_platform_pins.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_policy.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_post_deploy_smoke.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_project_mcp_sidecar.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_projectlock.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_provenance.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_rag.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_rag_fusion.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_registries_fresh.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_registry.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_registry_categories.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_release_guard.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_release_preflight.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_required_checks.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_resolve.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_roadmap_fresh.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_rules.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_scale_corpus.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_scopes.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_secretscan.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_selfupdate.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_serve.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_spin.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_stackprobe.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_staleness.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_store.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_token_parity.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_toolchain_lock.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_trustaudit.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_typosquat.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_updatediff.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_util.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_version.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_workflow_concurrency.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_workflow_timeouts.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/unit/test_workflows.py +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/visual/a11y_check.mjs +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/visual/console_check.mjs +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/visual/package-lock.json +0 -0
- {boost_skill_cli-1.0.394 → boost_skill_cli-1.0.396}/tests/visual/package.json +0 -0
- {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
|
|
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",
|
|
@@ -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.
|
|
22
|
-
__version_tuple__ = version_tuple = (1, 0,
|
|
21
|
+
__version__ = version = '1.0.396'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 396)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -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 — 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×</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 KiB, and
|
|
25
|
+
<code>transferSize</code> 567,874 sits against <code>resourceSize</code> 567,685 — the bytes on
|
|
26
|
+
the wire are the bytes on disk. Lighthouse throttles to <b>1,474.56 kbps</b>, where 566 KB
|
|
27
|
+
is <b>3.08 s</b> of download; the observed FCP was <b>3.63 s</b>. There is nothing left
|
|
28
|
+
over to explain.
|
|
29
|
+
|
|
30
|
+
<b>And the score decomposes exactly.</b> FCP 3,638 ms scores 0.31 (×10) ·
|
|
31
|
+
SI 3,638 ms 0.86 (×10) · LCP 3,858 ms 0.53 (×25) ·
|
|
32
|
+
TBT 100 ms 0.98 (×30) · CLS 0 1.00 (×25), which totals
|
|
33
|
+
<b>79.35 → 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><details></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 — 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 → 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 —
|
|
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×,
|
|
49
|
+
index.html 3.38×, boost.css 2.99×), 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> — 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 → 184,126 B</b>, or <b>3.24 s → 1.00 s</b> of
|
|
56
|
+
download on Lighthouse's link. Nothing else about the harness changed — 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 — 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>
|
|
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 — 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×</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 KiB, and
|
|
7169
|
+
<code>transferSize</code> 567,874 sits against <code>resourceSize</code> 567,685 — the bytes on
|
|
7170
|
+
the wire are the bytes on disk. Lighthouse throttles to <b>1,474.56 kbps</b>, where 566 KB
|
|
7171
|
+
is <b>3.08 s</b> of download; the observed FCP was <b>3.63 s</b>. There is nothing left
|
|
7172
|
+
over to explain.
|
|
7173
|
+
|
|
7174
|
+
<b>And the score decomposes exactly.</b> FCP 3,638 ms scores 0.31 (×10) ·
|
|
7175
|
+
SI 3,638 ms 0.86 (×10) · LCP 3,858 ms 0.53 (×25) ·
|
|
7176
|
+
TBT 100 ms 0.98 (×30) · CLS 0 1.00 (×25), which totals
|
|
7177
|
+
<b>79.35 → 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><details></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 — 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 → 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 —
|
|
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×,
|
|
7193
|
+
index.html 3.38×, boost.css 2.99×), 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> — 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 → 184,126 B</b>, or <b>3.24 s → 1.00 s</b> of
|
|
7200
|
+
download on Lighthouse's link. Nothing else about the harness changed — 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 — 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-
|
|
68
|
-
#: roadmap.html
|
|
69
|
-
#: index.html
|
|
70
|
-
#: design-roadmap
|
|
71
|
-
#: carousel.html 27,
|
|
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=
|
|
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())
|
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|