hyperi-ci 2.2.0__tar.gz → 2.2.1__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 (222) hide show
  1. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/CHANGELOG.md +9 -0
  2. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/PKG-INFO +1 -1
  3. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/STATE.md +31 -0
  4. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/TODO.md +46 -4
  5. hyperi_ci-2.2.1/VERSION +1 -0
  6. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/docs/ARCHITECTURE.md +17 -0
  7. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/cli.py +13 -1
  8. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/gh.py +6 -0
  9. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/init.py +8 -1
  10. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/watch.py +31 -19
  11. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/integration/test_rust_build_optimize.py +8 -5
  12. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_init.py +17 -0
  13. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_watch.py +36 -0
  14. hyperi_ci-2.2.0/VERSION +0 -1
  15. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/.ai-version +0 -0
  16. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/commands/doco.md +0 -0
  17. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/commands/load.md +0 -0
  18. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/commands/review.md +0 -0
  19. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/commands/save.md +0 -0
  20. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/commands/setup-claude.md +0 -0
  21. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/commands/simplify.md +0 -0
  22. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/commands/standards.md +0 -0
  23. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/UNIVERSAL.md +0 -0
  24. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/ai-conduct.md +0 -0
  25. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/ansible.md +0 -0
  26. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/bash.md +0 -0
  27. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/chars-policy.md +0 -0
  28. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/ci.md +0 -0
  29. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/clickhouse-sql.md +0 -0
  30. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/code-header.md +0 -0
  31. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/code-style.md +0 -0
  32. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/config-and-logging.md +0 -0
  33. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/cpp.md +0 -0
  34. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/design-principles.md +0 -0
  35. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/dfe-metrics.md +0 -0
  36. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/docker.md +0 -0
  37. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/error-handling.md +0 -0
  38. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/git.md +0 -0
  39. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/golang.md +0 -0
  40. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/issue-management.md +0 -0
  41. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/k8s.md +0 -0
  42. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/licensing.md +0 -0
  43. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/mocks-policy.md +0 -0
  44. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/pki.md +0 -0
  45. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/python.md +0 -0
  46. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/repo-naming.md +0 -0
  47. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/rust.md +0 -0
  48. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/security.md +0 -0
  49. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/sql-clickhouse.md +0 -0
  50. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/terraform.md +0 -0
  51. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/testing.md +0 -0
  52. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/typescript.md +0 -0
  53. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/rules/universal.md +0 -0
  54. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/settings.json +0 -0
  55. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/skills/ai-common/SKILL.md +0 -0
  56. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/skills/ai-guidelines/SKILL.md +0 -0
  57. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/skills/bleeding-edge/SKILL.md +0 -0
  58. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/skills/ci-check/SKILL.md +0 -0
  59. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/skills/ci-logs/SKILL.md +0 -0
  60. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/skills/ci-watch/SKILL.md +0 -0
  61. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/skills/deps/SKILL.md +0 -0
  62. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/skills/docs-audit/SKILL.md +0 -0
  63. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/skills/documentation/SKILL.md +0 -0
  64. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/skills/python/SKILL.md +0 -0
  65. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/skills/release/SKILL.md +0 -0
  66. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/skills/standards/SKILL.md +0 -0
  67. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/skills/test-review/SKILL.md +0 -0
  68. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.claude/skills/verification/SKILL.md +0 -0
  69. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.gitattributes +0 -0
  70. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.github/actions/predict-version/action.yml +0 -0
  71. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.github/workflows/_release-tail.yml +0 -0
  72. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.github/workflows/ci.yml +0 -0
  73. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.github/workflows/go-ci.yml +0 -0
  74. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.github/workflows/python-ci.yml +0 -0
  75. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.github/workflows/rust-ci.yml +0 -0
  76. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.github/workflows/ts-ci.yml +0 -0
  77. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.gitignore +0 -0
  78. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.gitmodules +0 -0
  79. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.hyperi-ci.yaml +0 -0
  80. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.mcp.json +0 -0
  81. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/.releaserc.yaml +0 -0
  82. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/AI-TRAINING-POLICY.md +0 -0
  83. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/CLAUDE.md +0 -0
  84. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/LICENSE +0 -0
  85. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/README.md +0 -0
  86. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/config/commit-types.yaml +0 -0
  87. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/config/org.yaml +0 -0
  88. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/config/runners.yaml +0 -0
  89. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/config/secrets-access.yaml +0 -0
  90. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/config/versions.yaml +0 -0
  91. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/docs/ARC-RUNNERS.md +0 -0
  92. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/docs/CI-LESSONS.md +0 -0
  93. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/docs/DESIGN.md +0 -0
  94. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/docs/JFROG-MIGRATION.md +0 -0
  95. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/docs/MIGRATION-GUIDE.md +0 -0
  96. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/docs/PGO-WORKLOAD-GUIDE.md +0 -0
  97. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/docs/deployment-contract.md +0 -0
  98. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/docs/migration/deployment-contract-tier3.md +0 -0
  99. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/docs/rust.md +0 -0
  100. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/docs/typescript.md +0 -0
  101. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/pyproject.toml +0 -0
  102. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/renovate.json +0 -0
  103. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/robots.txt +0 -0
  104. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/scripts/pre-commit-versions.sh +0 -0
  105. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/scripts/setup-rust-dev.py +0 -0
  106. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/scripts/sync-secrets-access.py +0 -0
  107. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/scripts/update-versions.py +0 -0
  108. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/__init__.py +0 -0
  109. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/common.py +0 -0
  110. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/config/defaults.yaml +0 -0
  111. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/config/native-deps/golang.yaml +0 -0
  112. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/config/native-deps/python.yaml +0 -0
  113. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/config/native-deps/rust.yaml +0 -0
  114. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/config/native-deps/typescript.yaml +0 -0
  115. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/config/org.yaml +0 -0
  116. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/config/toolchains/gcc.yaml +0 -0
  117. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/config/toolchains/llvm.yaml +0 -0
  118. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/config.py +0 -0
  119. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/container/__init__.py +0 -0
  120. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/container/binary_stage.py +0 -0
  121. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/container/build.py +0 -0
  122. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/container/compose.py +0 -0
  123. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/container/detect.py +0 -0
  124. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/container/labels.py +0 -0
  125. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/container/manifest.py +0 -0
  126. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/container/registry.py +0 -0
  127. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/container/stage.py +0 -0
  128. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/container/templates.py +0 -0
  129. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/deployment/__init__.py +0 -0
  130. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/deployment/cli.py +0 -0
  131. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/deployment/contract.py +0 -0
  132. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/deployment/detect.py +0 -0
  133. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/deployment/registry.py +0 -0
  134. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/deployment/scaffold.py +0 -0
  135. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/deployment/stage.py +0 -0
  136. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/detect.py +0 -0
  137. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/dispatch.py +0 -0
  138. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/install_deps.py +0 -0
  139. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/__init__.py +0 -0
  140. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/_build_common.py +0 -0
  141. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/golang/__init__.py +0 -0
  142. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/golang/build.py +0 -0
  143. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/golang/publish.py +0 -0
  144. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/golang/quality.py +0 -0
  145. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/golang/test.py +0 -0
  146. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/python/__init__.py +0 -0
  147. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/python/build.py +0 -0
  148. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/python/publish.py +0 -0
  149. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/python/quality.py +0 -0
  150. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/python/test.py +0 -0
  151. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/quality_common.py +0 -0
  152. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/rust/__init__.py +0 -0
  153. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/rust/build.py +0 -0
  154. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/rust/optimize.py +0 -0
  155. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/rust/pgo.py +0 -0
  156. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/rust/publish.py +0 -0
  157. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/rust/quality.py +0 -0
  158. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/rust/test.py +0 -0
  159. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/typescript/__init__.py +0 -0
  160. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/typescript/_common.py +0 -0
  161. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/typescript/build.py +0 -0
  162. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/typescript/install_deps.py +0 -0
  163. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/typescript/publish.py +0 -0
  164. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/typescript/quality.py +0 -0
  165. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/languages/typescript/test.py +0 -0
  166. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/logs.py +0 -0
  167. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/migrate.py +0 -0
  168. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/native_deps.py +0 -0
  169. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/publish/__init__.py +0 -0
  170. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/publish/binaries.py +0 -0
  171. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/publish/dispatch.py +0 -0
  172. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/publish_binaries.py +0 -0
  173. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/push.py +0 -0
  174. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/quality/__init__.py +0 -0
  175. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/quality/commit_validation.py +0 -0
  176. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/quality/gitleaks.py +0 -0
  177. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/release.py +0 -0
  178. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/trigger.py +0 -0
  179. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/src/hyperi_ci/upgrade.py +0 -0
  180. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/templates/pgo-workload/README.md +0 -0
  181. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/templates/pgo-workload/grpc-server.sh +0 -0
  182. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/templates/pgo-workload/http-server.sh +0 -0
  183. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/templates/pgo-workload/kafka-consumer.sh +0 -0
  184. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/templates/pgo-workload/kafka-producer.sh +0 -0
  185. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/templates/pgo-workload/multi-protocol.sh +0 -0
  186. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/__init__.py +0 -0
  187. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/integration/__init__.py +0 -0
  188. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/__init__.py +0 -0
  189. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/deployment/__init__.py +0 -0
  190. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/deployment/test_contract.py +0 -0
  191. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/deployment/test_detect_tier.py +0 -0
  192. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/deployment/test_emit_artefacts_cli.py +0 -0
  193. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/deployment/test_registry_cascade.py +0 -0
  194. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/deployment/test_scaffold.py +0 -0
  195. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/deployment/test_stage.py +0 -0
  196. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_cli.py +0 -0
  197. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_commit_validation.py +0 -0
  198. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_common.py +0 -0
  199. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_config.py +0 -0
  200. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_container_binary_stage.py +0 -0
  201. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_container_build.py +0 -0
  202. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_container_compose.py +0 -0
  203. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_container_detect.py +0 -0
  204. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_container_labels.py +0 -0
  205. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_container_manifest.py +0 -0
  206. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_container_registry.py +0 -0
  207. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_container_stage.py +0 -0
  208. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_container_templates.py +0 -0
  209. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_detect.py +0 -0
  210. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_dispatch_alias.py +0 -0
  211. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_gh.py +0 -0
  212. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_migrate.py +0 -0
  213. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_native_deps.py +0 -0
  214. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_publish.py +0 -0
  215. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_push.py +0 -0
  216. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_rust_optimize.py +0 -0
  217. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_rust_pgo.py +0 -0
  218. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_rust_quality.py +0 -0
  219. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_typescript_quality.py +0 -0
  220. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_upgrade.py +0 -0
  221. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/tests/unit/test_workflow_consistency.py +0 -0
  222. {hyperi_ci-2.2.0 → hyperi_ci-2.2.1}/uv.lock +0 -0
@@ -1,3 +1,12 @@
1
+ ## [2.2.1](https://github.com/hyperi-io/hyperi-ci/compare/v2.2.0...v2.2.1) (2026-05-08)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **init:** scaffold ci.yml with tag input on workflow_dispatch ([e6f7470](https://github.com/hyperi-io/hyperi-ci/commit/e6f7470c827ee8013db5ae2ed9b0af27c0226d93))
7
+ * **test:** align spike-channel allocator test with current jemalloc-everywhere policy ([9de19e4](https://github.com/hyperi-io/hyperi-ci/commit/9de19e4a3d897b44caf0c586f5548443c1b8015d))
8
+ * **watch:** accept --repo flag for cross-repo run watching ([378dea3](https://github.com/hyperi-io/hyperi-ci/commit/378dea37b86f7d3c3ca508233c57a9058ee28cdb))
9
+
1
10
  # [2.2.0](https://github.com/hyperi-io/hyperi-ci/compare/v2.1.6...v2.2.0) (2026-05-08)
2
11
 
3
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperi-ci
3
- Version: 2.2.0
3
+ Version: 2.2.1
4
4
  Summary: HyperI CI/CD CLI tool — multi-language build, test, and publish automation
5
5
  License: Proprietary
6
6
  License-File: LICENSE
@@ -157,6 +157,16 @@ PR review and release-worthy pushes run them. The gate is computed
157
157
  ONCE in the `plan` job and consumed by every downstream job; do not
158
158
  re-implement the condition string elsewhere — `tests/unit/test_workflow_consistency.py` enforces this.
159
159
 
160
+ ## CI bug-log convention (cross-repo)
161
+
162
+ CI bugs and fixes surfaced in consumer repos are logged under
163
+ `<consumer>/docs/superpowers/plans/<date>-ci-<topic>.md` (gitignored
164
+ local-only) plus a one-line entry in that consumer's `TODO.md`.
165
+ This is the SSoT location for CI fixes across the org — when canary
166
+ runs surface bugs, look there for the resolution status. The
167
+ hyperi-ci rollout doc references back to those plans so the loop
168
+ is closeable.
169
+
160
170
  ## Architecture
161
171
 
162
172
  See `docs/DESIGN.md` for full architecture documentation.
@@ -332,6 +342,27 @@ See `docs/MIGRATION-GUIDE.md` for migrating projects from v1 to v2.
332
342
  - **dfe-protocol-sdk** — plugin system removed
333
343
  - **dfe-receiver-plugin-syslog** — syslog is built-in transport
334
344
 
345
+ ## Future direction (aspirational)
346
+
347
+ Today: GitHub for git hosting, GitHub Actions for CI. Likely move when
348
+ budget and time allow:
349
+
350
+ - **Codeberg** for git hosting — reduce single-vendor lock-in to GitHub.
351
+ - **Buildkite** for CI — stronger pipeline ergonomics, self-hosted
352
+ runners without ARC's K8s overhead.
353
+
354
+ Design implications today:
355
+
356
+ - CI logic stays in the `hyperi-ci` Python CLI, not embedded in
357
+ workflow YAML. Buildkite (or any successor) calls the same CLI;
358
+ only the runner glue changes.
359
+ - Workflows stay thin — plan job + gates + handler dispatch.
360
+ - Avoid hard dependencies on GitHub-only features in handler code
361
+ (Actions-specific matrix syntax, GHCR-only auth flows).
362
+
363
+ Not on the near-term roadmap; recorded so we don't accidentally make
364
+ choices that paint us into the GitHub-Actions corner.
365
+
335
366
  ## Licensing
336
367
 
337
368
  Proprietary — HYPERI PTY LIMITED.
@@ -20,9 +20,14 @@ This is the **single source of truth** for all tasks and progress.
20
20
 
21
21
  **Canaries (no SEP fields — fix bugs found, don't dismiss):**
22
22
 
23
- - [ ] **Canary 0: hyperi-ci's own `test-projects/`** — `ci-test-python-app`, `ci-test-go-app`, `ci-test-ts-app` drives the iteration loop in-repo via `tests/integration/`.
24
- - [ ] **Canary 1: dfe-loader (Rust)** — most complex Rust example: clickhouse-driver, Arrow, columnar deps. Must produce a tagged R2 + GHCR + GH Release artefact under the new shape, AND a chore: bump must skip build entirely.
25
- - [ ] **Canary 2: dfe-engine (Python)** — most complex Python example. Same exit criteria.
23
+ - [x] **Canary 0: hyperi-ci's own `test-projects/`** — integration tests green; one stale spike-allocator test fixed (commit `a331a0b`).
24
+ - [x] **Canary 1a: dfe-loader chore-skip** — [run 25531398891](https://github.com/hyperi-io/dfe-loader/actions/runs/25531398891) 16 seconds total, plan ✅, every other job skipped. **Killer feature validated.**
25
+ - [ ] **Canary 1b: dfe-loader publish-dispatch** — [run 25531808212](https://github.com/hyperi-io/dfe-loader/actions/runs/25531808212) in flight as of 2026-05-08T01:40Z. Plan/Quality/Test green; both Build (linux-amd64, linux-arm64) jobs in_progress. BOLT/PGO; expect 30-45 min.
26
+ - [x] **Canary 2a: dfe-engine chore-skip** — [run 25531462469](https://github.com/hyperi-io/dfe-engine/actions/runs/25531462469) — 33 seconds, all heavy jobs skipped. **Gate validated.**
27
+ - [ ] **Canary 2b: dfe-engine publish-dispatch** — failed at quality stage on real pre-existing CVEs (pytest, cryptography). NOT a gate regression. Handed back to dfe-engine maintainers via [`dfe-engine/docs/superpowers/plans/2026-05-08-ci-canary-publish-fix.md`](../../dfe-engine/docs/superpowers/plans/2026-05-08-ci-canary-publish-fix.md). Blocked on merge coordination (Derek + Kaz have WIP on `feat/transport-filter-helpers`).
28
+ - [ ] **Canary 3 (added 2026-05-08): hyperi-pylib publish-dispatch** — preferred Python canary now: clean lib, no parallel WIP. User to drive.
29
+
30
+ **Ordering update 2026-05-08:** Python canary order is hyperi-pylib FIRST (clean), then dfe-engine after merge coordination. dfe-engine is the most complex Python case but its current branch state makes it a poor first canary.
26
31
 
27
32
  **Done means:**
28
33
 
@@ -32,7 +37,44 @@ This is the **single source of truth** for all tasks and progress.
32
37
  - A `Publish: true` commit on each canary still runs the full pipeline and ships to the right registries
33
38
  - v2.2.0+ of hyperi-ci is published to PyPI
34
39
 
35
- **Bugs discovered during rollout (no SEP fields):** populate as the rollout proceeds.
40
+ **Bugs discovered during rollout (no SEP fields):**
41
+
42
+ - [x] `tests/integration/test_rust_build_optimize.py::test_spike_channel_default_uses_system_allocator` encoded the old "spike → system allocator" policy; current code (and standards/rules/RUST.md Allocator Policy) says jemalloc at every channel. Fixed in commit `a331a0b`.
43
+ - [x] `_release-tail.yml` expects a single `build-dist-*` artifact containing both `dist/` AND `ci-tmp/`. The plan's draft proposed splitting into separate artifacts which would have broken release-tail's download step. Combined-upload pattern preserved.
44
+ - [x] `ts-ci.yml` had a duplicate `setup:` job key (silent YAML override) and `test:` job missing `needs:`/`if:`. Fixed during Task 8.
45
+ - [x] `go-ci.yml` ran quality + test unconditionally before any gate decision (setup ran AFTER them). Fixed during Task 9.
46
+
47
+ ---
48
+
49
+ ### Follow-up: dedicated CI test repos (next plan)
50
+
51
+ **Why:** in-repo `test-projects/` fixtures validate the CLI, but cannot exercise GitHub-side workflow behaviour (chore-skip, semantic-release tagging, publish flow). Real validation needs separate repos that push commits and trigger real CI runs.
52
+
53
+ **Proposed minimum:**
54
+
55
+ - `hyperi-io/ci-test-rust-app` — single-crate binary (chore-skip, R2 + GH Release path)
56
+ - `hyperi-io/ci-test-rust-workspace` — 3-crate workspace (workspace version stamp)
57
+ - `hyperi-io/ci-test-python-pypi` — Python lib for PyPI (sdist clean)
58
+ - `hyperi-io/ci-test-python-app` — Python container app (Tier-3 deployment-contract path)
59
+ - `hyperi-io/ci-test-ts-app` — TypeScript bundle (npm publish)
60
+ - `hyperi-io/ci-test-go-app` — Go binary (cross-compile, GH Release)
61
+
62
+ **Status:** scoped only — needs its own plan written. Track separately when we pick this up.
63
+
64
+ ---
65
+
66
+ ### Follow-up: deployment artefact distribution (next plan)
67
+
68
+ **Why:** `hyperi-ci run generate` produces `argocd-application.yaml`, `chart/` (Helm), `Dockerfile.runtime`, `container-manifest.json`. These get uploaded as a CI artifact and then... dropped on the floor. `_release-tail.yml` consumes only the container-manifest. ArgoCD operators have no consumable distribution path.
69
+
70
+ **Proposed:**
71
+
72
+ - Helm `chart/` → push to GHCR as OCI artifact (`oci://ghcr.io/hyperi-io/charts/<app>:vX.Y.Z`); ArgoCD ≥2.6 reads OCI natively
73
+ - `argocd-application.yaml` → PR into a `hyperi-io/gitops` cluster-config repo via GitHub App with `contents:write`
74
+ - Versioning: chart version === app version === `next-version` from plan output
75
+ - NOT R2 — Helm and ArgoCD don't read from R2; would need to reinvent chart-museum
76
+
77
+ **Status:** scoped only — needs its own plan written. Out of scope for the KISS consolidation.
36
78
 
37
79
  ---
38
80
 
@@ -0,0 +1 @@
1
+ 2.2.1
@@ -154,6 +154,23 @@ workflows.
154
154
  - ["GitHub Actions Is Slowly Killing Your Engineering Team"](https://www.iankduncan.com/engineering/2026-02-05-github-actions-killing-your-team/) — explicit warning against generic-abstraction-layer reusable workflows
155
155
  - [Composite-action path resolution discussion #26245](https://github.com/orgs/community/discussions/26245) — confirms the cross-repo `./` problem is unsolved as of May 2026
156
156
 
157
+ ## Future portability (aspirational)
158
+
159
+ We may move from GitHub + GitHub Actions to Codeberg (git) +
160
+ Buildkite (CI) when budget and time allow. Not on the near-term
161
+ roadmap, but it shapes design today:
162
+
163
+ - The `hyperi-ci` Python CLI owns the work — quality, test, build,
164
+ publish. The reusable workflows are thin runner glue around it.
165
+ Porting to Buildkite means rewriting the glue, not the CLI.
166
+ - Handler code (`src/hyperi_ci/languages/<lang>/*.py`) avoids
167
+ GitHub-only assumptions: no `${{ ... }}` template syntax leaking
168
+ into Python, no GHCR-only auth flows hardcoded in publish handlers.
169
+ - The plan job + gate-output pattern translates directly to
170
+ Buildkite's dynamic pipelines.
171
+
172
+ The shared CI tool keeps the cost of switching CI vendors bounded.
173
+
157
174
  ## Pre-2026-05-08 archaeology
158
175
 
159
176
  Before this consolidation, `_setup.yml` existed as a shared first-job
@@ -424,11 +424,23 @@ def watch(
424
424
  int,
425
425
  typer.Option("--interval", "-i", help="Initial poll interval in seconds"),
426
426
  ] = 30,
427
+ repo: Annotated[
428
+ str | None,
429
+ typer.Option(
430
+ "--repo",
431
+ "-R",
432
+ help=(
433
+ "Target repo as owner/name (e.g. hyperi-io/dfe-loader). "
434
+ "Defaults to the cwd's git remote — set this when watching "
435
+ "a run in a different repo than your cwd."
436
+ ),
437
+ ),
438
+ ] = None,
427
439
  ) -> None:
428
440
  """Watch a GitHub Actions run to completion."""
429
441
  from hyperi_ci.watch import watch_run
430
442
 
431
- rc = watch_run(run_id=run_id, timeout=timeout, interval=interval)
443
+ rc = watch_run(run_id=run_id, timeout=timeout, interval=interval, repo=repo)
432
444
  raise typer.Exit(rc)
433
445
 
434
446
 
@@ -91,18 +91,24 @@ def gh_json(
91
91
  def get_latest_run(
92
92
  branch: str | None = None,
93
93
  workflow: str | None = None,
94
+ repo: str | None = None,
94
95
  ) -> dict | None:
95
96
  """Find the most recent workflow run.
96
97
 
97
98
  Args:
98
99
  branch: Filter by branch name.
99
100
  workflow: Filter by workflow filename.
101
+ repo: Optional ``owner/name`` — when set, queries this repo
102
+ instead of the cwd's git remote. Use this when looking up
103
+ runs in a different repo than your cwd.
100
104
 
101
105
  Returns:
102
106
  Dict with run info, or None if no runs found.
103
107
 
104
108
  """
105
109
  args = ["run", "list", "--limit", "1"]
110
+ if repo:
111
+ args.extend(["--repo", repo])
106
112
  if branch:
107
113
  args.extend(["--branch", branch])
108
114
  if workflow:
@@ -261,15 +261,22 @@ def _render_workflow(
261
261
  " pull_request:\n"
262
262
  " branches: [main]\n"
263
263
  " workflow_dispatch:\n"
264
+ " inputs:\n"
265
+ " tag:\n"
266
+ " type: string\n"
267
+ " required: true\n"
268
+ ' description: "Tag to publish (e.g. v1.3.0)"\n'
264
269
  "\n"
265
270
  "jobs:\n"
266
271
  " ci:\n"
267
272
  f" uses: {_CI_REPO}/.github/workflows/"
268
273
  f"{workflow_file}@{_WORKFLOW_REF}\n"
274
+ " with:\n"
275
+ " tag: ${{ inputs.tag || '' }}\n"
269
276
  )
270
277
 
271
278
  if publish_target != "internal":
272
- base += f" with:\n publish-target: {publish_target}\n"
279
+ base += f" publish-target: {publish_target}\n"
273
280
 
274
281
  base += " secrets: inherit\n"
275
282
  return base
@@ -67,11 +67,16 @@ def _poll_interval(base: int, attempt: int) -> float:
67
67
  return min(base * (1.5 ** min(attempt - 1, 4)), 120.0)
68
68
 
69
69
 
70
- def _get_run_status(run_id: str) -> dict | None:
70
+ def _get_run_status(run_id: str, repo: str | None = None) -> dict | None:
71
71
  """Fetch current run status.
72
72
 
73
73
  Args:
74
74
  run_id: Workflow run ID.
75
+ repo: Optional ``owner/name`` — pass this when watching a run
76
+ in a different repo than the current working directory.
77
+ ``gh run view`` defaults to the cwd's git remote and
78
+ silently 404s when the run isn't there, which the watch
79
+ loop misreads as transient network failure.
75
80
 
76
81
  Returns:
77
82
  Dict with status/conclusion/jobs, or None on transient error.
@@ -82,26 +87,28 @@ def _get_run_status(run_id: str) -> dict | None:
82
87
  `_MAX_CONSECUTIVE_FETCH_FAILURES`.
83
88
 
84
89
  """
90
+ args = [
91
+ "run",
92
+ "view",
93
+ run_id,
94
+ "--json",
95
+ "status,conclusion,jobs,url,workflowName,headBranch",
96
+ ]
97
+ if repo:
98
+ args.extend(["--repo", repo])
85
99
  try:
86
- result = gh_run(
87
- [
88
- "run",
89
- "view",
90
- run_id,
91
- "--json",
92
- "status,conclusion,jobs,url,workflowName,headBranch",
93
- ]
94
- )
100
+ result = gh_run(args)
95
101
  return json.loads(result.stdout)
96
102
  except (subprocess.CalledProcessError, json.JSONDecodeError):
97
103
  return None
98
104
 
99
105
 
100
- def _resume_command(run_id: str, timeout: int) -> str:
106
+ def _resume_command(run_id: str, timeout: int, repo: str | None = None) -> str:
101
107
  """Format a copy-pasteable resume command for the user."""
108
+ repo_arg = f" --repo {repo}" if repo else ""
102
109
  if timeout == 0:
103
- return f"hyperi-ci watch {run_id} --timeout 0"
104
- return f"hyperi-ci watch {run_id} --timeout {timeout}"
110
+ return f"hyperi-ci watch {run_id}{repo_arg} --timeout 0"
111
+ return f"hyperi-ci watch {run_id}{repo_arg} --timeout {timeout}"
105
112
 
106
113
 
107
114
  def _print_summary(run_data: dict) -> None:
@@ -146,6 +153,7 @@ def watch_run(
146
153
  run_id: str | None = None,
147
154
  timeout: int = _DEFAULT_TIMEOUT,
148
155
  interval: int = 30,
156
+ repo: str | None = None,
149
157
  ) -> int:
150
158
  """Watch a GitHub Actions run to completion.
151
159
 
@@ -155,6 +163,9 @@ def watch_run(
155
163
  (poll until the run reaches a terminal state). Default is
156
164
  sized for Tier 2 Rust builds (3600 s = 60 min).
157
165
  interval: Base poll interval in seconds.
166
+ repo: Optional ``owner/name`` — when set, all gh calls target
167
+ this repo instead of the cwd's git remote. Use this when
168
+ watching a run in a different repo than your cwd.
158
169
 
159
170
  Returns:
160
171
  Exit code: 0=success, 1=failed/cancelled/unreachable, 2=timeout.
@@ -170,16 +181,17 @@ def watch_run(
170
181
  return 1
171
182
 
172
183
  info(f"Finding latest run on {branch}...")
173
- latest = get_latest_run(branch=branch)
184
+ latest = get_latest_run(branch=branch, repo=repo)
174
185
  if not latest:
175
186
  error(f"No runs found on {branch}")
176
187
  return 1
177
188
  run_id = str(latest["databaseId"])
178
189
 
190
+ repo_label = f" in {repo}" if repo else ""
179
191
  if timeout == 0:
180
- info(f"Watching run {run_id} (no timeout)")
192
+ info(f"Watching run {run_id}{repo_label} (no timeout)")
181
193
  else:
182
- info(f"Watching run {run_id} (timeout: {timeout}s)")
194
+ info(f"Watching run {run_id}{repo_label} (timeout: {timeout}s)")
183
195
 
184
196
  # `deadline = None` disables the timeout check entirely.
185
197
  deadline: float | None = None if timeout == 0 else time.monotonic() + timeout
@@ -192,7 +204,7 @@ def watch_run(
192
204
  now = datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
193
205
  info(f" [{now}] polling (attempt {attempt})...")
194
206
 
195
- run_data = _get_run_status(run_id)
207
+ run_data = _get_run_status(run_id, repo=repo)
196
208
  if not run_data:
197
209
  consecutive_failures += 1
198
210
  if consecutive_failures >= _MAX_CONSECUTIVE_FETCH_FAILURES:
@@ -200,7 +212,7 @@ def watch_run(
200
212
  f" Failed to fetch run status "
201
213
  f"{consecutive_failures} times in a row — giving up. "
202
214
  f"Last known status: {last_known_status}. "
203
- f"Resume: {_resume_command(run_id, timeout)}"
215
+ f"Resume: {_resume_command(run_id, timeout, repo=repo)}"
204
216
  )
205
217
  return 1
206
218
  warn(
@@ -232,7 +244,7 @@ def watch_run(
232
244
  # in progress) or investigate (stuck / silently failing).
233
245
  error(
234
246
  f"Timeout after {timeout} seconds — run still {last_known_status}. "
235
- f"Resume: {_resume_command(run_id, timeout)} "
247
+ f"Resume: {_resume_command(run_id, timeout, repo=repo)} "
236
248
  f"(or use --timeout 0 to disable timeout)"
237
249
  )
238
250
  return 2
@@ -309,22 +309,25 @@ class TestChannelToBinaryFlow:
309
309
  binary = tmp_path / "target" / "release" / "fixture-bin"
310
310
  assert _nm_has_symbol(binary, "je_")
311
311
 
312
- def test_spike_channel_default_uses_system_allocator(self, tmp_path) -> None:
313
- # spike channel should default to system allocator — no jemalloc.
312
+ def test_spike_channel_default_uses_jemalloc(self, tmp_path) -> None:
313
+ # standards/rules/RUST.md "Allocator Policy" DFE Rust binaries
314
+ # use jemalloc at EVERY channel for tooling consistency
315
+ # (jeprof works on every binary from day one). spike still gets
316
+ # thin LTO, but allocator is jemalloc.
314
317
  _write_fixture_crate(
315
318
  tmp_path,
316
- with_jemalloc_feature=True, # Available but not selected
319
+ with_jemalloc_feature=True,
317
320
  wire_global_allocator=True,
318
321
  )
319
322
 
320
323
  profile = resolve_optimization_profile("spike", None)
321
- assert profile.allocator == "system"
324
+ assert profile.allocator == "jemalloc"
322
325
 
323
326
  result = _run_cargo_build(tmp_path, profile)
324
327
  assert result.returncode == 0
325
328
 
326
329
  binary = tmp_path / "target" / "release" / "fixture-bin"
327
- assert not _nm_has_symbol(binary, "je_malloc")
330
+ assert _nm_has_symbol(binary, "je_")
328
331
 
329
332
 
330
333
  @pytest.mark.skipif(not CARGO_AVAILABLE, reason="cargo not installed")
@@ -55,6 +55,23 @@ class TestRenderTemplates:
55
55
  content = _render_workflow("my-project", "rust-ci.yml")
56
56
  assert "secrets: inherit" in content
57
57
 
58
+ def test_workflow_dispatch_accepts_tag_input(self) -> None:
59
+ # `hyperi-ci publish vX.Y.Z` calls `gh workflow run ci.yml -f
60
+ # tag=vX.Y.Z`. Without a `tag` input on workflow_dispatch the
61
+ # GitHub API returns 422 "Unexpected inputs provided" and
62
+ # publish silently fails. Every scaffolded ci.yml must accept
63
+ # the tag input AND forward it to the language workflow.
64
+ for workflow_file in ("python-ci.yml", "rust-ci.yml", "ts-ci.yml", "go-ci.yml"):
65
+ content = _render_workflow("my-project", workflow_file)
66
+ assert "workflow_dispatch:" in content
67
+ assert "inputs:" in content, (
68
+ f"{workflow_file}: missing workflow_dispatch inputs"
69
+ )
70
+ assert "tag:" in content, f"{workflow_file}: missing tag input"
71
+ assert "tag: ${{ inputs.tag" in content, (
72
+ f"{workflow_file}: tag input not forwarded to language workflow"
73
+ )
74
+
58
75
 
59
76
  class TestDetectPythonBuildType:
60
77
  """Python build type detection from pyproject.toml."""
@@ -16,6 +16,7 @@ import pytest
16
16
  from hyperi_ci.watch import (
17
17
  _DEFAULT_TIMEOUT,
18
18
  _MAX_CONSECUTIVE_FETCH_FAILURES,
19
+ _get_run_status,
19
20
  _poll_interval,
20
21
  _resume_command,
21
22
  watch_run,
@@ -57,6 +58,41 @@ class TestResumeCommand:
57
58
  def test_with_zero_timeout(self) -> None:
58
59
  assert _resume_command("12345", 0) == "hyperi-ci watch 12345 --timeout 0"
59
60
 
61
+ def test_with_repo(self) -> None:
62
+ # When watching a run in a different repo than the cwd, the
63
+ # resume hint must include --repo so the user can copy-paste
64
+ # without re-deriving the repo from somewhere.
65
+ assert (
66
+ _resume_command("12345", 3600, repo="hyperi-io/dfe-loader")
67
+ == "hyperi-ci watch 12345 --repo hyperi-io/dfe-loader --timeout 3600"
68
+ )
69
+
70
+ def test_with_repo_and_zero_timeout(self) -> None:
71
+ assert (
72
+ _resume_command("12345", 0, repo="hyperi-io/dfe-loader")
73
+ == "hyperi-ci watch 12345 --repo hyperi-io/dfe-loader --timeout 0"
74
+ )
75
+
76
+
77
+ class TestGetRunStatusRepo:
78
+ """`_get_run_status` must forward --repo to gh when set, so watching
79
+ a run in a different repo than cwd doesn't 404 on every poll."""
80
+
81
+ def test_no_repo_omits_flag(self) -> None:
82
+ with patch("hyperi_ci.watch.gh_run") as mock_gh:
83
+ mock_gh.return_value.stdout = '{"status": "in_progress"}'
84
+ _get_run_status("12345")
85
+ args = mock_gh.call_args[0][0]
86
+ assert "--repo" not in args
87
+
88
+ def test_repo_set_appends_flag(self) -> None:
89
+ with patch("hyperi_ci.watch.gh_run") as mock_gh:
90
+ mock_gh.return_value.stdout = '{"status": "in_progress"}'
91
+ _get_run_status("12345", repo="hyperi-io/dfe-loader")
92
+ args = mock_gh.call_args[0][0]
93
+ assert "--repo" in args
94
+ assert args[args.index("--repo") + 1] == "hyperi-io/dfe-loader"
95
+
60
96
 
61
97
  class TestDefaultTimeout:
62
98
  """Default timeout is sized for Tier 2 Rust builds."""
hyperi_ci-2.2.0/VERSION DELETED
@@ -1 +0,0 @@
1
- 2.2.0
File without changes
File without changes
File without changes
File without changes