kanon-cli 3.3.2__tar.gz → 3.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1033) hide show
  1. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/CHANGELOG.md +135 -0
  2. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/PKG-INFO +1 -1
  3. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/integration-testing.md +191 -0
  4. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/pyproject.toml +1 -1
  5. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/__init__.py +1 -1
  6. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/marketplace_validator.py +210 -30
  7. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_validate_marketplace.py +50 -5
  8. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_validate_marketplace.py +10 -5
  9. kanon_cli-3.3.3/tests/scenarios/test_et.py +445 -0
  10. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_ci_workflows.py +34 -0
  11. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_marketplace_validator.py +223 -10
  12. kanon_cli-3.3.3/tests/unit/test_toolchain_isolation.py +243 -0
  13. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/uv.lock +1 -1
  14. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.claude/settings.json +0 -0
  15. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/.devcontainer.postcreate.sh +0 -0
  16. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/VERSION +0 -0
  17. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/catalog-entry.json +0 -0
  18. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/devcontainer-functions.sh +0 -0
  19. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/devcontainer.json +0 -0
  20. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/fix-line-endings.py +0 -0
  21. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/nix-family-os/README.md +0 -0
  22. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/nix-family-os/tinyproxy-daemon.sh +0 -0
  23. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/nix-family-os/tinyproxy.conf.template +0 -0
  24. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/postcreate-wrapper.sh +0 -0
  25. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/project-setup.sh +0 -0
  26. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/wsl-family-os/README.md +0 -0
  27. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/wsl-family-os/tinyproxy-daemon.sh +0 -0
  28. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.devcontainer/wsl-family-os/tinyproxy.conf.template +0 -0
  29. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.github/CODEOWNERS +0 -0
  30. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.github/actions/setup-kanon/action.yml +0 -0
  31. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.github/workflows/codeql-analysis.yml +0 -0
  32. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.github/workflows/main-validation.yml +0 -0
  33. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.github/workflows/pr-validation.yml +0 -0
  34. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.github/workflows/publish.yml +0 -0
  35. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.gitignore +0 -0
  36. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.markdownlint.json +0 -0
  37. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.pre-commit-config.yaml +0 -0
  38. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.tool-versions +0 -0
  39. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/.yamllint +0 -0
  40. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/CLAUDE.md +0 -0
  41. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/CONTRIBUTING.md +0 -0
  42. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/LICENSE +0 -0
  43. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/Makefile +0 -0
  44. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/README.md +0 -0
  45. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/architecture.md +0 -0
  46. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/catalog-author-guide.md +0 -0
  47. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/catalog-format-versioning.md +0 -0
  48. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/catalogs-explained.md +0 -0
  49. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/claude-marketplaces-guide.md +0 -0
  50. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/cli/catalog-audit.md +0 -0
  51. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/cli/doctor.md +0 -0
  52. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/cli/validate.md +0 -0
  53. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/cli-reference.md +0 -0
  54. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/cli.md +0 -0
  55. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/coming-from-pip-npm-cargo.md +0 -0
  56. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/configuration.md +0 -0
  57. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/contributing.md +0 -0
  58. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/creating-manifest-repos.md +0 -0
  59. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/creating-packages.md +0 -0
  60. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/doctor.md +0 -0
  61. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/exit-codes.md +0 -0
  62. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/git-auth-setup.md +0 -0
  63. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/how-it-works.md +0 -0
  64. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/installation.md +0 -0
  65. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/lifecycle.md +0 -0
  66. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/list-and-add.md +0 -0
  67. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/lockfile.md +0 -0
  68. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/migrating-existing-kanon-files.md +0 -0
  69. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/migration-to-add.md +0 -0
  70. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/multi-source-guide.md +0 -0
  71. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/outdated-and-why.md +0 -0
  72. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/pipeline-integration.md +0 -0
  73. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/privacy.md +0 -0
  74. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/repo/README.md +0 -0
  75. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/repo/internal-fs-layout.md +0 -0
  76. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/repo/manifest-format.md +0 -0
  77. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/repo/python-support.md +0 -0
  78. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/repo/repo-hooks.md +0 -0
  79. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/repo/smart-sync.md +0 -0
  80. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/repo/windows.md +0 -0
  81. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/security-model.md +0 -0
  82. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/setup-guide.md +0 -0
  83. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/shell-completion.md +0 -0
  84. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/test-coverage.md +0 -0
  85. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/testing/matrix-traceability.md +0 -0
  86. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/troubleshooting.md +0 -0
  87. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/url-canonicalization.md +0 -0
  88. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/docs/version-resolution.md +0 -0
  89. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/git-hooks/pre-commit +0 -0
  90. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/git-hooks/pre-push +0 -0
  91. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/link +0 -0
  92. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/scripts/check_archive_no_duplicates.py +0 -0
  93. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/__main__.py +0 -0
  94. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/cli.py +0 -0
  95. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/__init__.py +0 -0
  96. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/add.py +0 -0
  97. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/catalog.py +0 -0
  98. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/clean.py +0 -0
  99. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/completion.py +0 -0
  100. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/doctor.py +0 -0
  101. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/install.py +0 -0
  102. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/list.py +0 -0
  103. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/marketplace.py +0 -0
  104. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/outdated.py +0 -0
  105. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/remove.py +0 -0
  106. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/repo.py +0 -0
  107. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/search.py +0 -0
  108. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/validate.py +0 -0
  109. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/commands/why.py +0 -0
  110. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/__init__.py +0 -0
  111. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/cache.py +0 -0
  112. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/cached_catalogs.py +0 -0
  113. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/catalog_entries.py +0 -0
  114. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/catalog_versions.py +0 -0
  115. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/lockfile_names.py +0 -0
  116. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/midtoken.py +0 -0
  117. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/pep440_filter.py +0 -0
  118. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/powershell.py +0 -0
  119. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/preamble.py +0 -0
  120. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/project_versions.py +0 -0
  121. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/sanitize.py +0 -0
  122. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/completions/source_names.py +0 -0
  123. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/constants.py +0 -0
  124. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/__init__.py +0 -0
  125. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/catalog.py +0 -0
  126. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/clean.py +0 -0
  127. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/cli_args.py +0 -0
  128. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/discover.py +0 -0
  129. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/git_runner.py +0 -0
  130. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/include_walker.py +0 -0
  131. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/install.py +0 -0
  132. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/kanon_hash.py +0 -0
  133. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/kanonenv.py +0 -0
  134. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/kanonenv_writer.py +0 -0
  135. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/lockfile.py +0 -0
  136. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/manifest.py +0 -0
  137. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/manifest_vars.py +0 -0
  138. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/marketplace.py +0 -0
  139. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/metadata.py +0 -0
  140. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/remote_url.py +0 -0
  141. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/telemetry.py +0 -0
  142. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/update_check.py +0 -0
  143. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/url.py +0 -0
  144. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/core/xml_validator.py +0 -0
  145. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/__init__.py +0 -0
  146. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/color.py +0 -0
  147. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/command.py +0 -0
  148. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/editor.py +0 -0
  149. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/error.py +0 -0
  150. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/event_log.py +0 -0
  151. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/fetch.py +0 -0
  152. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/git_command.py +0 -0
  153. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/git_config.py +0 -0
  154. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/git_refs.py +0 -0
  155. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/git_ssh +0 -0
  156. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/git_superproject.py +0 -0
  157. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/git_trace2_event_log.py +0 -0
  158. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/git_trace2_event_log_base.py +0 -0
  159. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/hooks/commit-msg +0 -0
  160. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/hooks/pre-auto-gc +0 -0
  161. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/hooks.py +0 -0
  162. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/main.py +0 -0
  163. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/manifest_xml.py +0 -0
  164. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/pager.py +0 -0
  165. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/platform_utils.py +0 -0
  166. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/platform_utils_win32.py +0 -0
  167. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/progress.py +0 -0
  168. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/project.py +0 -0
  169. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/repo +0 -0
  170. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/repo_logging.py +0 -0
  171. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/repo_trace.py +0 -0
  172. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/requirements.jsonc +0 -0
  173. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/ssh.py +0 -0
  174. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/__init__.py +0 -0
  175. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/abandon.py +0 -0
  176. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/branches.py +0 -0
  177. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/checkout.py +0 -0
  178. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/cherry_pick.py +0 -0
  179. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/diff.py +0 -0
  180. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/diffmanifests.py +0 -0
  181. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/download.py +0 -0
  182. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/envsubst.py +0 -0
  183. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/forall.py +0 -0
  184. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/gc.py +0 -0
  185. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/grep.py +0 -0
  186. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/help.py +0 -0
  187. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/info.py +0 -0
  188. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/init.py +0 -0
  189. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/list.py +0 -0
  190. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/manifest.py +0 -0
  191. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/overview.py +0 -0
  192. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/prune.py +0 -0
  193. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/rebase.py +0 -0
  194. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/selfupdate.py +0 -0
  195. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/smartsync.py +0 -0
  196. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/stage.py +0 -0
  197. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/start.py +0 -0
  198. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/status.py +0 -0
  199. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/sync.py +0 -0
  200. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/subcmds/upload.py +0 -0
  201. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/version_constraints.py +0 -0
  202. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/repo/wrapper.py +0 -0
  203. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/utils/__init__.py +0 -0
  204. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/utils/concurrency.py +0 -0
  205. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/utils/levenshtein.py +0 -0
  206. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/utils/lock_file_path.py +0 -0
  207. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/utils/spawn.py +0 -0
  208. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/src/kanon_cli/version.py +0 -0
  209. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/__init__.py +0 -0
  210. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/conftest.py +0 -0
  211. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-1/repo-specs/duplicate-child-marketplace.xml +0 -0
  212. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-1/repo-specs/missing-recommended-marketplace.xml +0 -0
  213. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-1/repo-specs/missing-required-marketplace.xml +0 -0
  214. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-1/repo-specs/multiple-blocks-marketplace.xml +0 -0
  215. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-2/repo-specs/dotted-name-marketplace.xml +0 -0
  216. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-2/repo-specs/hyphenated-name-marketplace.xml +0 -0
  217. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-2/repo-specs/uppercase-name-marketplace.xml +0 -0
  218. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-3/repo-specs/group-a-1-marketplace.xml +0 -0
  219. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-3/repo-specs/group-a-2-marketplace.xml +0 -0
  220. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-3/repo-specs/group-b-1-marketplace.xml +0 -0
  221. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-3/repo-specs/group-b-2-marketplace.xml +0 -0
  222. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-4/repo-specs/file-url-marketplace.xml +0 -0
  223. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-4/repo-specs/query-string-marketplace.xml +0 -0
  224. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/broken-soft-spot-4/repo-specs/unresolvable-marketplace.xml +0 -0
  225. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/legacy-catalog-dir/catalog/sample-entry/.kanon +0 -0
  226. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalog/legacy-catalog-dir/repo-specs/sample.xml +0 -0
  227. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalogs/zero-pep440-tags/README.md +0 -0
  228. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/catalogs/zero-pep440-tags/repo-specs/entry-a/entry-a-marketplace.xml +0 -0
  229. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/completion/__init__.py +0 -0
  230. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/completion/expected-bash.sh +0 -0
  231. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/completion/expected-powershell.ps1 +0 -0
  232. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/completion/expected-zsh.sh +0 -0
  233. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/README.md +0 -0
  234. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/conflict-detected.txt +0 -0
  235. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/entry-not-found.txt +0 -0
  236. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/lockfile-hash-mismatch.txt +0 -0
  237. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/lockfile-sha-unreachable.txt +0 -0
  238. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/missing-catalog-source.txt +0 -0
  239. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/missing-required-metadata-field.txt +0 -0
  240. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/source-collision.txt +0 -0
  241. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/errors/zero-pep440-tags-under-prefix.txt +0 -0
  242. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/README.md +0 -0
  243. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-add.txt +0 -0
  244. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-catalog-audit.txt +0 -0
  245. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-catalog.txt +0 -0
  246. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-clean.txt +0 -0
  247. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-completion.txt +0 -0
  248. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-doctor.txt +0 -0
  249. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-install.txt +0 -0
  250. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-list.txt +0 -0
  251. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-marketplace.txt +0 -0
  252. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-outdated.txt +0 -0
  253. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-remove.txt +0 -0
  254. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-search.txt +0 -0
  255. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-toplevel.txt +0 -0
  256. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/help/kanon-why.txt +0 -0
  257. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/.gitignore +0 -0
  258. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/README.md +0 -0
  259. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/linter-test-bad.invalid-yaml +0 -0
  260. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/linter-test-bad.md +0 -0
  261. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/linter-test-bad.py +0 -0
  262. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/sample-manifest.xml +0 -0
  263. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/sample-project-config.json +0 -0
  264. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/test.gitconfig +0 -0
  265. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/fixtures/repo/version_constraints_data.json +0 -0
  266. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/__init__.py +0 -0
  267. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/conftest.py +0 -0
  268. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_add_alias_journey.py +0 -0
  269. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_alias_consumer_journey.py +0 -0
  270. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_argparse_errors.py +0 -0
  271. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_argparse_help.py +0 -0
  272. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_ci_runs_operator_path_tests.py +0 -0
  273. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_clean_lifecycle.py +0 -0
  274. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_cli_entry_point.py +0 -0
  275. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_completion_snapshots.py +0 -0
  276. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_default_branch_journey.py +0 -0
  277. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_env_int_guard_journey.py +0 -0
  278. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_error_snapshots.py +0 -0
  279. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_exit_code_matrix.py +0 -0
  280. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_groups_filter.py +0 -0
  281. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_help_snapshots.py +0 -0
  282. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_help_text_contract.py +0 -0
  283. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_home_flag_unwritable_journey.py +0 -0
  284. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_init_default_branch_prerequisite_journey.py +0 -0
  285. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_install_hermetic_journey.py +0 -0
  286. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_install_lifecycle.py +0 -0
  287. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_install_real_kanon.py +0 -0
  288. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_install_v3_lock_fail_fast_journey.py +0 -0
  289. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_kanon_home_store_journey.py +0 -0
  290. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_kanon_repo_cli.py +0 -0
  291. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_kanon_repo_e2e.py +0 -0
  292. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_kanon_repo_lifecycle_journey.py +0 -0
  293. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_lifecycle_journey.py +0 -0
  294. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_list.py +0 -0
  295. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_list_telemetry.py +0 -0
  296. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_make_operator_path_targets.py +0 -0
  297. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_marketplace_journey.py +0 -0
  298. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_matrix_traceability_complete.py +0 -0
  299. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_provider_agnostic.py +0 -0
  300. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_abandon_errors.py +0 -0
  301. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_abandon_flags.py +0 -0
  302. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_abandon_happy.py +0 -0
  303. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_branches_errors.py +0 -0
  304. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_branches_flags.py +0 -0
  305. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_branches_happy.py +0 -0
  306. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_checkout_errors.py +0 -0
  307. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_checkout_flags.py +0 -0
  308. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_checkout_happy.py +0 -0
  309. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_cherry_pick_errors.py +0 -0
  310. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_cherry_pick_flags.py +0 -0
  311. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_cherry_pick_happy.py +0 -0
  312. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_diff_errors.py +0 -0
  313. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_diff_flags.py +0 -0
  314. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_diff_happy.py +0 -0
  315. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_diffmanifests_errors.py +0 -0
  316. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_diffmanifests_flags.py +0 -0
  317. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_diffmanifests_happy.py +0 -0
  318. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_dir_override.py +0 -0
  319. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_download_errors.py +0 -0
  320. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_download_flags.py +0 -0
  321. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_download_happy.py +0 -0
  322. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_envsubst_errors.py +0 -0
  323. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_envsubst_flags.py +0 -0
  324. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_envsubst_happy.py +0 -0
  325. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_exit_codes.py +0 -0
  326. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_forall_errors.py +0 -0
  327. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_forall_flags.py +0 -0
  328. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_forall_happy.py +0 -0
  329. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_gc_errors.py +0 -0
  330. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_gc_flags.py +0 -0
  331. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_gc_happy.py +0 -0
  332. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_grep_errors.py +0 -0
  333. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_grep_flags.py +0 -0
  334. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_grep_happy.py +0 -0
  335. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_help_errors.py +0 -0
  336. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_help_flags.py +0 -0
  337. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_help_happy.py +0 -0
  338. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_info_errors.py +0 -0
  339. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_info_flags.py +0 -0
  340. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_info_happy.py +0 -0
  341. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_init_errors.py +0 -0
  342. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_init_flags.py +0 -0
  343. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_init_happy.py +0 -0
  344. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_init_mirror.py +0 -0
  345. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_list_errors.py +0 -0
  346. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_list_flags.py +0 -0
  347. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_list_happy.py +0 -0
  348. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_manifest_errors.py +0 -0
  349. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_manifest_flags.py +0 -0
  350. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_manifest_happy.py +0 -0
  351. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_manifest_revision_as_tag.py +0 -0
  352. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_overview_errors.py +0 -0
  353. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_overview_flags.py +0 -0
  354. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_overview_happy.py +0 -0
  355. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_passthrough.py +0 -0
  356. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_prune_errors.py +0 -0
  357. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_prune_flags.py +0 -0
  358. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_prune_happy.py +0 -0
  359. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_rebase_errors.py +0 -0
  360. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_rebase_flags.py +0 -0
  361. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_rebase_happy.py +0 -0
  362. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_selfupdate_disabled.py +0 -0
  363. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_selfupdate_errors.py +0 -0
  364. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_selfupdate_flags.py +0 -0
  365. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_selfupdate_happy.py +0 -0
  366. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_smartsync_errors.py +0 -0
  367. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_smartsync_flags.py +0 -0
  368. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_smartsync_happy.py +0 -0
  369. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_stage_errors.py +0 -0
  370. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_stage_flags.py +0 -0
  371. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_stage_happy.py +0 -0
  372. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_start_errors.py +0 -0
  373. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_start_flags.py +0 -0
  374. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_start_happy.py +0 -0
  375. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_status_errors.py +0 -0
  376. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_status_flags.py +0 -0
  377. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_status_happy.py +0 -0
  378. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_sync_errors.py +0 -0
  379. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_sync_flags.py +0 -0
  380. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_sync_happy.py +0 -0
  381. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_upload_errors.py +0 -0
  382. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_upload_flags.py +0 -0
  383. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_repo_upload_happy.py +0 -0
  384. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_singular_catalog_source_inert.py +0 -0
  385. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_stdout_stderr_discipline.py +0 -0
  386. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_telemetry_journey.py +0 -0
  387. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_update_alert_journey.py +0 -0
  388. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_validate_journey.py +0 -0
  389. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_validate_lifecycle.py +0 -0
  390. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_validate_lockfile.py +0 -0
  391. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_validate_xml_errors.py +0 -0
  392. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_validate_xml_repo_root.py +0 -0
  393. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/functional/test_zero_source_clean_error.py +0 -0
  394. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/__init__.py +0 -0
  395. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/conftest.py +0 -0
  396. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/fixtures/__init__.py +0 -0
  397. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/fixtures/synthetic/__init__.py +0 -0
  398. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/fixtures/synthetic/conftest.py +0 -0
  399. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/fixtures/synthetic/drift.py +0 -0
  400. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/fixtures/synthetic/test_synthetic_pytest_fixtures.py +0 -0
  401. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/fixtures/synthetic/upgrade_versioned.py +0 -0
  402. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/provider_allowlist.txt +0 -0
  403. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/__init__.py +0 -0
  404. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/conftest.py +0 -0
  405. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_bug_fixes.py +0 -0
  406. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_consolidated_constraints_e2e.py +0 -0
  407. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_envsubst_integration.py +0 -0
  408. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_import_functional.py +0 -0
  409. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_linkfile_copyfile.py +0 -0
  410. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_linkfile_exclude_journey.py +0 -0
  411. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_manifest_parsing.py +0 -0
  412. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_process_isolation.py +0 -0
  413. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_repo_module_smoke.py +0 -0
  414. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_repo_pipeline.py +0 -0
  415. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_repo_run_lifecycle.py +0 -0
  416. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_repo_sync_lifecycle.py +0 -0
  417. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_version_constraints_integration.py +0 -0
  418. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_annotation_roundtrip.py +0 -0
  419. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_contactinfo_roundtrip.py +0 -0
  420. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_copyfile_roundtrip.py +0 -0
  421. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_default_roundtrip.py +0 -0
  422. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_extend_project_roundtrip.py +0 -0
  423. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_include_roundtrip.py +0 -0
  424. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_linkfile_roundtrip.py +0 -0
  425. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_manifest_roundtrip.py +0 -0
  426. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_manifest_server_roundtrip.py +0 -0
  427. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_notice_roundtrip.py +0 -0
  428. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_project_roundtrip.py +0 -0
  429. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_remote_roundtrip.py +0 -0
  430. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_remove_project_roundtrip.py +0 -0
  431. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_repo_hooks_roundtrip.py +0 -0
  432. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_submanifest_roundtrip.py +0 -0
  433. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/repo/test_xml_superproject_roundtrip.py +0 -0
  434. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_add_core.py +0 -0
  435. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_add_dry_run.py +0 -0
  436. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_add_env_var_detection.py +0 -0
  437. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_add_zero_tags.py +0 -0
  438. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_auto_discovery.py +0 -0
  439. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_background_refresh.py +0 -0
  440. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_cache_clock_skew.py +0 -0
  441. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_cache_layout.py +0 -0
  442. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_entry_uniqueness.py +0 -0
  443. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_framework.py +0 -0
  444. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_legacy_dir.py +0 -0
  445. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_metadata.py +0 -0
  446. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_remote_url.py +0 -0
  447. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_source_name.py +0 -0
  448. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_strict.py +0 -0
  449. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_audit_tag_format.py +0 -0
  450. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_catalog_constraints.py +0 -0
  451. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_ci_validation.py +0 -0
  452. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_clean_env_override_cleanup.py +0 -0
  453. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_clean_lifecycle.py +0 -0
  454. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_clean_paths.py +0 -0
  455. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_cli_entry_points.py +0 -0
  456. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_complete_cached_catalogs.py +0 -0
  457. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_complete_catalog_entries.py +0 -0
  458. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_complete_catalog_versions.py +0 -0
  459. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_complete_lockfile_names.py +0 -0
  460. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_complete_project_versions.py +0 -0
  461. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_complete_source_names.py +0 -0
  462. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_completion_bash.py +0 -0
  463. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_completion_powershell_subcommand.py +0 -0
  464. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_completion_subcommand.py +0 -0
  465. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_completion_zsh.py +0 -0
  466. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_concurrency.py +0 -0
  467. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_concurrency_serialization.py +0 -0
  468. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_copyfile_fs_effects.py +0 -0
  469. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_cross_platform_contract.py +0 -0
  470. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doc_validation.py +0 -0
  471. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doctor_cache_flags.py +0 -0
  472. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doctor_cache_flags_workspace_independent.py +0 -0
  473. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doctor_consistency.py +0 -0
  474. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doctor_default_subcheck_output.py +0 -0
  475. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doctor_effective_source.py +0 -0
  476. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doctor_prune_cache.py +0 -0
  477. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_doctor_remote_check.py +0 -0
  478. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_envsubst_command.py +0 -0
  479. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_fs_fault_extended.py +0 -0
  480. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_fs_fault_injection.py +0 -0
  481. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_full_lifecycle_synthetic.py +0 -0
  482. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_full_user_journey.py +0 -0
  483. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_git_fault_injection.py +0 -0
  484. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_git_retry_env.py +0 -0
  485. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_gitignore_idempotency.py +0 -0
  486. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_home_flag_store_relocation.py +0 -0
  487. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_after_add.py +0 -0
  488. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_command.py +0 -0
  489. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_env_var_resolution.py +0 -0
  490. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_errors.py +0 -0
  491. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_include_cycle.py +0 -0
  492. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_include_diamond.py +0 -0
  493. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_lifecycle.py +0 -0
  494. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_lock_file_derivation.py +0 -0
  495. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_lockfile_replay.py +0 -0
  496. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_marketplace_registration.py +0 -0
  497. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_no_kanon_remediation.py +0 -0
  498. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_optional_vars.py +0 -0
  499. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_path_conflict_integration.py +0 -0
  500. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_paths.py +0 -0
  501. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_per_alias_gitbase.py +0 -0
  502. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_reconcile.py +0 -0
  503. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_refresh_lock.py +0 -0
  504. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_refresh_lock_source.py +0 -0
  505. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_remote_url_policy.py +0 -0
  506. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_required_vars.py +0 -0
  507. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_install_strict.py +0 -0
  508. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_json_output_stream_discipline.py +0 -0
  509. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_kanon_add_placeholder_handling.py +0 -0
  510. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_kanon_clean_embedded.py +0 -0
  511. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_kanon_dir_collision.py +0 -0
  512. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_kanon_full_lifecycle.py +0 -0
  513. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_kanon_install_embedded.py +0 -0
  514. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_kanonenv_parsing.py +0 -0
  515. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_lifecycle_recovery.py +0 -0
  516. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_linkfile_fs_effects.py +0 -0
  517. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_all_versions.py +0 -0
  518. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_all_versions_canonical.py +0 -0
  519. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_all_versions_malformed_revision_resilience.py +0 -0
  520. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_command_json.py +0 -0
  521. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_default.py +0 -0
  522. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_detail.py +0 -0
  523. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_filter.py +0 -0
  524. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_format_json.py +0 -0
  525. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_synthetic_catalog_variants.py +0 -0
  526. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_list_tree.py +0 -0
  527. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_lockfile_roundtrip.py +0 -0
  528. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_marketplace_install.py +0 -0
  529. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_marketplace_lifecycle.py +0 -0
  530. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_marketplace_orphan_prune.py +0 -0
  531. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_midtoken_bash.py +0 -0
  532. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_midtoken_zsh.py +0 -0
  533. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_misc_features.py +0 -0
  534. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_multi_source_aggregation.py +0 -0
  535. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_no_bundled_catalog.py +0 -0
  536. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_no_default_catalog.py +0 -0
  537. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_no_hardcoded_org_values.py +0 -0
  538. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_observability.py +0 -0
  539. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_outdated.py +0 -0
  540. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_outdated_branch_drift.py +0 -0
  541. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_outdated_fail_on_upgrade.py +0 -0
  542. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_outdated_format_json.py +0 -0
  543. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_outdated_refs_tags_revision_parsing.py +0 -0
  544. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_platform_parity.py +0 -0
  545. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_preamble_bash.py +0 -0
  546. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_preamble_zsh.py +0 -0
  547. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_remove_core.py +0 -0
  548. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_remove_dry_run.py +0 -0
  549. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_remove_force_integration.py +0 -0
  550. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_signal_handling.py +0 -0
  551. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_synthetic_drift_fixture.py +0 -0
  552. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_synthetic_upgrade_versioned_fixture.py +0 -0
  553. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_unicode_encoding.py +0 -0
  554. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_validate_marketplace_revision_existence.py +0 -0
  555. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_validate_metadata.py +0 -0
  556. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_validate_xml.py +0 -0
  557. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_version_resolution.py +0 -0
  558. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_version_widened_bare_pep440.py +0 -0
  559. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_wheel_e2e.py +0 -0
  560. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_why_ambiguous.py +0 -0
  561. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_why_chain_walker.py +0 -0
  562. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_why_format_json.py +0 -0
  563. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_why_live_resolve.py +0 -0
  564. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_why_not_found_suggestion.py +0 -0
  565. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/integration/test_workspace_dir_env.py +0 -0
  566. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f1_s2_t5_regression.py +0 -0
  567. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f5_s2_t7_regression.py +0 -0
  568. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s1_t1_regression.py +0 -0
  569. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s1_t2_regression.py +0 -0
  570. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s1_t3_regression.py +0 -0
  571. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s1_t4_regression.py +0 -0
  572. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s2_t1_regression.py +0 -0
  573. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s2_t2_regression.py +0 -0
  574. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s2_t3_regression.py +0 -0
  575. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s2_t4_regression.py +0 -0
  576. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s2_t5_regression.py +0 -0
  577. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s2_t6_regression.py +0 -0
  578. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s3_t1_regression.py +0 -0
  579. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_f6_s3_t2_regression.py +0 -0
  580. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_e0_install_relative_regression.py +0 -0
  581. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/regression/test_linkfile_samefile_regression.py +0 -0
  582. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/__init__.py +0 -0
  583. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/_rp_helpers.py +0 -0
  584. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/conftest.py +0 -0
  585. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ad.py +0 -0
  586. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_bs.py +0 -0
  587. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_cd.py +0 -0
  588. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_content_pins.py +0 -0
  589. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_cs.py +0 -0
  590. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_doctor_cache.py +0 -0
  591. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_doctor_journey.py +0 -0
  592. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ec.py +0 -0
  593. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ep.py +0 -0
  594. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ev.py +0 -0
  595. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_hv.py +0 -0
  596. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ic.py +0 -0
  597. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_id.py +0 -0
  598. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_install_graph_capture.py +0 -0
  599. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ks.py +0 -0
  600. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_lf.py +0 -0
  601. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_list_journey.py +0 -0
  602. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_lockfile_lifecycle.py +0 -0
  603. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_marketplace_direct_checkout.py +0 -0
  604. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_mk.py +0 -0
  605. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ms.py +0 -0
  606. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_ns_marketplace_and_global_flags.py +0 -0
  607. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_outdated_two_source.py +0 -0
  608. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_pk.py +0 -0
  609. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rc.py +0 -0
  610. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_refresh_lock_existing_checkout.py +0 -0
  611. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rls_exact_vs_range.py +0 -0
  612. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_abandon.py +0 -0
  613. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_branches.py +0 -0
  614. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_checkout.py +0 -0
  615. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_cherry_pick.py +0 -0
  616. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_diff.py +0 -0
  617. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_diffmanifests.py +0 -0
  618. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_download.py +0 -0
  619. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_envsubst.py +0 -0
  620. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_forall.py +0 -0
  621. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_gc.py +0 -0
  622. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_grep.py +0 -0
  623. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_help.py +0 -0
  624. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_info.py +0 -0
  625. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_init.py +0 -0
  626. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_list.py +0 -0
  627. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_manifest.py +0 -0
  628. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_overview.py +0 -0
  629. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_prune.py +0 -0
  630. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_rebase.py +0 -0
  631. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_smartsync.py +0 -0
  632. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_stage.py +0 -0
  633. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_start.py +0 -0
  634. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_status.py +0 -0
  635. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_sync.py +0 -0
  636. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_upload.py +0 -0
  637. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rp_wrap.py +0 -0
  638. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_rx.py +0 -0
  639. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_scenario_coverage_meta.py +0 -0
  640. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_search_multi_source.py +0 -0
  641. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_tc_bootstrap.py +0 -0
  642. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_tc_clean.py +0 -0
  643. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_tc_install.py +0 -0
  644. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_tc_validate.py +0 -0
  645. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_uj.py +0 -0
  646. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_va.py +0 -0
  647. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_va_validate_lockfile.py +0 -0
  648. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_why_surface_query.py +0 -0
  649. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_why_url_path.py +0 -0
  650. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/scenarios/test_why_url_path_placeholder.py +0 -0
  651. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/security/__init__.py +0 -0
  652. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/security/test_security_hardening.py +0 -0
  653. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/test_wheel_layout.py +0 -0
  654. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/__init__.py +0 -0
  655. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/commands/test_repo_dir_resolution.py +0 -0
  656. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/conftest.py +0 -0
  657. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/__init__.py +0 -0
  658. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/conftest.py +0 -0
  659. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/fixtures/.gitignore +0 -0
  660. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/fixtures/README.md +0 -0
  661. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/fixtures/sample-manifest.xml +0 -0
  662. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/fixtures/sample-project-config.json +0 -0
  663. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/fixtures/test.gitconfig +0 -0
  664. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/fixtures/version_constraints_data.json +0 -0
  665. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/functional/__init__.py +0 -0
  666. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/functional/test_features.py +0 -0
  667. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/subcmds/__init__.py +0 -0
  668. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/subcmds/test_init_mirror.py +0 -0
  669. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/subcmds/test_manifest_revision_as_tag.py +0 -0
  670. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/subcmds/test_manifest_revision_as_tag_pep440.py +0 -0
  671. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/subcmds/test_selfupdate_stub.py +0 -0
  672. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_abandon_massive.py +0 -0
  673. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_branches_coverage.py +0 -0
  674. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug10_selfupdate_incompatible.py +0 -0
  675. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug11_race_condition.py +0 -0
  676. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug12_backup_preserved.py +0 -0
  677. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug13_init_reinit_warning.py +0 -0
  678. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug14_non_tty_log.py +0 -0
  679. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug15_prerelease_docs.py +0 -0
  680. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug16_nested_var_warning.py +0 -0
  681. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug18_envsubst_double_parse.py +0 -0
  682. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug19_glob_src_error.py +0 -0
  683. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug1_envsubst_malformed_xml.py +0 -0
  684. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug20_glob_dest_file.py +0 -0
  685. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug2_linkfile_errors.py +0 -0
  686. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug3_execv_replaces_process.py +0 -0
  687. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug4_symlink_overwrite.py +0 -0
  688. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug5_empty_envsubst_list.py +0 -0
  689. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug6_undefined_env_vars.py +0 -0
  690. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug7_git_ls_remote_retry.py +0 -0
  691. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug8_ls_remote_stderr.py +0 -0
  692. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_bug9_constraint_resolution_cache.py +0 -0
  693. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_checklocalpath_rules_1_5.py +0 -0
  694. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_checklocalpath_rules_6_11.py +0 -0
  695. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_checkout_massive.py +0 -0
  696. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_cherrypick_coverage.py +0 -0
  697. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_color.py +0 -0
  698. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_command.py +0 -0
  699. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_conftest_fixtures.py +0 -0
  700. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_diffmanifests_deep.py +0 -0
  701. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_doc_validate_git_preconditions.py +0 -0
  702. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_download_coverage.py +0 -0
  703. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_editor.py +0 -0
  704. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_embedded_mode.py +0 -0
  705. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_envsubst_basic.py +0 -0
  706. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_envsubst_edge.py +0 -0
  707. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_envsubst_massive.py +0 -0
  708. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_error.py +0 -0
  709. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_event_log.py +0 -0
  710. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_event_log_massive.py +0 -0
  711. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_fetch.py +0 -0
  712. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_fixture_files.py +0 -0
  713. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_forall_deep.py +0 -0
  714. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_git_command.py +0 -0
  715. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_git_config.py +0 -0
  716. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_git_refs.py +0 -0
  717. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_git_superproject.py +0 -0
  718. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_git_trace2_event_log.py +0 -0
  719. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_gitconfig_coverage.py +0 -0
  720. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_grep_deep.py +0 -0
  721. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_harness_smoke.py +0 -0
  722. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_hooks.py +0 -0
  723. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_import_verification.py +0 -0
  724. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_imports.py +0 -0
  725. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_include_path_resolution.py +0 -0
  726. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_info_deep.py +0 -0
  727. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_init_deep.py +0 -0
  728. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_list_massive.py +0 -0
  729. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_main.py +0 -0
  730. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_main_coverage.py +0 -0
  731. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_main_init_download_boost.py +0 -0
  732. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_makefile_lint_format.py +0 -0
  733. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_makefile_structure.py +0 -0
  734. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_makefile_test_targets.py +0 -0
  735. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_manifest_coverage_boost.py +0 -0
  736. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_manifest_deep.py +0 -0
  737. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_manifest_doc_rp_flags.py +0 -0
  738. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_manifest_massive.py +0 -0
  739. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_manifest_subcmd_massive.py +0 -0
  740. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_manifest_xml.py +0 -0
  741. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_manifest_xml_pep440.py +0 -0
  742. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_medium_files_boost.py +0 -0
  743. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_mkdtemp_cleanup.py +0 -0
  744. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_overview_massive.py +0 -0
  745. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_package_structure.py +0 -0
  746. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_pager.py +0 -0
  747. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_parselist.py +0 -0
  748. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_pep440_edge_1.py +0 -0
  749. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_pep440_edge_2.py +0 -0
  750. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_pep440_ops_ge.py +0 -0
  751. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_pep440_ops_rest.py +0 -0
  752. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_platform_utils.py +0 -0
  753. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_process_isolation.py +0 -0
  754. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_progress.py +0 -0
  755. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project.py +0 -0
  756. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_coverage_boost.py +0 -0
  757. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_coverage_threshold.py +0 -0
  758. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_deep.py +0 -0
  759. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_deep_boost.py +0 -0
  760. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_final_boost.py +0 -0
  761. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_integration.py +0 -0
  762. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_massive.py +0 -0
  763. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_metaproject_boost.py +0 -0
  764. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_methods.py +0 -0
  765. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_project_sync.py +0 -0
  766. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_prune_massive.py +0 -0
  767. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_rebase_coverage.py +0 -0
  768. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_remaining_coverage_boost.py +0 -0
  769. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_repo_envsubst_api.py +0 -0
  770. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_repo_logging.py +0 -0
  771. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_repo_run_api.py +0 -0
  772. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_repo_sync_api.py +0 -0
  773. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_repo_trace.py +0 -0
  774. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_revision_inheritance.py +0 -0
  775. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_revision_tag_branch_sha.py +0 -0
  776. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_ruff_config.py +0 -0
  777. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_selfupdate_embedded.py +0 -0
  778. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_selfupdate_massive.py +0 -0
  779. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_small_files_boost.py +0 -0
  780. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_ssh.py +0 -0
  781. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_ssh_deep.py +0 -0
  782. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_stage_coverage.py +0 -0
  783. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_stage_massive.py +0 -0
  784. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_start_coverage.py +0 -0
  785. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_status_coverage.py +0 -0
  786. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_status_gaps.py +0 -0
  787. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_status_massive.py +0 -0
  788. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmd_imports.py +0 -0
  789. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds.py +0 -0
  790. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_abandon.py +0 -0
  791. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_branches.py +0 -0
  792. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_checkout.py +0 -0
  793. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_cherry_pick.py +0 -0
  794. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_diff.py +0 -0
  795. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_diffmanifests.py +0 -0
  796. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_download.py +0 -0
  797. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_envsubst.py +0 -0
  798. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_forall.py +0 -0
  799. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_gc.py +0 -0
  800. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_grep.py +0 -0
  801. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_help.py +0 -0
  802. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_info.py +0 -0
  803. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_init.py +0 -0
  804. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_list.py +0 -0
  805. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_manifest.py +0 -0
  806. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_overview.py +0 -0
  807. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_prune.py +0 -0
  808. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_rebase.py +0 -0
  809. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_selfupdate.py +0 -0
  810. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_smartsync.py +0 -0
  811. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_stage.py +0 -0
  812. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_start.py +0 -0
  813. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_status.py +0 -0
  814. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_sync.py +0 -0
  815. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_subcmds_upload.py +0 -0
  816. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_superproject_deep.py +0 -0
  817. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_sync_coverage_boost.py +0 -0
  818. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_sync_deep.py +0 -0
  819. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_sync_deep_boost.py +0 -0
  820. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_sync_massive.py +0 -0
  821. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_upload_deep.py +0 -0
  822. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_version_consolidation.py +0 -0
  823. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_version_constraints.py +0 -0
  824. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_wheel_contents.py +0 -0
  825. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_wrapper.py +0 -0
  826. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_annotation_attributes.py +0 -0
  827. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_annotation_crossref.py +0 -0
  828. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_annotation_happy.py +0 -0
  829. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_contactinfo_attributes.py +0 -0
  830. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_contactinfo_crossref.py +0 -0
  831. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_contactinfo_happy.py +0 -0
  832. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_copyfile_attributes.py +0 -0
  833. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_copyfile_crossref.py +0 -0
  834. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_copyfile_happy.py +0 -0
  835. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_default_attributes.py +0 -0
  836. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_default_crossref.py +0 -0
  837. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_default_happy.py +0 -0
  838. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_extend_project_attributes.py +0 -0
  839. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_extend_project_crossref.py +0 -0
  840. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_extend_project_happy.py +0 -0
  841. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_fault_malformed.py +0 -0
  842. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_fault_structural.py +0 -0
  843. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_include_attributes.py +0 -0
  844. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_include_crossref.py +0 -0
  845. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_include_cycles.py +0 -0
  846. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_include_happy.py +0 -0
  847. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_linkfile_attributes.py +0 -0
  848. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_linkfile_crossref.py +0 -0
  849. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_linkfile_happy.py +0 -0
  850. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_manifest_attributes.py +0 -0
  851. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_manifest_crossref.py +0 -0
  852. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_manifest_happy.py +0 -0
  853. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_manifest_server_attributes.py +0 -0
  854. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_manifest_server_crossref.py +0 -0
  855. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_manifest_server_flow.py +0 -0
  856. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_manifest_server_happy.py +0 -0
  857. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_notice_attributes.py +0 -0
  858. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_notice_crossref.py +0 -0
  859. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_notice_happy.py +0 -0
  860. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_project_attributes.py +0 -0
  861. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_project_crossref.py +0 -0
  862. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_project_happy.py +0 -0
  863. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_remote_attributes.py +0 -0
  864. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_remote_crossref.py +0 -0
  865. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_remote_happy.py +0 -0
  866. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_remove_project_attributes.py +0 -0
  867. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_remove_project_crossref.py +0 -0
  868. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_remove_project_happy.py +0 -0
  869. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_repo_hooks_attributes.py +0 -0
  870. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_repo_hooks_crossref.py +0 -0
  871. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_repo_hooks_happy.py +0 -0
  872. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_submanifest_attributes.py +0 -0
  873. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_submanifest_crossref.py +0 -0
  874. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_submanifest_happy.py +0 -0
  875. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_superproject_attributes.py +0 -0
  876. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_superproject_crossref.py +0 -0
  877. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_superproject_flow.py +0 -0
  878. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xml_superproject_happy.py +0 -0
  879. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xmlbool.py +0 -0
  880. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_xmlint.py +0 -0
  881. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/repo/test_yamllint_config.py +0 -0
  882. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_accessed_at_coalescing.py +0 -0
  883. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_add.py +0 -0
  884. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_add_collision.py +0 -0
  885. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_add_zero_tags.py +0 -0
  886. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_background_refresh.py +0 -0
  887. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_bare_semver_to_tag.py +0 -0
  888. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_build_project_entries.py +0 -0
  889. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cache.py +0 -0
  890. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cache_layout.py +0 -0
  891. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cache_ttl.py +0 -0
  892. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cached_catalogs.py +0 -0
  893. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog.py +0 -0
  894. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_check_parser.py +0 -0
  895. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_entry_uniqueness.py +0 -0
  896. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_framework.py +0 -0
  897. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_legacy_dir.py +0 -0
  898. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_metadata.py +0 -0
  899. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_project_tag_format.py +0 -0
  900. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_remote_url.py +0 -0
  901. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_source_name.py +0 -0
  902. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_strict.py +0 -0
  903. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_audit_tag_format.py +0 -0
  904. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_catalog_source_parsing.py +0 -0
  905. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_check_no_comments.py +0 -0
  906. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_clean.py +0 -0
  907. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_clean_command.py +0 -0
  908. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cli.py +0 -0
  909. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cli_args.py +0 -0
  910. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cli_help_format.py +0 -0
  911. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_cli_json_stream_discipline.py +0 -0
  912. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_complete_cached_catalogs.py +0 -0
  913. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_complete_catalog_entries.py +0 -0
  914. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_complete_catalog_versions.py +0 -0
  915. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_complete_lockfile_names.py +0 -0
  916. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_complete_project_versions.py +0 -0
  917. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_complete_source_names.py +0 -0
  918. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_completion.py +0 -0
  919. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_completion_sanitization.py +0 -0
  920. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_completion_subcommand.py +0 -0
  921. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_concurrency.py +0 -0
  922. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_conftest_scrubber.py +0 -0
  923. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_constants.py +0 -0
  924. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_constants_doctor_subcheck.py +0 -0
  925. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_constants_env_int.py +0 -0
  926. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_constants_install_after_add.py +0 -0
  927. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_constants_list.py +0 -0
  928. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_constants_outdated_refs_tags.py +0 -0
  929. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_constants_why_lockfile.py +0 -0
  930. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_coverage_gaps.py +0 -0
  931. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_derive_source_name.py +0 -0
  932. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_discover.py +0 -0
  933. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_discover_source_names_missing_url.py +0 -0
  934. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_docs_embedded_architecture.py +0 -0
  935. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_docs_remaining_and_catalog.py +0 -0
  936. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor.py +0 -0
  937. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor_cache_flags.py +0 -0
  938. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor_completion_errors.py +0 -0
  939. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor_completion_staleness.py +0 -0
  940. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor_consistency.py +0 -0
  941. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor_coverage_gaps.py +0 -0
  942. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor_effective_source.py +0 -0
  943. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_doctor_remote_reachability.py +0 -0
  944. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_env_isolation.py +0 -0
  945. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_envsubst_subcommand.py +0 -0
  946. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_git_runner.py +0 -0
  947. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_home_flag.py +0 -0
  948. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_include_walker.py +0 -0
  949. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install.py +0 -0
  950. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_color_default.py +0 -0
  951. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_command.py +0 -0
  952. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_conflict_detection.py +0 -0
  953. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_https_enforcement.py +0 -0
  954. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_placeholder_validation.py +0 -0
  955. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_reconcile_decision.py +0 -0
  956. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_refresh_lock.py +0 -0
  957. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_refresh_lock_source.py +0 -0
  958. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_state_matrix.py +0 -0
  959. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_strict_flags.py +0 -0
  960. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_install_strict_lock_orphan_naming.py +0 -0
  961. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_integration_testing_doc_manifest_paths.py +0 -0
  962. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_integration_testing_doc_s2_t14.py +0 -0
  963. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_integration_testing_doc_s2_t4.py +0 -0
  964. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_integration_testing_doc_s2_t5.py +0 -0
  965. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_integration_testing_doc_s2_t6.py +0 -0
  966. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_integration_testing_doc_s2_t7.py +0 -0
  967. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_integration_testing_doc_s2_tier1.py +0 -0
  968. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_isolation_fixtures.py +0 -0
  969. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_kanon_hash.py +0 -0
  970. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_kanonenv.py +0 -0
  971. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_kanonenv_advanced_edge_cases.py +0 -0
  972. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_kanonenv_edge_cases.py +0 -0
  973. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_kanonenv_writer.py +0 -0
  974. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_levenshtein.py +0 -0
  975. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_list.py +0 -0
  976. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_lock_file_path.py +0 -0
  977. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_lockfile.py +0 -0
  978. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_lockfile_coverage_gaps.py +0 -0
  979. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_lockfile_reconcile.py +0 -0
  980. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_lockfile_schema_migration.py +0 -0
  981. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_manifest.py +0 -0
  982. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_marketplace.py +0 -0
  983. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_marketplace_cmd.py +0 -0
  984. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_marketplace_install.py +0 -0
  985. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_marketplace_non_plugin_skip.py +0 -0
  986. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_metadata.py +0 -0
  987. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_midtoken_splitter.py +0 -0
  988. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_outdated.py +0 -0
  989. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_outdated_branch_pinned.py +0 -0
  990. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_outdated_fail_on_upgrade.py +0 -0
  991. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_outdated_format_json.py +0 -0
  992. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_pep440_filter.py +0 -0
  993. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_powershell.py +0 -0
  994. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_pre_push_hook.py +0 -0
  995. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_preamble.py +0 -0
  996. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_preamble_semver_tags.py +0 -0
  997. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_provider_agnosticism.py +0 -0
  998. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_pyproject_build_config.py +0 -0
  999. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_remote_url.py +0 -0
  1000. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_remove.py +0 -0
  1001. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_remove_dry_run.py +0 -0
  1002. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_remove_force.py +0 -0
  1003. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_remove_line_endings.py +0 -0
  1004. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_repo.py +0 -0
  1005. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_repo_abspath.py +0 -0
  1006. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_repo_command.py +0 -0
  1007. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_resolve_catalog_dir.py +0 -0
  1008. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_revision_resolve.py +0 -0
  1009. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_rx_catalog_sub_repo.py +0 -0
  1010. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_sanitize.py +0 -0
  1011. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_search.py +0 -0
  1012. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_search_all_versions.py +0 -0
  1013. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_search_coverage_gaps.py +0 -0
  1014. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_search_detail.py +0 -0
  1015. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_search_filter.py +0 -0
  1016. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_search_format_json.py +0 -0
  1017. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_search_tree.py +0 -0
  1018. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_spawn.py +0 -0
  1019. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_telemetry.py +0 -0
  1020. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_update_check.py +0 -0
  1021. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_url.py +0 -0
  1022. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_validate.py +0 -0
  1023. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_validate_command.py +0 -0
  1024. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_validate_metadata.py +0 -0
  1025. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_version.py +0 -0
  1026. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_version_constraint_errors.py +0 -0
  1027. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_why.py +0 -0
  1028. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_why_ambiguity.py +0 -0
  1029. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_why_format_json.py +0 -0
  1030. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_why_suggestions.py +0 -0
  1031. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tests/unit/test_xml_validator.py +0 -0
  1032. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tools/lint/check_no_comments.py +0 -0
  1033. {kanon_cli-3.3.2 → kanon_cli-3.3.3}/tools/test_tmp_monitor.py +0 -0
@@ -2,8 +2,137 @@
2
2
 
3
3
 
4
4
 
5
+ ## v3.3.3 (2026-08-06)
6
+
7
+ ### Fix
8
+
9
+ * fix: scope linkfile dest rule by entry type, exempt direct-checkout marketplaces (#109)
10
+
11
+ * fix: scope marketplace linkfile dest rule to claude-marketplace entries
12
+
13
+ validate_linkfile_dest required every <linkfile dest> in every catalog
14
+ entry to start with ${CLAUDE_MARKETPLACES_DIR}/, ignoring the declared
15
+ <catalog-metadata><type>. Non-marketplace entries that install correctly
16
+ could not pass validation.
17
+
18
+ Closes #94
19
+
20
+ * fix: exempt direct-checkout entries, de-duplicate errors, align tests
21
+
22
+ Builds on ryano144's 0e75e27 (#99), which correctly identified issue #94:
23
+ validate_linkfile_dest required every <linkfile dest> to start with
24
+ ${CLAUDE_MARKETPLACES_DIR}/ regardless of <catalog-metadata><type>, so a
25
+ non-marketplace entry that `kanon install` places correctly could not pass
26
+ validation. Scoping that rule by entry type is right and is kept as is.
27
+
28
+ Three problems remained.
29
+
30
+ 1. The new "a claude-marketplace entry must land a dest under
31
+ ${CLAUDE_MARKETPLACES_DIR}/" rule rejected an entry that declares no
32
+ <linkfile> at all. That is the direct-checkout shape:
33
+ register_direct_checkout_marketplaces registers a project whose checkout
34
+ carries .claude-plugin/marketplace.json and which has no <linkfile>
35
+ children, covered end to end by test_marketplace_direct_checkout.py. The
36
+ old validator accepted it, so the rule as written was a regression, and it
37
+ reproduced the very validator/install contradiction #94 reports, aimed at a
38
+ different entry shape. The rule now applies only when the entry declares at
39
+ least one <linkfile>; an entry declaring none is exempt. The useful half is
40
+ unchanged: an entry whose links all land elsewhere is still caught, and the
41
+ diagnostic now names the direct-checkout way out.
42
+
43
+ 2. Linkfile checks follow each entry's <include> chain, so a defect in a
44
+ manifest shared by several entries was reported once per consumer. Three
45
+ entries including one broken packages.xml produced three identical errors
46
+ and a count of three for a single defect. Errors are de-duplicated within a
47
+ call (a manifest reachable by two include paths) and across the run.
48
+ Identical message text means the same file, project and reason, so
49
+ collapsing exact duplicates cannot hide a second real defect.
50
+
51
+ 3. tests/functional/test_validate_marketplace.py still asserted the old
52
+ contract and was not touched by #99, so three parametrized cases failed:
53
+ relative/path, CLAUDE_MARKETPLACES_DIR/missing-dollar-brace and
54
+ ${OTHER_VAR}/proj are contained dests on an entry with no <type> and are
55
+ now legal. Rather than delete the coverage, the class is split: the three
56
+ contained dests assert exit 0, and a new negative case asserts exit 1 for
57
+ the three shapes that escape the workspace (absolute, '..', empty).
58
+
59
+ Adds docs/integration-testing.md Category 11b (ET-01..ET-07) with runnable
60
+ manual reproductions, and tests/scenarios/test_et.py automating them through
61
+ the real `kanon validate marketplace` subprocess: the full 3x4 entry-type by
62
+ linkfile-shape matrix, containment across all three entry types, a linkfile
63
+ inside an <include>, a marketplace dest supplied by an include, single
64
+ reporting of a shared-include defect, and the mixed plugin-plus-standards
65
+ package from #94 with its negative counterpart.
66
+
67
+ Every documented scenario was also executed by hand against the built CLI and
68
+ matched its stated pass criteria.
69
+
70
+ Closes #94
71
+
72
+ * test: guard the single dependency-resolution path
73
+
74
+ Adds automated coverage for four invariants that were only ever verified by
75
+ hand while diagnosing the shtab CI drift and the 3.3.1 publish failure. Each
76
+ corresponds to a defect this repository actually hit, and none had a test.
77
+
78
+ 1. A tool invoked through `uv run` is declared in [dependency-groups].
79
+ `make security-scan` was `uv run bandit` while bandit was declared nowhere,
80
+ so uv fell through to PATH and silently ran a system-wide bandit -- an
81
+ undeclared dependency deciding a security gate. `uv run` does not fail on an
82
+ undeclared executable, so nothing surfaced it.
83
+
84
+ 2. No Make recipe invokes a tool directly. A bare `ruff check .` or
85
+ `pytest -m unit` resolves from PATH rather than uv.lock, which is precisely
86
+ the two-path split that let shtab 1.9.0 break the tiered CI jobs while the
87
+ uv-based jobs stayed green. Only the scenario target was previously guarded.
88
+
89
+ 3. A dependency whose generated output is byte-compared against a committed
90
+ fixture carries an upper bound. `shtab>=1.7.0` allowed 1.9.0 to change its
91
+ completion output and break CI with no change to this repository.
92
+
93
+ 4. The release job re-locks and stages uv.lock. semantic-release bumps
94
+ pyproject.toml and __init__.py but knows nothing about uv.lock, so without
95
+ the explicit refresh every release leaves the lock a version behind and
96
+ `uv sync --locked` fails on the tag -- how 3.3.1 failed to publish. Its
97
+ symptom is already guarded by test_uv_lock_records_the_declared_project_version;
98
+ this guards the mechanism that prevents it.
99
+
100
+ Each was verified RED by reverting the invariant it protects: removing bandit
101
+ from the dev group, rewriting `uv run ruff` as `ruff`, restoring `shtab>=1.7.0`,
102
+ dropping `uv lock` from the release job, and dropping uv.lock from its `git add`.
103
+ All five produce a message naming the file and the remedy.
104
+
105
+ * fix(test): replace the uv-run regex with linear tokenization
106
+
107
+ CodeQL flagged py/redos (high) on the pattern added in the previous commit:
108
+
109
+ \buv\s+run\s+(?:--[\w-]+(?:[= ]\S+)?\s+)*([A-Za-z][\w.-]*)
110
+
111
+ The repeated group holds an optional sub-match, so input with many repetitions
112
+ of ' --- ---' backtracks exponentially. Skipping uv's own flags is awkward to
113
+ express as a pattern and easy to get wrong in exactly this way.
114
+
115
+ Walking tokens does the same job in linear time and reads more plainly: find
116
+ `uv run`, skip following tokens that begin with '-', take the next one. A flag
117
+ with a detached value would misreport that value as the tool; no target uses
118
+ that form, and the assertion names the offending line, so it would be obvious
119
+ rather than silent. Documented on the helper.
120
+
121
+ Not suppressed: CLAUDE.md forbids annotating away a security finding, and the
122
+ finding was correct. Both guards were re-verified RED afterwards, and the
123
+ tokenizer returns in single-digit milliseconds on 40k adversarial tokens.
124
+
125
+ ---------
126
+
127
+ Co-authored-by: Ryan Gross <ryan.gross@caylent.com> ([`ccfdfec`](https://github.com/caylent-solutions/kanon/commit/ccfdfecdbd7b3e366e1ca9c0579bd84aa70e66ae))
128
+
129
+
5
130
  ## v3.3.2 (2026-08-05)
6
131
 
132
+ ### Chore
133
+
134
+ * chore(release): 3.3.2 ([`6f5ffe7`](https://github.com/caylent-solutions/kanon/commit/6f5ffe7c01553820a2e091cdc996151b5100c6cb))
135
+
7
136
  ### Fix
8
137
 
9
138
  * fix(ci): refresh uv.lock during the release version bump (#107)
@@ -47,6 +176,12 @@ Note the existing 3.3.1 tag still points at a commit carrying the stale
47
176
  lock, so republishing that exact tag will keep failing until the tag is
48
177
  moved or a further release is cut. ([`00714e6`](https://github.com/caylent-solutions/kanon/commit/00714e648a42bea706945e7a38a66fa6dca8df28))
49
178
 
179
+ ### Unknown
180
+
181
+ * Merge pull request #108 from caylent-solutions/release-3.3.2
182
+
183
+ Release 3.3.2 ([`fc48540`](https://github.com/caylent-solutions/kanon/commit/fc48540a5fc082e64c81ef9809f68d583a3a16e8))
184
+
50
185
 
51
186
  ## v3.3.1 (2026-08-04)
52
187
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kanon-cli
3
- Version: 3.3.2
3
+ Version: 3.3.3
4
4
  Summary: Kanon (Kanon Package Manager) CLI tool
5
5
  Project-URL: Homepage, https://github.com/caylent-solutions/kanon
6
6
  Project-URL: Issues, https://github.com/caylent-solutions/kanon/issues
@@ -1521,6 +1521,197 @@ rm -rf "${VA06_DIR}"
1521
1521
 
1522
1522
  ---
1523
1523
 
1524
+ ## 12b. Category 11b: Catalog Entry Type Validation (7 tests)
1525
+
1526
+ `kanon validate marketplace` enforces two linkfile rules. **Containment** applies
1527
+ to every entry: a `<linkfile dest>` names a symlink created relative to the top of
1528
+ the consumer tree, so it must land inside that tree. **The marketplace-dest rule**
1529
+ applies only to an entry whose `<catalog-metadata><type>` is `claude-marketplace`
1530
+ *and* which declares at least one `<linkfile>`: one of those dests must sit under
1531
+ `${CLAUDE_MARKETPLACES_DIR}/`.
1532
+
1533
+ The worked example throughout is a package of engineering standards containing a
1534
+ Claude Code plugin plus the repo-level assets a team expects at conventional
1535
+ paths: `.claude/rules/`, `.githooks/`, and a `.gitleaks.toml` at the repo root.
1536
+
1537
+ **Shared setup for this category:**
1538
+
1539
+ ```bash
1540
+ export ET_DIR="${KANON_TEST_ROOT}/test-et"
1541
+ mkdir -p "${ET_DIR}"
1542
+
1543
+ # Writes a catalog entry: $1 file, $2 <type> (empty for none), $3.. linkfile dests.
1544
+ et_entry() {
1545
+ local file="$1" entry_type="$2"; shift 2
1546
+ local links="" type_el=""
1547
+ for dest in "$@"; do
1548
+ links="${links} <linkfile src=\"src\" dest=\"${dest}\" />
1549
+ "
1550
+ done
1551
+ [ -n "${entry_type}" ] && type_el=" <type>${entry_type}</type>
1552
+ "
1553
+ mkdir -p "$(dirname "${file}")"
1554
+ cat > "${file}" << ENTRYEOF
1555
+ <?xml version="1.0" encoding="UTF-8"?>
1556
+ <manifest>
1557
+ <remote name="origin" fetch="https://example.com" />
1558
+ <project name="standards" path=".packages/standards" remote="origin" revision="refs/tags/ex/standards/1.0.0">
1559
+ ${links} </project>
1560
+ <catalog-metadata>
1561
+ <name>standards</name>
1562
+ <display-name>Engineering Standards</display-name>
1563
+ <description>Plugin plus repo-level standards.</description>
1564
+ <version>1.0.0</version>
1565
+ ${type_el} <owner-name>Example Org</owner-name>
1566
+ <owner-email>eng@example.com</owner-email>
1567
+ <keywords>standards</keywords>
1568
+ </catalog-metadata>
1569
+ </manifest>
1570
+ ENTRYEOF
1571
+ }
1572
+ ```
1573
+
1574
+ ### ET-01: Marketplace entry ships a plugin alongside repo-level standards
1575
+
1576
+ The case issue #94 was filed to unblock. One entry registers a Claude plugin and
1577
+ also places rules, hooks, a root dotfile, and a plain relative config.
1578
+
1579
+ ```bash
1580
+ rm -rf "${ET_DIR}/c01" && et_entry "${ET_DIR}/c01/repo-specs/standards.xml" claude-marketplace \
1581
+ '${CLAUDE_MARKETPLACES_DIR}/standards' \
1582
+ '${PROJECT_ROOT}/.claude/rules' \
1583
+ '${PROJECT_ROOT}/.githooks' \
1584
+ '${PROJECT_ROOT}/.gitleaks.toml' \
1585
+ 'config/lint.toml'
1586
+
1587
+ kanon validate marketplace --repo-root "${ET_DIR}/c01"
1588
+ ```
1589
+
1590
+ **Pass criteria:** Exit code 0, stderr empty. Before the fix each of the four
1591
+ non-marketplace dests produced one error.
1592
+
1593
+ ### ET-02: Non-marketplace entry links only into the project root
1594
+
1595
+ An entry declaring `<type>library</type>` ships no plugin at all.
1596
+
1597
+ ```bash
1598
+ rm -rf "${ET_DIR}/c02" && et_entry "${ET_DIR}/c02/repo-specs/standards.xml" library \
1599
+ '${PROJECT_ROOT}/.claude/rules' '${PROJECT_ROOT}/.gitleaks.toml'
1600
+
1601
+ kanon validate marketplace --repo-root "${ET_DIR}/c02"
1602
+ ```
1603
+
1604
+ **Pass criteria:** Exit code 0, stderr empty. An entry with no `<type>` at all
1605
+ behaves identically.
1606
+
1607
+ ### ET-03: Direct-checkout marketplace entry declares no linkfiles
1608
+
1609
+ A `claude-marketplace` entry registered from a checked-out
1610
+ `.claude-plugin/marketplace.json`, with no `<linkfile>` elements. The
1611
+ marketplace-dest rule must not fire, or validation would reject an entry that
1612
+ `kanon install` registers correctly.
1613
+
1614
+ ```bash
1615
+ rm -rf "${ET_DIR}/c03" && et_entry "${ET_DIR}/c03/repo-specs/standards.xml" claude-marketplace
1616
+
1617
+ kanon validate marketplace --repo-root "${ET_DIR}/c03"
1618
+ ```
1619
+
1620
+ **Pass criteria:** Exit code 0, stderr empty.
1621
+
1622
+ ### ET-04: Marketplace entry whose linkfiles all miss the marketplace directory
1623
+
1624
+ Declares itself a marketplace and uses linkfiles, but every dest lands elsewhere,
1625
+ so it registers nothing.
1626
+
1627
+ ```bash
1628
+ rm -rf "${ET_DIR}/c04" && et_entry "${ET_DIR}/c04/repo-specs/standards.xml" claude-marketplace \
1629
+ '${PROJECT_ROOT}/.claude/rules' '${PROJECT_ROOT}/.githooks'
1630
+
1631
+ set +e
1632
+ kanon validate marketplace --repo-root "${ET_DIR}/c04"
1633
+ exit_code=$?
1634
+ set -e
1635
+ ```
1636
+
1637
+ **Pass criteria:** Exit code non-zero. stderr contains `registers no marketplace`
1638
+ and names all three ways out, including `direct checkout`.
1639
+
1640
+ ### ET-05: A dest that escapes the consumer workspace is rejected
1641
+
1642
+ Three shapes escape, for every entry type: an absolute path, a `..` component,
1643
+ and an empty dest.
1644
+
1645
+ ```bash
1646
+ for bad in '/etc/kanon/rules' '../../outside/workspace' ''; do
1647
+ rm -rf "${ET_DIR}/c05" && et_entry "${ET_DIR}/c05/repo-specs/standards.xml" library "${bad}"
1648
+ set +e
1649
+ kanon validate marketplace --repo-root "${ET_DIR}/c05"
1650
+ echo "dest=${bad} exit=$?"
1651
+ set -e
1652
+ done
1653
+ ```
1654
+
1655
+ **Pass criteria:** Exit code non-zero for each. stderr names the specific reason:
1656
+ `absolute path`, `'..' component`, or `dest is empty`. No error text on stdout.
1657
+
1658
+ ### ET-06: A linkfile inside an `<include>` is validated like an inline one
1659
+
1660
+ `kanon install` resolves the whole include chain, so validation must see the same
1661
+ projects. The entry below is clean; only the included manifest is not.
1662
+
1663
+ ```bash
1664
+ rm -rf "${ET_DIR}/c06" && mkdir -p "${ET_DIR}/c06/repo-specs"
1665
+ cat > "${ET_DIR}/c06/repo-specs/packages.xml" << 'INCEOF'
1666
+ <?xml version="1.0" encoding="UTF-8"?>
1667
+ <manifest>
1668
+ <project name="shared" path=".packages/shared" remote="origin" revision="refs/tags/ex/shared/1.0.0">
1669
+ <linkfile src="src" dest="../escapes" />
1670
+ </project>
1671
+ </manifest>
1672
+ INCEOF
1673
+ et_entry "${ET_DIR}/c06/repo-specs/standards.xml" claude-marketplace '${CLAUDE_MARKETPLACES_DIR}/standards'
1674
+ sed -i.bak 's|<remote name="origin" fetch="https://example.com" />|<remote name="origin" fetch="https://example.com" />\n <include name="repo-specs/packages.xml" />|' \
1675
+ "${ET_DIR}/c06/repo-specs/standards.xml"
1676
+
1677
+ set +e
1678
+ kanon validate marketplace --repo-root "${ET_DIR}/c06"
1679
+ exit_code=$?
1680
+ set -e
1681
+ ```
1682
+
1683
+ **Pass criteria:** Exit code non-zero. stderr contains `'..' component` and names
1684
+ `packages.xml`.
1685
+
1686
+ ### ET-07: A defect in a shared `<include>` is reported once
1687
+
1688
+ Three entries include the same broken manifest. Reporting the identical message
1689
+ once per consumer inflates the count and buries the distinct failures.
1690
+
1691
+ ```bash
1692
+ rm -rf "${ET_DIR}/c07" && mkdir -p "${ET_DIR}/c07/repo-specs"
1693
+ cp "${ET_DIR}/c06/repo-specs/packages.xml" "${ET_DIR}/c07/repo-specs/packages.xml"
1694
+ for name in alpha bravo charlie; do
1695
+ cp "${ET_DIR}/c06/repo-specs/standards.xml" "${ET_DIR}/c07/repo-specs/${name}.xml"
1696
+ done
1697
+
1698
+ set +e
1699
+ kanon validate marketplace --repo-root "${ET_DIR}/c07" 2>&1 | grep -c "'..' component"
1700
+ set -e
1701
+ ```
1702
+
1703
+ **Pass criteria:** Exactly `1` occurrence, and stderr reports
1704
+ `Found 1 validation error(s)` despite three entries including the defect.
1705
+
1706
+ **Cleanup:**
1707
+
1708
+ ```bash
1709
+ cd "${KANON_TEST_ROOT}"
1710
+ rm -rf "${ET_DIR}"
1711
+ ```
1712
+
1713
+ ---
1714
+
1524
1715
  ## 13. Category 12: Entry Points (2 tests)
1525
1716
 
1526
1717
  ### EP-01: python -m kanon_cli --version
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "kanon-cli"
7
- version = "3.3.2"
7
+ version = "3.3.3"
8
8
  description = "Kanon (Kanon Package Manager) CLI tool"
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  requires-python = ">=3.11"
@@ -1,3 +1,3 @@
1
1
  """Kanon CLI -- Kanon Package Manager."""
2
2
 
3
- __version__ = "3.3.2"
3
+ __version__ = "3.3.3"
@@ -1,8 +1,17 @@
1
1
  """Validate marketplace XML manifest files.
2
2
 
3
3
  Checks:
4
- - All <linkfile dest> attributes use the ${CLAUDE_MARKETPLACES_DIR}
5
- variable prefix, rejecting hard-coded or relative paths.
4
+ - Every <linkfile dest> resolves inside the consumer workspace: an absolute
5
+ path, an empty dest, and a '..' traversal component are rejected. A dest
6
+ rooted at ${CLAUDE_MARKETPLACES_DIR}/, at any other ${VAR}, or at a plain
7
+ workspace-relative path is accepted -- an entry may ship non-plugin content
8
+ (shared rules, lint config, git hooks) alongside a Claude plugin.
9
+ - An entry whose <catalog-metadata><type> is 'claude-marketplace' AND which
10
+ declares at least one <linkfile> lands one of them under
11
+ ${CLAUDE_MARKETPLACES_DIR}/, so an entry that declares itself a marketplace
12
+ actually registers one. An entry with no <linkfile> at all is exempt: that
13
+ is the direct-checkout shape that register_direct_checkout_marketplaces
14
+ handles. Entries of any other type (or none) carry no such requirement.
6
15
  - All <include> chains are unbroken (every referenced file exists).
7
16
  - All flattened project path names are unique across manifests.
8
17
  - All <project revision> attributes are pinnable refs: an exact existing git
@@ -27,6 +36,7 @@ from collections.abc import Callable
27
36
  from pathlib import Path
28
37
 
29
38
  from kanon_cli.constants import (
39
+ CATALOG_TYPE_CLAUDE_MARKETPLACE,
30
40
  GIT_RETRY_COUNT_DEFAULT,
31
41
  GIT_RETRY_COUNT_ENV_VAR,
32
42
  KANON_GIT_LS_REMOTE_TIMEOUT,
@@ -47,36 +57,196 @@ LsRemoteRunner = Callable[[str, str], tuple[int, str, str]]
47
57
  _FULL_SHA_RE = re.compile(r"^[0-9a-f]{40}$")
48
58
 
49
59
 
50
- def validate_linkfile_dest(xml_path: Path) -> list[str]:
51
- """Validate all linkfile dest attributes in a manifest XML file.
60
+ def read_entry_type(xml_path: Path) -> str | None:
61
+ """Return the entry's ``<catalog-metadata><type>`` text, or None.
52
62
 
53
- Checks that every <linkfile> element's dest attribute starts with
54
- ${CLAUDE_MARKETPLACES_DIR}/. Returns a list of error messages for
55
- any violations found. An empty list means validation passed.
63
+ A lightweight, side-effect-free read of the one metadata field this module
64
+ needs. It deliberately does NOT reuse
65
+ :func:`kanon_cli.core.metadata._parse_catalog_metadata`: that parser raises
66
+ on any missing REQUIRED field and warns on stderr for missing RECOMMENDED
67
+ ones, which is ``kanon validate metadata``'s job (spec Section 3.5
68
+ soft-spot 1), not this module's. A metadata problem must be reported once,
69
+ by the command that owns it -- never as a spurious linkfile error here.
56
70
 
57
71
  Args:
58
- xml_path: Path to the XML manifest file to validate.
72
+ xml_path: Path to the catalog entry manifest.
73
+
74
+ Returns:
75
+ The stripped ``<type>`` text, or None when the file is unparseable, has
76
+ no ``<catalog-metadata>`` block, or declares no non-empty ``<type>``.
77
+ """
78
+ try:
79
+ root = ET.parse(xml_path).getroot()
80
+ except ET.ParseError:
81
+ return None
82
+
83
+ for block in root.findall("catalog-metadata"):
84
+ type_el = block.find("type")
85
+ if type_el is not None and type_el.text and type_el.text.strip():
86
+ return type_el.text.strip()
87
+ return None
88
+
89
+
90
+ def _dest_containment_error(dest: str) -> str | None:
91
+ """Return why *dest* escapes the consumer workspace, or None when it is safe.
92
+
93
+ A ``<linkfile dest>`` names a symlink created relative to the top of the
94
+ consumer tree. The property worth enforcing is containment -- the link must
95
+ land inside the workspace -- not which specific variable roots it. Three
96
+ shapes escape and are rejected:
97
+
98
+ - An empty dest (nothing to create).
99
+ - An absolute path (``/etc/...``), which writes outside the workspace
100
+ regardless of where kanon runs.
101
+ - Any ``..`` path component, which climbs out of the workspace.
102
+
103
+ A dest rooted at ``${CLAUDE_MARKETPLACES_DIR}/``, at another ``${VAR}``, or
104
+ at a plain relative path is contained and accepted. A ``${VAR}`` root is
105
+ resolved from the consumer's own ``.kanon``, so the consumer -- not the
106
+ catalog author -- chooses where it lands.
107
+
108
+ Args:
109
+ dest: The raw ``dest`` attribute value, before variable expansion.
110
+
111
+ Returns:
112
+ A short reason string when *dest* escapes; None when it is safe.
113
+ """
114
+ if not dest:
115
+ return "dest is empty"
116
+ if dest.startswith("/"):
117
+ return "dest is an absolute path; it must be relative to the consumer workspace root"
118
+ if ".." in dest.split("/"):
119
+ return "dest contains a '..' component that escapes the consumer workspace"
120
+ return None
121
+
122
+
123
+ def _collect_manifest_chain(xml_path: Path, repo_root: Path) -> list[Path]:
124
+ """Return *xml_path* plus every manifest reachable through ``<include>``.
125
+
126
+ Depth-first and cycle-safe, mirroring the traversal in
127
+ :func:`validate_include_chain`. Linkfile checks must see the same set of
128
+ ``<project>`` elements that ``kanon install`` acts on, and install resolves
129
+ the full include chain -- so a ``<project>`` moved into an included
130
+ ``packages.xml`` is validated exactly like one written inline. Missing
131
+ includes are skipped here; :func:`validate_include_chain` owns that error.
132
+
133
+ Args:
134
+ xml_path: The catalog entry manifest to start from.
135
+ repo_root: Repository root used to resolve ``<include name>`` paths.
136
+
137
+ Returns:
138
+ The entry manifest followed by each reachable include, in visit order.
139
+ """
140
+ chain: list[Path] = []
141
+ visited: set[str] = set()
142
+
143
+ def _walk(current: Path) -> None:
144
+ resolved = str(current.resolve())
145
+ if resolved in visited:
146
+ return
147
+ visited.add(resolved)
148
+ chain.append(current)
149
+ try:
150
+ root = ET.parse(current).getroot()
151
+ except ET.ParseError:
152
+ return
153
+ for include in root.findall("include"):
154
+ name = include.get("name")
155
+ if not name:
156
+ continue
157
+ include_path = repo_root / name
158
+ if include_path.exists():
159
+ _walk(include_path)
160
+
161
+ _walk(xml_path)
162
+ return chain
163
+
164
+
165
+ def validate_linkfile_dest(xml_path: Path, repo_root: Path) -> list[str]:
166
+ """Validate the ``<linkfile dest>`` attributes reachable from a catalog entry.
167
+
168
+ Two rules, applied across the entry and its whole ``<include>`` chain:
169
+
170
+ 1. **Containment (every entry).** Each dest must stay inside the consumer
171
+ workspace -- see :func:`_dest_containment_error`. A dest rooted at
172
+ ``${CLAUDE_MARKETPLACES_DIR}/``, at another ``${VAR}``, or at a plain
173
+ relative path all pass. This is what the old blanket
174
+ ``${CLAUDE_MARKETPLACES_DIR}/`` prefix requirement was standing in for,
175
+ and it no longer forbids an entry from shipping non-plugin content
176
+ (shared rules, lint config, git hooks) next to a Claude plugin.
177
+
178
+ 2. **A marketplace entry that uses linkfiles points one at the marketplace.**
179
+ When the entry declares ``<catalog-metadata><type>claude-marketplace</type>``
180
+ -- the same field ``kanon add`` reads to set
181
+ ``KANON_SOURCE_<alias>_MARKETPLACE`` -- and declares at least one
182
+ ``<linkfile>``, one of those dests must sit under
183
+ ``${CLAUDE_MARKETPLACES_DIR}/``. Otherwise the entry calls itself a
184
+ marketplace while every link it creates lands somewhere else.
185
+
186
+ An entry that declares **no** ``<linkfile>`` at all is exempt, because
187
+ that is the direct-checkout shape:
188
+ :func:`kanon_cli.core.marketplace.register_direct_checkout_marketplaces`
189
+ registers a project whose checkout carries
190
+ ``.claude-plugin/marketplace.json`` and which has no ``<linkfile>``
191
+ children. Requiring a marketplace dest there would reject an entry that
192
+ ``kanon install`` registers correctly -- the same validator/install
193
+ contradiction this function exists to remove, aimed at a different entry
194
+ shape. The catalog XML alone cannot prove that checkout carries a
195
+ ``marketplace.json``, so the absence of linkfiles is the only signal
196
+ available here and validation defers to install rather than guessing.
197
+
198
+ An entry of any other type, or with no ``<type>``, carries no such
199
+ requirement.
200
+
201
+ Errors are de-duplicated before returning. A ``<project>`` reached through
202
+ ``<include>`` is visited once per entry that includes it, so a single
203
+ defect in a shared include would otherwise be reported once per consumer.
204
+
205
+ Args:
206
+ xml_path: Path to the catalog entry manifest.
207
+ repo_root: Repository root used to resolve ``<include name>`` paths.
59
208
 
60
209
  Returns:
61
- List of error messages. Empty if all dest attributes are valid.
62
- Each error identifies the file, project name, and invalid dest.
210
+ List of error messages, each naming the file, project, and dest,
211
+ in first-seen order with duplicates removed. Empty when the entry
212
+ passes.
63
213
  """
64
214
  errors: list[str] = []
65
- tree = ET.parse(xml_path)
66
- root = tree.getroot()
215
+ is_marketplace = read_entry_type(xml_path) == CATALOG_TYPE_CLAUDE_MARKETPLACE
216
+ linkfile_count = 0
217
+ marketplace_dest_count = 0
67
218
 
68
- for project in root.findall("project"):
69
- project_name = project.get("name", "<unknown>")
70
- for linkfile in project.findall("linkfile"):
71
- dest = linkfile.get("dest", "")
72
- if not dest.startswith(MARKETPLACE_DIR_PREFIX):
73
- errors.append(
74
- f"{xml_path}: project '{project_name}' has "
75
- f"invalid linkfile dest='{dest}' -- "
76
- f"must start with {MARKETPLACE_DIR_PREFIX}"
77
- )
219
+ for manifest_path in _collect_manifest_chain(xml_path, repo_root):
220
+ try:
221
+ root = ET.parse(manifest_path).getroot()
222
+ except ET.ParseError:
223
+ continue
224
+ for project in root.findall("project"):
225
+ project_name = project.get("name", "<unknown>")
226
+ for linkfile in project.findall("linkfile"):
227
+ linkfile_count += 1
228
+ dest = linkfile.get("dest", "")
229
+ if dest.startswith(MARKETPLACE_DIR_PREFIX):
230
+ marketplace_dest_count += 1
231
+ continue
232
+ reason = _dest_containment_error(dest)
233
+ if reason is not None:
234
+ errors.append(
235
+ f"{manifest_path}: project '{project_name}' has invalid linkfile dest='{dest}' -- {reason}"
236
+ )
237
+
238
+ if is_marketplace and linkfile_count > 0 and marketplace_dest_count == 0:
239
+ errors.append(
240
+ f"{xml_path}: entry declares "
241
+ f"<catalog-metadata><type>{CATALOG_TYPE_CLAUDE_MARKETPLACE}</type> "
242
+ f"and declares <linkfile> elements, but none target "
243
+ f"{MARKETPLACE_DIR_PREFIX} -- such an entry registers no marketplace. "
244
+ f"Point one linkfile at {MARKETPLACE_DIR_PREFIX}, change <type> to a "
245
+ f"non-marketplace value, or drop the linkfiles to register the "
246
+ f"project as a direct checkout."
247
+ )
78
248
 
79
- return errors
249
+ return list(dict.fromkeys(errors))
80
250
 
81
251
 
82
252
  def validate_include_chain(
@@ -593,12 +763,20 @@ def validate_marketplace(
593
763
  """Validate all marketplace XML files found under repo-specs/.
594
764
 
595
765
  Scans for catalog entry manifests (``*.xml`` with a ``<catalog-metadata>``
596
- block) and validates each one for linkfile dest attributes, include chain
597
- integrity, project path uniqueness, pinnable ``<project revision>`` format
598
- (a deep-path tag, a ``refs/heads/<name>`` branch ref, or a 40-hex SHA;
599
- covering revisions inherited from ``<default revision>``), and two-tier +
600
- local-aware revision existence. Exits with a non-zero code if any validation
601
- errors are found.
766
+ block) and validates each one for linkfile dest containment (plus the
767
+ marketplace-dest rule for ``claude-marketplace`` entries that use
768
+ linkfiles), include chain integrity, project path uniqueness, pinnable
769
+ ``<project revision>`` format (a deep-path tag, a ``refs/heads/<name>``
770
+ branch ref, or a 40-hex SHA; covering revisions inherited from
771
+ ``<default revision>``), and two-tier + local-aware revision existence.
772
+ Exits with a non-zero code if any validation errors are found.
773
+
774
+ Errors are de-duplicated across the whole run before reporting. Linkfile
775
+ and include checks follow each entry's ``<include>`` chain, so a defect in
776
+ a manifest shared by several entries is reached once per entry; reporting
777
+ it once per consumer would inflate the count and bury the distinct
778
+ failures. Identical message text means the same file, project, and reason,
779
+ so collapsing exact duplicates cannot hide a second real defect.
602
780
 
603
781
  Args:
604
782
  repo_root: Repository root directory.
@@ -626,13 +804,15 @@ def validate_marketplace(
626
804
  for xml_file in marketplace_files:
627
805
  rel_path = xml_file.relative_to(repo_root)
628
806
  print(f"Validating {rel_path}...")
629
- all_errors.extend(validate_linkfile_dest(xml_file))
807
+ all_errors.extend(validate_linkfile_dest(xml_file, repo_root))
630
808
  all_errors.extend(validate_include_chain(xml_file, repo_root))
631
809
 
632
810
  all_errors.extend(validate_name_uniqueness(marketplace_files))
633
811
  all_errors.extend(validate_tag_format(marketplace_files, repo_root))
634
812
  all_errors.extend(validate_revision_existence(marketplace_files, repo_root, effective_env, runner))
635
813
 
814
+ all_errors = list(dict.fromkeys(all_errors))
815
+
636
816
  if all_errors:
637
817
  print(
638
818
  f"\nFound {len(all_errors)} validation error(s):",