dj-digger 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. dj_digger-0.1.0/.agents/scripts/changed-files +9 -0
  2. dj_digger-0.1.0/.agents/scripts/handoff +63 -0
  3. dj_digger-0.1.0/.agents/scripts/package-check +79 -0
  4. dj_digger-0.1.0/.agents/scripts/project-env +5 -0
  5. dj_digger-0.1.0/.agents/scripts/protect-local +47 -0
  6. dj_digger-0.1.0/.agents/scripts/qa-run +144 -0
  7. dj_digger-0.1.0/.agents/scripts/qa-select +90 -0
  8. dj_digger-0.1.0/.agents/scripts/staged-check +43 -0
  9. dj_digger-0.1.0/.agents/skills/commit/SKILL.md +40 -0
  10. dj_digger-0.1.0/.agents/skills/commit/references/message-patterns.md +28 -0
  11. dj_digger-0.1.0/.agents/skills/implement/SKILL.md +40 -0
  12. dj_digger-0.1.0/.agents/skills/mr/SKILL.md +50 -0
  13. dj_digger-0.1.0/.agents/skills/mr/references/pr-description.md +24 -0
  14. dj_digger-0.1.0/.agents/skills/native-analysis/SKILL.md +40 -0
  15. dj_digger-0.1.0/.agents/skills/qa/SKILL.md +46 -0
  16. dj_digger-0.1.0/.agents/skills/runtime-proof/SKILL.md +38 -0
  17. dj_digger-0.1.0/.agents/skills/ship/SKILL.md +45 -0
  18. dj_digger-0.1.0/.agents/skills/ship/assets/report.md +19 -0
  19. dj_digger-0.1.0/.agents/skills/sqlite-change/SKILL.md +45 -0
  20. dj_digger-0.1.0/.agents/skills/task/SKILL.md +35 -0
  21. dj_digger-0.1.0/.agents/tests/simple-test.sh +4 -0
  22. dj_digger-0.1.0/.agents/tests/test-harness.sh +336 -0
  23. dj_digger-0.1.0/.claude/scripts/changed-files +1 -0
  24. dj_digger-0.1.0/.claude/scripts/handoff +1 -0
  25. dj_digger-0.1.0/.claude/scripts/package-check +1 -0
  26. dj_digger-0.1.0/.claude/scripts/project-env +1 -0
  27. dj_digger-0.1.0/.claude/scripts/protect-local +1 -0
  28. dj_digger-0.1.0/.claude/scripts/qa-run +1 -0
  29. dj_digger-0.1.0/.claude/scripts/qa-select +1 -0
  30. dj_digger-0.1.0/.claude/scripts/staged-check +1 -0
  31. dj_digger-0.1.0/.claude/settings.json +29 -0
  32. dj_digger-0.1.0/.claude/skills/implement/SKILL.md +40 -0
  33. dj_digger-0.1.0/.claude/skills/native-analysis/SKILL.md +38 -0
  34. dj_digger-0.1.0/.claude/skills/qa/SKILL.md +40 -0
  35. dj_digger-0.1.0/.claude/skills/runtime-proof/SKILL.md +38 -0
  36. dj_digger-0.1.0/.claude/skills/ship/SKILL.md +54 -0
  37. dj_digger-0.1.0/.claude/skills/sqlite-change/SKILL.md +42 -0
  38. dj_digger-0.1.0/.claude/skills/task/SKILL.md +35 -0
  39. dj_digger-0.1.0/.claude/tests/test-harness.sh +339 -0
  40. dj_digger-0.1.0/.codex/cloud/ENVIRONMENT_VERSION +1 -0
  41. dj_digger-0.1.0/.codex/cloud/check.sh +55 -0
  42. dj_digger-0.1.0/.codex/cloud/maintenance.sh +7 -0
  43. dj_digger-0.1.0/.codex/cloud/runtime-smoke.py +154 -0
  44. dj_digger-0.1.0/.codex/cloud/setup.sh +32 -0
  45. dj_digger-0.1.0/.codex/hooks/stop-protect-local +15 -0
  46. dj_digger-0.1.0/.codex/hooks.json +24 -0
  47. dj_digger-0.1.0/.docker-agent/README.md +35 -0
  48. dj_digger-0.1.0/.docker-agent/instructions/lead.md +138 -0
  49. dj_digger-0.1.0/.docker-agent/instructions/reviewer.md +23 -0
  50. dj_digger-0.1.0/.docker-agent/schemas/benchmark.schema.json +17 -0
  51. dj_digger-0.1.0/.docker-agent/schemas/review-result.schema.json +13 -0
  52. dj_digger-0.1.0/.docker-agent/schemas/task-brief.schema.json +20 -0
  53. dj_digger-0.1.0/.docker-agent/scripts/benchmark-compare +102 -0
  54. dj_digger-0.1.0/.docker-agent/scripts/change-summary +155 -0
  55. dj_digger-0.1.0/.docker-agent/scripts/codex-session-benchmark +319 -0
  56. dj_digger-0.1.0/.docker-agent/scripts/lead-qa +21 -0
  57. dj_digger-0.1.0/.docker-agent/scripts/next-plan-task +132 -0
  58. dj_digger-0.1.0/.docker-agent/scripts/qa-gate +63 -0
  59. dj_digger-0.1.0/.docker-agent/scripts/session-guard +20 -0
  60. dj_digger-0.1.0/.github/workflows/ci.yml +92 -0
  61. dj_digger-0.1.0/.github/workflows/pypi.yaml +56 -0
  62. dj_digger-0.1.0/.gitignore +13 -0
  63. dj_digger-0.1.0/AGENTS.md +140 -0
  64. dj_digger-0.1.0/CLAUDE.md +139 -0
  65. dj_digger-0.1.0/Dockerfile +17 -0
  66. dj_digger-0.1.0/PKG-INFO +769 -0
  67. dj_digger-0.1.0/README.md +755 -0
  68. dj_digger-0.1.0/compose.yaml +10 -0
  69. dj_digger-0.1.0/config/analysis.toml +30 -0
  70. dj_digger-0.1.0/config/dj-digger.example.toml +17 -0
  71. dj_digger-0.1.0/docker-agent.yaml +154 -0
  72. dj_digger-0.1.0/docs/AGENTS.md +36 -0
  73. dj_digger-0.1.0/docs/ARCHITECTURE.md +273 -0
  74. dj_digger-0.1.0/docs/CLAUDE.md +36 -0
  75. dj_digger-0.1.0/docs/docker-agent-development.md +135 -0
  76. dj_digger-0.1.0/docs/export-fields.md +215 -0
  77. dj_digger-0.1.0/docs/implementation-workflow.md +194 -0
  78. dj_digger-0.1.0/docs/mcp.md +99 -0
  79. dj_digger-0.1.0/pyproject.toml +53 -0
  80. dj_digger-0.1.0/references/copy-set.sh +283 -0
  81. dj_digger-0.1.0/references/export-music-audit.sh +663 -0
  82. dj_digger-0.1.0/schema-bundle.json +26 -0
  83. dj_digger-0.1.0/schemas/catalog-v6.sql +167 -0
  84. dj_digger-0.1.0/schemas/catalog-v7.sql +271 -0
  85. dj_digger-0.1.0/schemas/catalog-v8.sql +296 -0
  86. dj_digger-0.1.0/schemas/catalog-v9.sql +363 -0
  87. dj_digger-0.1.0/schemas/dj-analysis-run.schema.json +116 -0
  88. dj_digger-0.1.0/schemas/dj-analysis.schema.json +1206 -0
  89. dj_digger-0.1.0/schemas/dj-sections.schema.json +300 -0
  90. dj_digger-0.1.0/schemas/dj-set.schema.json +408 -0
  91. dj_digger-0.1.0/schemas/library-artifacts.schema.json +94 -0
  92. dj_digger-0.1.0/schemas/snapshot-manifest.schema.json +84 -0
  93. dj_digger-0.1.0/schemas/tracks.schema.json +288 -0
  94. dj_digger-0.1.0/scripts/AGENTS.md +39 -0
  95. dj_digger-0.1.0/scripts/CLAUDE.md +39 -0
  96. dj_digger-0.1.0/scripts/acceptance_library_pilot.py +228 -0
  97. dj_digger-0.1.0/skills/AGENTS.md +38 -0
  98. dj_digger-0.1.0/skills/CLAUDE.md +38 -0
  99. dj_digger-0.1.0/skills/electronic-dj-set-curator/SKILL.md +62 -0
  100. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/acid-rave.json +1 -0
  101. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/adversarial.json +1 -0
  102. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/baseline/acid-rave.m3u8 +4 -0
  103. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/baseline/acid-rave.md +3 -0
  104. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/baseline/acid-rave.set.json +1 -0
  105. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/dj-analysis-run.json +1 -0
  106. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/dj-analysis.tsv +5 -0
  107. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/dj-sections.jsonl +4 -0
  108. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/tracks.tsv +5 -0
  109. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/with-skill/acid-rave.m3u8 +4 -0
  110. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/with-skill/acid-rave.md +24 -0
  111. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/with-skill/acid-rave.set.json +1 -0
  112. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/baseline/adversarial.m3u8 +2 -0
  113. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/baseline/adversarial.md +3 -0
  114. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/baseline/adversarial.set.json +1 -0
  115. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/dj-analysis-run.json +1 -0
  116. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/dj-analysis.tsv +5 -0
  117. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/dj-sections.jsonl +2 -0
  118. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/tracks.tsv +5 -0
  119. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/with-skill/adversarial.m3u8 +2 -0
  120. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/with-skill/adversarial.md +17 -0
  121. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/with-skill/adversarial.set.json +1 -0
  122. dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/harness.py +249 -0
  123. dj_digger-0.1.0/skills/electronic-dj-set-curator/references/compatibility-engine.md +40 -0
  124. dj_digger-0.1.0/skills/electronic-dj-set-curator/references/set-emission.md +74 -0
  125. dj_digger-0.1.0/skills/electronic-dj-set-curator/references/source-contracts.md +26 -0
  126. dj_digger-0.1.0/src/dj_digger/AGENTS.md +38 -0
  127. dj_digger-0.1.0/src/dj_digger/CLAUDE.md +38 -0
  128. dj_digger-0.1.0/src/dj_digger/__init__.py +1 -0
  129. dj_digger-0.1.0/src/dj_digger/analysis/AGENTS.md +41 -0
  130. dj_digger-0.1.0/src/dj_digger/analysis/CLAUDE.md +41 -0
  131. dj_digger-0.1.0/src/dj_digger/analysis/__init__.py +1 -0
  132. dj_digger-0.1.0/src/dj_digger/analysis/aggregation.py +10 -0
  133. dj_digger-0.1.0/src/dj_digger/analysis/audio.py +20 -0
  134. dj_digger-0.1.0/src/dj_digger/analysis/config.py +14 -0
  135. dj_digger-0.1.0/src/dj_digger/analysis/ebur128.py +119 -0
  136. dj_digger-0.1.0/src/dj_digger/analysis/eligibility.py +27 -0
  137. dj_digger-0.1.0/src/dj_digger/analysis/exporters.py +400 -0
  138. dj_digger-0.1.0/src/dj_digger/analysis/extractor.py +388 -0
  139. dj_digger-0.1.0/src/dj_digger/analysis/ffmpeg.py +142 -0
  140. dj_digger-0.1.0/src/dj_digger/analysis/persistence.py +256 -0
  141. dj_digger-0.1.0/src/dj_digger/analysis/pipeline.py +217 -0
  142. dj_digger-0.1.0/src/dj_digger/analysis/rhythm.py +199 -0
  143. dj_digger-0.1.0/src/dj_digger/analysis/segmentation.py +126 -0
  144. dj_digger-0.1.0/src/dj_digger/analysis/semantics.py +35 -0
  145. dj_digger-0.1.0/src/dj_digger/analysis/spectrum.py +91 -0
  146. dj_digger-0.1.0/src/dj_digger/analysis/windows.py +41 -0
  147. dj_digger-0.1.0/src/dj_digger/analysis/worker.py +147 -0
  148. dj_digger-0.1.0/src/dj_digger/analysis/worker_client.py +254 -0
  149. dj_digger-0.1.0/src/dj_digger/analysis.toml +30 -0
  150. dj_digger-0.1.0/src/dj_digger/application.py +507 -0
  151. dj_digger-0.1.0/src/dj_digger/artifacts/__init__.py +5 -0
  152. dj_digger-0.1.0/src/dj_digger/artifacts/discovery.py +33 -0
  153. dj_digger-0.1.0/src/dj_digger/background.py +104 -0
  154. dj_digger-0.1.0/src/dj_digger/catalog/AGENTS.md +39 -0
  155. dj_digger-0.1.0/src/dj_digger/catalog/CLAUDE.md +39 -0
  156. dj_digger-0.1.0/src/dj_digger/catalog/__init__.py +1 -0
  157. dj_digger-0.1.0/src/dj_digger/catalog/current_analysis.py +78 -0
  158. dj_digger-0.1.0/src/dj_digger/catalog/database.py +184 -0
  159. dj_digger-0.1.0/src/dj_digger/catalog/factory.py +15 -0
  160. dj_digger-0.1.0/src/dj_digger/catalog/migrations.py +114 -0
  161. dj_digger-0.1.0/src/dj_digger/catalog/models.py +17 -0
  162. dj_digger-0.1.0/src/dj_digger/catalog/read_repositories.py +72 -0
  163. dj_digger-0.1.0/src/dj_digger/catalog/repositories.py +640 -0
  164. dj_digger-0.1.0/src/dj_digger/catalog/sql/catalog-v6.sql +167 -0
  165. dj_digger-0.1.0/src/dj_digger/catalog/sql/catalog-v7.sql +271 -0
  166. dj_digger-0.1.0/src/dj_digger/catalog/sql/catalog-v8.sql +296 -0
  167. dj_digger-0.1.0/src/dj_digger/catalog/sql/catalog-v9.sql +363 -0
  168. dj_digger-0.1.0/src/dj_digger/catalog/sql/migrate-v6-to-v7.sql +135 -0
  169. dj_digger-0.1.0/src/dj_digger/catalog/sql/migrate-v7-to-v8.sql +27 -0
  170. dj_digger-0.1.0/src/dj_digger/catalog/sql/migrate-v8-to-v9.sql +74 -0
  171. dj_digger-0.1.0/src/dj_digger/cli.py +580 -0
  172. dj_digger-0.1.0/src/dj_digger/completion.py +105 -0
  173. dj_digger-0.1.0/src/dj_digger/config.py +310 -0
  174. dj_digger-0.1.0/src/dj_digger/curation/__init__.py +20 -0
  175. dj_digger-0.1.0/src/dj_digger/curation/catalog.py +746 -0
  176. dj_digger-0.1.0/src/dj_digger/curation/models.py +201 -0
  177. dj_digger-0.1.0/src/dj_digger/duplicates/__init__.py +1 -0
  178. dj_digger-0.1.0/src/dj_digger/duplicates/fingerprint.py +70 -0
  179. dj_digger-0.1.0/src/dj_digger/duplicates/mastering.py +85 -0
  180. dj_digger-0.1.0/src/dj_digger/duplicates/mastering_comparison.py +132 -0
  181. dj_digger-0.1.0/src/dj_digger/duplicates/mastering_repository.py +212 -0
  182. dj_digger-0.1.0/src/dj_digger/duplicates/mastering_service.py +17 -0
  183. dj_digger-0.1.0/src/dj_digger/duplicates/quality.py +109 -0
  184. dj_digger-0.1.0/src/dj_digger/duplicates/repository.py +195 -0
  185. dj_digger-0.1.0/src/dj_digger/duplicates/service.py +432 -0
  186. dj_digger-0.1.0/src/dj_digger/exports/AGENTS.md +40 -0
  187. dj_digger-0.1.0/src/dj_digger/exports/CLAUDE.md +40 -0
  188. dj_digger-0.1.0/src/dj_digger/exports/__init__.py +6 -0
  189. dj_digger-0.1.0/src/dj_digger/exports/atomic.py +24 -0
  190. dj_digger-0.1.0/src/dj_digger/exports/audit.py +92 -0
  191. dj_digger-0.1.0/src/dj_digger/exports/formats.py +95 -0
  192. dj_digger-0.1.0/src/dj_digger/exports/snapshot.py +127 -0
  193. dj_digger-0.1.0/src/dj_digger/exports/tracks.py +167 -0
  194. dj_digger-0.1.0/src/dj_digger/logging.py +22 -0
  195. dj_digger-0.1.0/src/dj_digger/mcp_server.py +53 -0
  196. dj_digger-0.1.0/src/dj_digger/metadata/__init__.py +1 -0
  197. dj_digger-0.1.0/src/dj_digger/metadata/exiftool.py +368 -0
  198. dj_digger-0.1.0/src/dj_digger/progress.py +41 -0
  199. dj_digger-0.1.0/src/dj_digger/resources.py +11 -0
  200. dj_digger-0.1.0/src/dj_digger/rich_progress.py +110 -0
  201. dj_digger-0.1.0/src/dj_digger/scanning/__init__.py +5 -0
  202. dj_digger-0.1.0/src/dj_digger/scanning/classifiers.py +28 -0
  203. dj_digger-0.1.0/src/dj_digger/scanning/lifecycle.py +102 -0
  204. dj_digger-0.1.0/src/dj_digger/scanning/scanner.py +108 -0
  205. dj_digger-0.1.0/src/dj_digger/schemas/dj-analysis-run.schema.json +116 -0
  206. dj_digger-0.1.0/src/dj_digger/schemas/dj-analysis.schema.json +1206 -0
  207. dj_digger-0.1.0/src/dj_digger/schemas/dj-sections.schema.json +300 -0
  208. dj_digger-0.1.0/src/dj_digger/schemas/dj-set.schema.json +408 -0
  209. dj_digger-0.1.0/src/dj_digger/schemas/library-artifacts.schema.json +94 -0
  210. dj_digger-0.1.0/src/dj_digger/schemas/snapshot-manifest.schema.json +84 -0
  211. dj_digger-0.1.0/src/dj_digger/schemas/tracks.schema.json +288 -0
  212. dj_digger-0.1.0/src/dj_digger/set_copy.py +303 -0
  213. dj_digger-0.1.0/src/dj_digger/terminal.py +25 -0
  214. dj_digger-0.1.0/tests/AGENTS.md +47 -0
  215. dj_digger-0.1.0/tests/CLAUDE.md +47 -0
  216. dj_digger-0.1.0/tests/docker_analysis_smoke.py +39 -0
  217. dj_digger-0.1.0/tests/fixtures/acid-rave-core.m3u8 +4 -0
  218. dj_digger-0.1.0/tests/fixtures/blank-source-id.toml +9 -0
  219. dj_digger-0.1.0/tests/fixtures/codex_sessions/legacy-root.jsonl +5 -0
  220. dj_digger-0.1.0/tests/fixtures/codex_sessions/malformed-and-unknown.jsonl +3 -0
  221. dj_digger-0.1.0/tests/fixtures/codex_sessions/paginated-root.jsonl +4 -0
  222. dj_digger-0.1.0/tests/fixtures/codex_sessions/qa-repair-cycle.jsonl +4 -0
  223. dj_digger-0.1.0/tests/fixtures/codex_sessions/root-with-subagent-child-one.jsonl +3 -0
  224. dj_digger-0.1.0/tests/fixtures/codex_sessions/root-with-subagent-child-two.jsonl +3 -0
  225. dj_digger-0.1.0/tests/fixtures/codex_sessions/root-with-subagent.jsonl +4 -0
  226. dj_digger-0.1.0/tests/fixtures/database-inside-source.toml +9 -0
  227. dj_digger-0.1.0/tests/fixtures/dj-analysis-run.json +14 -0
  228. dj_digger-0.1.0/tests/fixtures/dj-analysis.tsv +2 -0
  229. dj_digger-0.1.0/tests/fixtures/dj-digger.toml +15 -0
  230. dj_digger-0.1.0/tests/fixtures/dj-sections.jsonl +1 -0
  231. dj_digger-0.1.0/tests/fixtures/duplicate-source-id.toml +15 -0
  232. dj_digger-0.1.0/tests/fixtures/exports-inside-source.toml +9 -0
  233. dj_digger-0.1.0/tests/fixtures/mastering/README.md +5 -0
  234. dj_digger-0.1.0/tests/fixtures/tracks.tsv +2 -0
  235. dj_digger-0.1.0/tests/integration/analysis_fixture.py +72 -0
  236. dj_digger-0.1.0/tests/integration/test_copy_set_compatibility.py +94 -0
  237. dj_digger-0.1.0/tests/integration/test_scan_history.py +95 -0
  238. dj_digger-0.1.0/tests/integration/test_tranche7_acceptance.py +252 -0
  239. dj_digger-0.1.0/tests/integration/test_v1a_pipeline.py +72 -0
  240. dj_digger-0.1.0/tests/integration/test_v1b_cutover.py +91 -0
  241. dj_digger-0.1.0/tests/mastering_fixture.py +28 -0
  242. dj_digger-0.1.0/tests/performance/README.md +219 -0
  243. dj_digger-0.1.0/tests/performance/__init__.py +1 -0
  244. dj_digger-0.1.0/tests/performance/benchmark_queries.py +416 -0
  245. dj_digger-0.1.0/tests/performance/fixtures.py +326 -0
  246. dj_digger-0.1.0/tests/performance/query_plans.py +28 -0
  247. dj_digger-0.1.0/tests/test_agent_benchmark.py +101 -0
  248. dj_digger-0.1.0/tests/test_agent_benchmark_compare.py +84 -0
  249. dj_digger-0.1.0/tests/test_analysis_eligibility.py +158 -0
  250. dj_digger-0.1.0/tests/test_analysis_exporters.py +171 -0
  251. dj_digger-0.1.0/tests/test_analysis_persistence.py +156 -0
  252. dj_digger-0.1.0/tests/test_analysis_pipeline.py +500 -0
  253. dj_digger-0.1.0/tests/test_analysis_worker.py +252 -0
  254. dj_digger-0.1.0/tests/test_application_contracts.py +369 -0
  255. dj_digger-0.1.0/tests/test_artifacts.py +28 -0
  256. dj_digger-0.1.0/tests/test_background_jobs.py +87 -0
  257. dj_digger-0.1.0/tests/test_catalog_migrations.py +601 -0
  258. dj_digger-0.1.0/tests/test_cli.py +151 -0
  259. dj_digger-0.1.0/tests/test_cli_analyze.py +165 -0
  260. dj_digger-0.1.0/tests/test_cli_background.py +121 -0
  261. dj_digger-0.1.0/tests/test_cli_completion.py +125 -0
  262. dj_digger-0.1.0/tests/test_cli_copy.py +184 -0
  263. dj_digger-0.1.0/tests/test_cli_duplicates.py +277 -0
  264. dj_digger-0.1.0/tests/test_cli_mcp.py +21 -0
  265. dj_digger-0.1.0/tests/test_cli_refresh.py +186 -0
  266. dj_digger-0.1.0/tests/test_cli_status_codes.py +75 -0
  267. dj_digger-0.1.0/tests/test_cli_status_doctor.py +209 -0
  268. dj_digger-0.1.0/tests/test_config.py +135 -0
  269. dj_digger-0.1.0/tests/test_curation_catalog.py +93 -0
  270. dj_digger-0.1.0/tests/test_current_analysis.py +288 -0
  271. dj_digger-0.1.0/tests/test_database.py +94 -0
  272. dj_digger-0.1.0/tests/test_database_commands.py +111 -0
  273. dj_digger-0.1.0/tests/test_docker_agent_contract.py +34 -0
  274. dj_digger-0.1.0/tests/test_docker_smoke.py +129 -0
  275. dj_digger-0.1.0/tests/test_duplicate_fingerprint.py +193 -0
  276. dj_digger-0.1.0/tests/test_duplicate_quality.py +210 -0
  277. dj_digger-0.1.0/tests/test_duplicates_service.py +236 -0
  278. dj_digger-0.1.0/tests/test_ebur128.py +68 -0
  279. dj_digger-0.1.0/tests/test_exiftool.py +402 -0
  280. dj_digger-0.1.0/tests/test_extractor.py +287 -0
  281. dj_digger-0.1.0/tests/test_ffmpeg.py +292 -0
  282. dj_digger-0.1.0/tests/test_golden_set.py +44 -0
  283. dj_digger-0.1.0/tests/test_library_pilot_reporting.py +25 -0
  284. dj_digger-0.1.0/tests/test_lifecycle.py +286 -0
  285. dj_digger-0.1.0/tests/test_mastering_comparison.py +42 -0
  286. dj_digger-0.1.0/tests/test_mastering_integration.py +15 -0
  287. dj_digger-0.1.0/tests/test_mastering_metrics.py +84 -0
  288. dj_digger-0.1.0/tests/test_mastering_persistence.py +104 -0
  289. dj_digger-0.1.0/tests/test_mcp_server.py +34 -0
  290. dj_digger-0.1.0/tests/test_packaging.py +54 -0
  291. dj_digger-0.1.0/tests/test_performance_fixtures.py +71 -0
  292. dj_digger-0.1.0/tests/test_playlist_emission.py +36 -0
  293. dj_digger-0.1.0/tests/test_progress.py +33 -0
  294. dj_digger-0.1.0/tests/test_query_plans.py +235 -0
  295. dj_digger-0.1.0/tests/test_read_repositories.py +188 -0
  296. dj_digger-0.1.0/tests/test_rhythm.py +166 -0
  297. dj_digger-0.1.0/tests/test_scanner.py +58 -0
  298. dj_digger-0.1.0/tests/test_segmentation.py +42 -0
  299. dj_digger-0.1.0/tests/test_semantics.py +29 -0
  300. dj_digger-0.1.0/tests/test_set_copy.py +415 -0
  301. dj_digger-0.1.0/tests/test_set_schema.py +121 -0
  302. dj_digger-0.1.0/tests/test_skill_tranche6.py +96 -0
  303. dj_digger-0.1.0/tests/test_snapshot.py +77 -0
  304. dj_digger-0.1.0/tests/test_spectrum.py +50 -0
  305. dj_digger-0.1.0/tests/test_sqlite_concurrency.py +283 -0
  306. dj_digger-0.1.0/tests/test_strict_current_contracts.py +173 -0
  307. dj_digger-0.1.0/tests/test_tracks_export.py +342 -0
  308. dj_digger-0.1.0/tests/test_windows.py +26 -0
  309. dj_digger-0.1.0/tests/validate_fixtures.py +143 -0
  310. dj_digger-0.1.0/uv.lock +1197 -0
@@ -0,0 +1,9 @@
1
+ #!/bin/sh
2
+ set -eu
3
+ root=$(git rev-parse --show-toplevel)
4
+ cd "$root"
5
+ {
6
+ git diff --name-only
7
+ git diff --cached --name-only
8
+ git ls-files --others --exclude-standard
9
+ } | sed '/^$/d' | LC_ALL=C sort -u
@@ -0,0 +1,63 @@
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ # Initialize fields with defaults
5
+ status=""
6
+ qa=""
7
+ next=""
8
+ risk=""
9
+
10
+ # Parse flags
11
+ while [ $# -gt 0 ]; do
12
+ case "$1" in
13
+ --status)
14
+ shift
15
+ status="$1"
16
+ ;;
17
+ --qa)
18
+ shift
19
+ qa="$1"
20
+ ;;
21
+ --next)
22
+ shift
23
+ next="$1"
24
+ ;;
25
+ --risk)
26
+ shift
27
+ risk="$1"
28
+ ;;
29
+ *)
30
+ printf 'usage: handoff [--status VALUE] [--qa VALUE] [--next VALUE] [--risk VALUE]\n' >&2
31
+ exit 2
32
+ ;;
33
+ esac
34
+ shift
35
+ done
36
+
37
+ # Derive branch name
38
+ branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
39
+
40
+ # Derive compact diff summary from real shortstat output (files/insertions/deletions)
41
+ staged_summary=$(git diff --cached --shortstat 2>/dev/null | sed 's/^ *//' || echo "")
42
+ unstaged_summary=$(git diff --shortstat 2>/dev/null | sed 's/^ *//' || echo "")
43
+
44
+ # Create compact diff summary
45
+ if [ -n "$staged_summary" ] && [ -n "$unstaged_summary" ]; then
46
+ diff_summary="staged: $staged_summary; unstaged: $unstaged_summary"
47
+ elif [ -n "$staged_summary" ]; then
48
+ diff_summary="staged: $staged_summary"
49
+ elif [ -n "$unstaged_summary" ]; then
50
+ diff_summary="unstaged: $unstaged_summary"
51
+ else
52
+ diff_summary="no-diff"
53
+ fi
54
+
55
+ # Print exactly six lines with headings
56
+ printf 'Status: %s\n' "$status"
57
+ printf 'Branch: %s\n' "$branch"
58
+ printf 'Diff: %s\n' "$diff_summary"
59
+ printf 'QA: %s\n' "$qa"
60
+ printf 'Next: %s\n' "$next"
61
+ printf 'Risk: %s\n' "$risk"
62
+
63
+ exit 0
@@ -0,0 +1,79 @@
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ # Build wheel and verify packaged resources
5
+ # Runs through project-env, unpacks into temp dir, verifies contents, cleans up
6
+
7
+ root=$(git rev-parse --show-toplevel)
8
+
9
+ # Create temp directory for unpacking (subshell-wrapped for isolation)
10
+ (
11
+ tmpdir=$(mktemp -d)
12
+ trap 'rm -rf "$tmpdir"' EXIT
13
+
14
+ # Build wheel and sdist using project-env, into a temp dir so nothing lands
15
+ # in the real dist/ directory.
16
+ cd "$root"
17
+ ./.agents/scripts/project-env uv build -q --out-dir "$tmpdir/dist"
18
+
19
+ # Find the built wheel (most recently modified)
20
+ wheel_file=$(find "$tmpdir/dist" -maxdepth 1 -name '*.whl' -type f -print -quit)
21
+ if [ -z "$wheel_file" ]; then
22
+ printf 'package-check: no wheel found in dist/\n' >&2
23
+ exit 1
24
+ fi
25
+ if ! find "$tmpdir/dist" -maxdepth 1 -name '*.tar.gz' -type f | grep -q .; then
26
+ printf 'package-check: no source distribution found in dist/\n' >&2
27
+ exit 1
28
+ fi
29
+
30
+ # Unpack wheel
31
+ cd "$tmpdir"
32
+ unzip -q "$wheel_file"
33
+
34
+ # Verify every resource read by runtime code is present in the package.
35
+ errors=0
36
+ required_files='dj_digger/analysis.toml
37
+ dj_digger/schema-bundle.json
38
+ dj_digger/schemas/tracks.schema.json
39
+ dj_digger/schemas/library-artifacts.schema.json
40
+ dj_digger/schemas/snapshot-manifest.schema.json
41
+ dj_digger/schemas/dj-analysis.schema.json
42
+ dj_digger/schemas/dj-sections.schema.json
43
+ dj_digger/schemas/dj-analysis-run.schema.json
44
+ dj_digger/catalog/sql/catalog-v9.sql
45
+ dj_digger/catalog/sql/migrate-v6-to-v7.sql
46
+ dj_digger/catalog/sql/migrate-v7-to-v8.sql
47
+ dj_digger/catalog/sql/migrate-v8-to-v9.sql'
48
+ while IFS= read -r required; do
49
+ [ -z "$required" ] && continue
50
+ if [ ! -f "$required" ]; then
51
+ printf 'package-check: required resource missing: %s\n' "$required" >&2
52
+ errors=1
53
+ fi
54
+ done <<EOF
55
+ $required_files
56
+ EOF
57
+ [ "$errors" -eq 0 ] || exit "$errors"
58
+
59
+ # Run the installed wheel through its public console entry point from a
60
+ # directory that contains neither the checkout nor source files.
61
+ package_workspace="$tmpdir/runtime"
62
+ mkdir -p "$package_workspace/music" "$package_workspace/exports"
63
+ cat > "$package_workspace/config.toml" <<'EOF'
64
+ [workspace]
65
+ database = "catalog.sqlite"
66
+ exports = "exports"
67
+
68
+ [[library.sources]]
69
+ id = "disabled"
70
+ path = "music"
71
+ set_eligible = false
72
+ analyze = false
73
+ enabled = false
74
+ EOF
75
+ cd "$package_workspace"
76
+ "$root/.agents/scripts/project-env" uvx --from "$wheel_file" dj-digger --help >/dev/null
77
+ "$root/.agents/scripts/project-env" uvx --from "$wheel_file" dj-digger doctor \
78
+ --config "$package_workspace/config.toml" --json >/dev/null
79
+ )
@@ -0,0 +1,5 @@
1
+ #!/bin/sh
2
+ set -eu
3
+ export UV_CACHE_DIR=/tmp/dj-digger-uv-cache
4
+ export UV_TOOL_DIR=/tmp/dj-digger-uv-tools
5
+ exec "$@"
@@ -0,0 +1,47 @@
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ # Validate arguments
5
+ if [ $# -eq 1 ] && { [ "$1" = "--changed" ] || [ "$1" = "--staged" ]; }; then
6
+ mode="$1"
7
+ revision_range=""
8
+ elif [ $# -eq 2 ] && [ "$1" = "--range" ]; then
9
+ mode="$1"
10
+ revision_range="$2"
11
+ else
12
+ exit 2
13
+ fi
14
+
15
+ failed=0
16
+
17
+ # Get the list of paths based on mode
18
+ if [ "$mode" = "--staged" ]; then
19
+ paths=$(git diff --cached --name-only 2>/dev/null || true)
20
+ elif [ "$mode" = "--range" ]; then
21
+ paths=$(git diff --name-only "$revision_range" 2>/dev/null) || {
22
+ printf 'cannot inspect protected paths in range: %s\n' "$revision_range" >&2
23
+ exit 1
24
+ }
25
+ else
26
+ paths=$( { git diff --name-only 2>/dev/null; git ls-files --others --exclude-standard 2>/dev/null; } || true)
27
+ fi
28
+
29
+ # Check each path
30
+ while IFS= read -r path; do
31
+ [ -z "$path" ] && continue
32
+
33
+ case "$path" in
34
+ config/local.toml|workspace/*|sets/*|*.sqlite*)
35
+ printf 'protected local path: %s\n' "$path" >&2
36
+ failed=1
37
+ ;;
38
+ .specifications/*)
39
+ printf 'protected specification archive path: %s\n' "$path" >&2
40
+ failed=1
41
+ ;;
42
+ esac
43
+ done <<EOF
44
+ $paths
45
+ EOF
46
+
47
+ exit "$failed"
@@ -0,0 +1,144 @@
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ # Execute QA commands for a given profile
5
+ # Usage: qa-run <profile> [-- target1 target2 ...]
6
+ # Profiles: docs, focused, subsystem, catalog, analysis, exports, runtime, full
7
+
8
+ if [ $# -lt 1 ]; then
9
+ printf 'usage: qa-run <profile> [-- targets...]\n' >&2
10
+ exit 2
11
+ fi
12
+
13
+ profile="$1"
14
+ shift
15
+ root=$(git rev-parse --show-toplevel)
16
+
17
+ # Parse arguments: optional -- is $1, targets are the rest
18
+ if [ $# -gt 0 ] && [ "$1" = "--" ]; then
19
+ shift
20
+ fi
21
+
22
+ # Create temp directory for logs (subshell-wrapped for isolation)
23
+ (
24
+ logdir=$(mktemp -d)
25
+ cleanup_on_exit=1
26
+ trap '[ "$cleanup_on_exit" = 1 ] && rm -rf "$logdir"' EXIT
27
+
28
+ status=0
29
+ cmd=""
30
+
31
+ case "$profile" in
32
+ docs)
33
+ # docs profile: git diff --check only
34
+ cmd="git diff --check"
35
+ git diff --check > "$logdir/docs.log" 2>&1 || status=$?
36
+ ;;
37
+
38
+ focused)
39
+ # focused profile: run pytest targets or shell scripts passed after --
40
+ if [ $# -eq 0 ]; then
41
+ printf 'qa-run focused: no targets provided after --\n' >&2
42
+ exit 2
43
+ fi
44
+
45
+ # Process each target, one log file per target
46
+ i=0
47
+ for target in "$@"; do
48
+ i=$((i + 1))
49
+ if [ -f "$target" ]; then
50
+ case "$target" in
51
+ *.sh)
52
+ # Shell script: run directly
53
+ cmd="sh $target"
54
+ sh "$target" > "$logdir/focused.$i.log" 2>&1 || status=$?
55
+ ;;
56
+ *.py)
57
+ # Python test file: run via pytest through project-env
58
+ cmd="uv run pytest $target"
59
+ "$root/.agents/scripts/project-env" uv run pytest "$target" > "$logdir/focused.$i.log" 2>&1 || status=$?
60
+ ;;
61
+ *)
62
+ printf 'qa-run focused: unknown target type: %s\n' "$target" >&2
63
+ exit 2
64
+ ;;
65
+ esac
66
+ else
67
+ printf 'qa-run focused: target not found: %s\n' "$target" >&2
68
+ exit 2
69
+ fi
70
+ [ "$status" -ne 0 ] && break
71
+ done
72
+ # For failure reporting, point at the last-attempted log
73
+ profile_log="$logdir/focused.$i.log"
74
+ ;;
75
+
76
+ subsystem)
77
+ # subsystem profile: relevant pytest + Ruff on changed Python
78
+ cmd="uv run pytest tests/test_subsystem.py && uv run ruff check src/dj_digger"
79
+ "$root/.agents/scripts/project-env" sh -c 'uv run pytest tests/ -k subsystem && uv run ruff check src/dj_digger' > "$logdir/subsystem.log" 2>&1 || status=$?
80
+ ;;
81
+
82
+ catalog)
83
+ # catalog profile: catalog/migration tests + package-check
84
+ cmd="uv run pytest tests/test_catalog.py && package-check"
85
+ "$root/.agents/scripts/project-env" sh -c 'uv run pytest tests/ -k catalog' > "$logdir/catalog.log" 2>&1 || status=$?
86
+ if [ "$status" -eq 0 ]; then
87
+ "$root/.agents/scripts/package-check" >> "$logdir/catalog.log" 2>&1 || status=$?
88
+ fi
89
+ ;;
90
+
91
+ analysis)
92
+ # analysis profile: worker/pipeline tests + Ruff + mypy
93
+ cmd="uv run pytest tests/test_analysis.py && uv run ruff check src/dj_digger/analysis && uv run mypy src/dj_digger/analysis"
94
+ "$root/.agents/scripts/project-env" sh -c 'uv run pytest tests/ -k analysis && uv run ruff check src/dj_digger/analysis && uv run mypy src/dj_digger/analysis' > "$logdir/analysis.log" 2>&1 || status=$?
95
+ ;;
96
+
97
+ exports)
98
+ # exports profile: export/schema tests + fixture validation
99
+ cmd="uv run pytest tests/test_exports.py"
100
+ "$root/.agents/scripts/project-env" sh -c 'uv run pytest tests/ -k exports' > "$logdir/exports.log" 2>&1 || status=$?
101
+ ;;
102
+
103
+ runtime)
104
+ # runtime profile: CLI/application tests + Ruff + mypy
105
+ cmd="uv run pytest tests/test_cli.py && uv run ruff check src/dj_digger/cli.py && uv run mypy src/dj_digger"
106
+ "$root/.agents/scripts/project-env" sh -c 'uv run pytest tests/ -k cli && uv run ruff check src/dj_digger && uv run mypy src/dj_digger' > "$logdir/runtime.log" 2>&1 || status=$?
107
+ ;;
108
+
109
+ full)
110
+ # full profile: full pytest, Ruff, mypy, fixtures, package-check, diff check
111
+ cmd="uv run pytest + uv run ruff check + uv run mypy + package-check + git diff --check"
112
+ "$root/.agents/scripts/project-env" sh -c 'uv run pytest tests/ && uv run ruff check src/dj_digger && uv run mypy src/dj_digger' > "$logdir/full.log" 2>&1 || status=$?
113
+ if [ "$status" -eq 0 ]; then
114
+ "$root/.agents/scripts/package-check" >> "$logdir/full.log" 2>&1 || status=$?
115
+ fi
116
+ if [ "$status" -eq 0 ]; then
117
+ git diff --check >> "$logdir/full.log" 2>&1 || status=$?
118
+ fi
119
+ ;;
120
+
121
+ *)
122
+ printf 'qa-run: unknown profile: %s\n' "$profile" >&2
123
+ exit 2
124
+ ;;
125
+ esac
126
+
127
+ # Default profile_log to the standard per-profile log file, unless already set (focused)
128
+ : "${profile_log:=$logdir/$profile.log}"
129
+
130
+ # If command failed, print failure details
131
+ if [ "$status" -ne 0 ]; then
132
+ printf '%s FAILED\n' "$cmd" >&2
133
+ if [ -f "$profile_log" ]; then
134
+ tail -10 "$profile_log" >&2
135
+ fi
136
+ printf 'log: %s\n' "$profile_log" >&2
137
+ # Keep the log dir around so the failure message above stays useful.
138
+ cleanup_on_exit=0
139
+ exit 1
140
+ fi
141
+
142
+ # Success
143
+ printf 'PASS %s\n' "$profile"
144
+ )
@@ -0,0 +1,90 @@
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ # Read paths from stdin and classify them into QA profiles
5
+ # Returns exactly one of: docs, focused, subsystem, catalog, analysis, exports, runtime, full
6
+
7
+ # Collect all categories found
8
+ categories=""
9
+
10
+ # Read each path and classify it
11
+ while IFS= read -r path; do
12
+ [ -z "$path" ] && continue
13
+
14
+ category=""
15
+
16
+ # Check for documentation files
17
+ if [ "$path" = "README.md" ] || [ "$path" = "CHANGELOG.md" ] || \
18
+ [ "$path" = "docs/README.md" ] || printf '%s\n' "$path" | grep -q '^docs/'; then
19
+ category="docs"
20
+ # Check for instruction/harness files
21
+ elif [ "$path" = "docker-agent.yaml" ] || printf '%s\n' "$path" | grep -q '^\.docker-agent/' || \
22
+ [ "$path" = "Makefile" ] || [ "$path" = "conftest.py" ] || \
23
+ [ "$path" = "pytest.ini" ] || [ "$path" = "pyproject.toml" ] || \
24
+ [ "$path" = "setup.py" ] || [ "$path" = "setup.cfg" ] || \
25
+ [ "$path" = "tox.ini" ] || printf '%s\n' "$path" | grep -qE '^\.(agents|codex|docker-agent|github)/|^(scripts|skills|tests)/'; then
26
+ category="focused"
27
+ # Check for production modules
28
+ elif printf '%s\n' "$path" | grep -q '^src/dj_digger/catalog/'; then
29
+ category="catalog"
30
+ elif printf '%s\n' "$path" | grep -q '^src/dj_digger/analysis/'; then
31
+ category="analysis"
32
+ elif printf '%s\n' "$path" | grep -q '^src/dj_digger/exports/'; then
33
+ category="exports"
34
+ elif printf '%s\n' "$path" | grep -q '^src/dj_digger/copying/'; then
35
+ category="subsystem"
36
+ elif printf '%s\n' "$path" | grep -q '^src/dj_digger/.*\.py$'; then
37
+ # Check if it's cli.py or another top-level Python file
38
+ if [ "$path" = "src/dj_digger/cli.py" ] || \
39
+ [ "$path" = "src/dj_digger/__main__.py" ] || \
40
+ [ "$path" = "src/dj_digger/__init__.py" ]; then
41
+ category="runtime"
42
+ else
43
+ # Check if it's in any other subsystem module
44
+ first_module=$(printf '%s\n' "$path" | sed 's|^src/dj_digger/||' | cut -d/ -f1 | sed 's/\.py$//')
45
+ case "$first_module" in
46
+ scanning|metadata|artifacts)
47
+ category="subsystem"
48
+ ;;
49
+ *)
50
+ # Default to subsystem for unknown modules
51
+ category="subsystem"
52
+ ;;
53
+ esac
54
+ fi
55
+ fi
56
+
57
+ # If we found a category, add it to the list
58
+ if [ -n "$category" ]; then
59
+ # Add to categories if not already present (avoid duplicates)
60
+ if ! printf '%s\n' "$categories" | grep -q "^$category$"; then
61
+ if [ -z "$categories" ]; then
62
+ categories="$category"
63
+ else
64
+ categories="$categories
65
+ $category"
66
+ fi
67
+ fi
68
+ fi
69
+ done
70
+
71
+ # Count distinct production categories (not including focused or docs)
72
+ production_count=$(printf '%s\n' "$categories" | grep -v '^focused$' | grep -v '^docs$' | grep -c . || true)
73
+
74
+ # If no categories found, default to focused
75
+ if [ -z "$categories" ]; then
76
+ printf '%s\n' "focused"
77
+ elif [ "$production_count" = 0 ]; then
78
+ # Only focused and/or docs files found
79
+ if printf '%s\n' "$categories" | grep -q '^docs$'; then
80
+ printf '%s\n' "docs"
81
+ else
82
+ printf '%s\n' "focused"
83
+ fi
84
+ elif [ "$production_count" -gt 1 ]; then
85
+ # Multiple production categories found
86
+ printf '%s\n' "full"
87
+ else
88
+ # Single production category
89
+ printf '%s\n' "$categories" | grep -v '^focused$' | grep -v '^docs$'
90
+ fi
@@ -0,0 +1,43 @@
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ # Validate that at least one allowed path is provided
5
+ if [ $# -lt 1 ]; then
6
+ printf 'usage: staged-check <allowed-path> [allowed-path ...]\n' >&2
7
+ exit 2
8
+ fi
9
+
10
+ # Get list of allowed paths (sort them)
11
+ allowed=$(printf '%s\n' "$@" | LC_ALL=C sort)
12
+
13
+ # Get list of staged paths (sort them)
14
+ staged=$(git diff --cached --name-only 2>/dev/null | LC_ALL=C sort || true)
15
+
16
+ # Compare staged paths with allowed paths
17
+ if [ "$staged" != "$allowed" ]; then
18
+ printf 'staged scope mismatch\nallowed:\n%s\nstaged:\n%s\n' "$allowed" "$staged" >&2
19
+ exit 1
20
+ fi
21
+
22
+ # Run protect-local validation using the same directory as this script
23
+ script_dir="$(dirname "$0")"
24
+ if ! "$script_dir/protect-local" --staged; then
25
+ exit 1
26
+ fi
27
+
28
+ # Check for conflict markers in staged content (only in added lines, anchored
29
+ # to the real marker shapes to avoid false-positives on e.g. Markdown setext
30
+ # underlines like "=======")
31
+ if git diff --cached | grep -qE '^\+(<{7}( |$)|={7}$|>{7}( |$))'; then
32
+ printf 'conflict markers detected in staged content\n' >&2
33
+ exit 1
34
+ fi
35
+
36
+ # Run git diff --cached --check to detect other issues
37
+ if ! git diff --cached --check; then
38
+ exit 1
39
+ fi
40
+
41
+ # All checks passed
42
+ printf 'PASS staged scope\n'
43
+ exit 0
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: commit
3
+ description: Create one scoped conventional Git commit after QA and staged-scope checks
4
+ ---
5
+
6
+ ## Purpose
7
+
8
+ Create a local commit only when the user explicitly asks to commit. A request
9
+ to implement, finish, wrap up, or report completion is not commit authorization.
10
+ This skill does not push, open a pull request, amend history, or broaden the
11
+ requested file scope.
12
+
13
+ ## Before committing
14
+
15
+ 1. Confirm the current branch and inspect `git status --short` and the relevant
16
+ `git diff`; preserve unrelated worktree changes.
17
+ 2. Run the focused QA required by the changed files. Pipe explicit paths to
18
+ `.agents/scripts/qa-select`, then run the selected profile with
19
+ `.agents/scripts/qa-run`.
20
+ 3. Stage only the requested paths with explicit path arguments. Never use
21
+ `git add .` or `git add -A`.
22
+ 4. Run `.agents/scripts/staged-check <path> ...`; inspect `git diff --cached`.
23
+ Protected local paths are never staged. Specs require explicit authorization
24
+ in the current user turn. Repository-declared protected paths and ignored
25
+ files are never force-staged.
26
+
27
+ ## Commit
28
+
29
+ Use the convention in [references/message-patterns.md](references/message-patterns.md).
30
+ The subject is English, imperative, and conventional; include a body with the
31
+ bounded worker brief (Goal, Changed files, Observed proof, Residual risk) when
32
+ the subject alone cannot explain a meaningful change. Do not add
33
+ `Co-Authored-By` or `Signed-off-by` trailers. Use `git commit` without
34
+ `--no-verify`; never amend unless the user explicitly authorizes it.
35
+
36
+ ## Report
37
+
38
+ Finish with `.agents/scripts/handoff` and report the exact QA command, staged
39
+ paths, commit result, and any residual risk. A commit is not authorization to
40
+ push or open a pull request.
@@ -0,0 +1,28 @@
1
+ # Commit message pattern
2
+
3
+ Use English and the subject form:
4
+
5
+ `type[(scope[, scope2, ...])]: imperative summary`
6
+
7
+ - Type: `feat`, `fix`, `refactor`, `chore`, or `docs`.
8
+ - Scope is optional. Use it only when one concise repository area clarifies the
9
+ change, such as `cli`, `catalog`, `analysis`, `exports`, `copy`, or `agent`.
10
+ The repository commonly uses unscoped subjects such as `feat: ...` and
11
+ `docs: ...`; do not invent a scope for consistency theatre.
12
+ - Keep the summary lowercase, imperative, and specific; wrap identifiers and
13
+ paths in backticks when they appear in a body.
14
+ - Add `(#PRD-XXXX)` only when the user supplies a ticket reference. Omit it for
15
+ internal tooling.
16
+
17
+ Use no body for mechanical changes. For meaningful changes, use short prose for
18
+ one cause or bullets for distinct changes. When a bounded worker brief is
19
+ useful, include:
20
+
21
+ ```
22
+ Goal: <what this commit solves>
23
+ Changed files: <paths or area>
24
+ Observed proof: <QA command and result>
25
+ Residual risk: <none or precise reservation>
26
+ ```
27
+
28
+ Never add `Co-Authored-By`, `Signed-off-by`, or tool-attribution trailers.
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: implement
3
+ description: Run the observable RED/GREEN TDD loop; verify changes before handoff
4
+ ---
5
+
6
+ ## Purpose
7
+
8
+ Executes the test-driven implementation loop. Verifies every change is observable, reproducible, and public-path only. Fakes on the claimed integration path invalidate the proof.
9
+
10
+ ## Steps
11
+
12
+ 1. **Understand**: Read the task brief and scoped AGENTS.md.
13
+ 2. **Plan**: Identify entry points, owned files, and dependencies.
14
+ 3. **RED**: Run test suite; confirm the test fails as expected.
15
+ 4. **Code**: Edit files to satisfy the test.
16
+ 5. **GREEN**: Run test suite; confirm the test passes.
17
+ 6. **Verify**: Confirm the change is observable:
18
+ - No fakes or stubs in the implementation path
19
+ - All real library calls are tested or marked unverified
20
+ - Exit codes, file state, or database state changed as expected
21
+ 7. **Report**: Observed RED command/output, GREEN command/output, residual risk.
22
+
23
+ ## Observable proof
24
+
25
+ - Command run (exact sh invocation)
26
+ - Exit status (0 or non-zero)
27
+ - Files modified (git status, diff)
28
+ - Database state (sqlite3 query output, pragma foreign_keys check)
29
+ - Artifact presence (file path exists and contains expected content)
30
+
31
+ ## Limitations
32
+
33
+ Inaccessible real libraries (network, cloud, third-party) are reported as unverified, not passed.
34
+
35
+ ## Do not do
36
+
37
+ - Use fakes, stubs, or mock patches on the implementation path
38
+ - Commit without explicit handoff
39
+ - Skip the GREEN step
40
+ - Ignore residual risk or boundary conditions
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: mr
3
+ description: Push a branch and create or update its GitHub pull request with gh
4
+ ---
5
+
6
+ ## Purpose
7
+
8
+ Use when the user explicitly asks to open, create, or update a merge request or
9
+ pull request. In this repository the requested `mr` parity skill operates on
10
+ GitHub via `gh`; pushing and PR metadata changes are visible mutations covered
11
+ by that explicit request.
12
+
13
+ Never update a closed or merged PR. Match an existing PR by exact source head
14
+ branch and verify its state before writing; target it by PR number, not a branch
15
+ name. Preserve existing base, assignees, labels, reviewers, and other metadata
16
+ unless the user requests a change.
17
+
18
+ ## Workflow
19
+
20
+ 1. Resolve the source branch without checking it out. For an existing open PR,
21
+ preserve its `baseRefName`. For a new PR, use an explicit user target first,
22
+ otherwise read GitHub's default with
23
+ `gh repo view --json defaultBranchRef --jq .defaultBranchRef.name`. Fetch the
24
+ selected remote ref and prove the relationship with `git merge-base`; do not
25
+ guess from `origin/HEAD` or an unrelated branch name.
26
+ 2. Inspect actual commits and `git diff <base>...<head>`. Run applicable QA via
27
+ `.agents/scripts/qa-select` and `.agents/scripts/qa-run`; derive title, summary,
28
+ test plan, and risks from those results, not assumptions. Before any push,
29
+ run `.agents/scripts/protect-local --range <base>...<head>` and inspect the
30
+ committed diff for private library facts; a clean working tree alone does
31
+ not prove that the branch range is safe.
32
+ 3. Before pushing, query all historical matches with
33
+ `gh pr list --head <branch> --state all --json number,state,mergedAt,headRefName,baseRefName,url`.
34
+ If an exact open-head PR exists, verify it with
35
+ `gh pr view <number> --json state,headRefName,baseRefName,url`. If only a
36
+ closed or merged match exists, stop before mutation and require a new branch
37
+ name. Refuse a new PR whose head equals its base.
38
+ 4. Push the exact branch with `git push -u origin <branch>`.
39
+ 5. Create with `gh pr create` only when no historical PR uses that exact head;
40
+ otherwise update the verified open exact-head PR by number with
41
+ `gh pr edit <number>`. Do not touch closed or merged PRs.
42
+
43
+ Use the template in [references/pr-description.md](references/pr-description.md).
44
+ Keep title and body in English. Do not add tool-attribution lines or merge
45
+ policy flags such as auto-delete or squash unless requested.
46
+
47
+ ## Report
48
+
49
+ Use `.agents/scripts/handoff`; include branch, base proof, PR URL/number, push
50
+ result, actual QA, and residual risk. This skill does not merge the PR.
@@ -0,0 +1,24 @@
1
+ # Pull request description
2
+
3
+ Title:
4
+
5
+ `type[(scope)]: imperative summary`
6
+
7
+ Body:
8
+
9
+ ```markdown
10
+ ## Summary
11
+ - <distinct change, based on actual commits and diff>
12
+
13
+ ## Test plan
14
+ - [ ] <re-runnable QA command or public-path check>
15
+
16
+ ## Risks and notes
17
+ - <none, or a precise residual risk and follow-up>
18
+ ```
19
+
20
+ Omit the risks section only when there is no meaningful reservation. Keep
21
+ identifiers and paths in backticks. Use checkboxes even for checks already run,
22
+ so reviewers can reproduce them. If the branch has no applicable ticket,
23
+ include no ticket section. Never include `Co-Authored-By`, `Signed-off-by`, or
24
+ generated-by attribution.