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.
- dj_digger-0.1.0/.agents/scripts/changed-files +9 -0
- dj_digger-0.1.0/.agents/scripts/handoff +63 -0
- dj_digger-0.1.0/.agents/scripts/package-check +79 -0
- dj_digger-0.1.0/.agents/scripts/project-env +5 -0
- dj_digger-0.1.0/.agents/scripts/protect-local +47 -0
- dj_digger-0.1.0/.agents/scripts/qa-run +144 -0
- dj_digger-0.1.0/.agents/scripts/qa-select +90 -0
- dj_digger-0.1.0/.agents/scripts/staged-check +43 -0
- dj_digger-0.1.0/.agents/skills/commit/SKILL.md +40 -0
- dj_digger-0.1.0/.agents/skills/commit/references/message-patterns.md +28 -0
- dj_digger-0.1.0/.agents/skills/implement/SKILL.md +40 -0
- dj_digger-0.1.0/.agents/skills/mr/SKILL.md +50 -0
- dj_digger-0.1.0/.agents/skills/mr/references/pr-description.md +24 -0
- dj_digger-0.1.0/.agents/skills/native-analysis/SKILL.md +40 -0
- dj_digger-0.1.0/.agents/skills/qa/SKILL.md +46 -0
- dj_digger-0.1.0/.agents/skills/runtime-proof/SKILL.md +38 -0
- dj_digger-0.1.0/.agents/skills/ship/SKILL.md +45 -0
- dj_digger-0.1.0/.agents/skills/ship/assets/report.md +19 -0
- dj_digger-0.1.0/.agents/skills/sqlite-change/SKILL.md +45 -0
- dj_digger-0.1.0/.agents/skills/task/SKILL.md +35 -0
- dj_digger-0.1.0/.agents/tests/simple-test.sh +4 -0
- dj_digger-0.1.0/.agents/tests/test-harness.sh +336 -0
- dj_digger-0.1.0/.claude/scripts/changed-files +1 -0
- dj_digger-0.1.0/.claude/scripts/handoff +1 -0
- dj_digger-0.1.0/.claude/scripts/package-check +1 -0
- dj_digger-0.1.0/.claude/scripts/project-env +1 -0
- dj_digger-0.1.0/.claude/scripts/protect-local +1 -0
- dj_digger-0.1.0/.claude/scripts/qa-run +1 -0
- dj_digger-0.1.0/.claude/scripts/qa-select +1 -0
- dj_digger-0.1.0/.claude/scripts/staged-check +1 -0
- dj_digger-0.1.0/.claude/settings.json +29 -0
- dj_digger-0.1.0/.claude/skills/implement/SKILL.md +40 -0
- dj_digger-0.1.0/.claude/skills/native-analysis/SKILL.md +38 -0
- dj_digger-0.1.0/.claude/skills/qa/SKILL.md +40 -0
- dj_digger-0.1.0/.claude/skills/runtime-proof/SKILL.md +38 -0
- dj_digger-0.1.0/.claude/skills/ship/SKILL.md +54 -0
- dj_digger-0.1.0/.claude/skills/sqlite-change/SKILL.md +42 -0
- dj_digger-0.1.0/.claude/skills/task/SKILL.md +35 -0
- dj_digger-0.1.0/.claude/tests/test-harness.sh +339 -0
- dj_digger-0.1.0/.codex/cloud/ENVIRONMENT_VERSION +1 -0
- dj_digger-0.1.0/.codex/cloud/check.sh +55 -0
- dj_digger-0.1.0/.codex/cloud/maintenance.sh +7 -0
- dj_digger-0.1.0/.codex/cloud/runtime-smoke.py +154 -0
- dj_digger-0.1.0/.codex/cloud/setup.sh +32 -0
- dj_digger-0.1.0/.codex/hooks/stop-protect-local +15 -0
- dj_digger-0.1.0/.codex/hooks.json +24 -0
- dj_digger-0.1.0/.docker-agent/README.md +35 -0
- dj_digger-0.1.0/.docker-agent/instructions/lead.md +138 -0
- dj_digger-0.1.0/.docker-agent/instructions/reviewer.md +23 -0
- dj_digger-0.1.0/.docker-agent/schemas/benchmark.schema.json +17 -0
- dj_digger-0.1.0/.docker-agent/schemas/review-result.schema.json +13 -0
- dj_digger-0.1.0/.docker-agent/schemas/task-brief.schema.json +20 -0
- dj_digger-0.1.0/.docker-agent/scripts/benchmark-compare +102 -0
- dj_digger-0.1.0/.docker-agent/scripts/change-summary +155 -0
- dj_digger-0.1.0/.docker-agent/scripts/codex-session-benchmark +319 -0
- dj_digger-0.1.0/.docker-agent/scripts/lead-qa +21 -0
- dj_digger-0.1.0/.docker-agent/scripts/next-plan-task +132 -0
- dj_digger-0.1.0/.docker-agent/scripts/qa-gate +63 -0
- dj_digger-0.1.0/.docker-agent/scripts/session-guard +20 -0
- dj_digger-0.1.0/.github/workflows/ci.yml +92 -0
- dj_digger-0.1.0/.github/workflows/pypi.yaml +56 -0
- dj_digger-0.1.0/.gitignore +13 -0
- dj_digger-0.1.0/AGENTS.md +140 -0
- dj_digger-0.1.0/CLAUDE.md +139 -0
- dj_digger-0.1.0/Dockerfile +17 -0
- dj_digger-0.1.0/PKG-INFO +769 -0
- dj_digger-0.1.0/README.md +755 -0
- dj_digger-0.1.0/compose.yaml +10 -0
- dj_digger-0.1.0/config/analysis.toml +30 -0
- dj_digger-0.1.0/config/dj-digger.example.toml +17 -0
- dj_digger-0.1.0/docker-agent.yaml +154 -0
- dj_digger-0.1.0/docs/AGENTS.md +36 -0
- dj_digger-0.1.0/docs/ARCHITECTURE.md +273 -0
- dj_digger-0.1.0/docs/CLAUDE.md +36 -0
- dj_digger-0.1.0/docs/docker-agent-development.md +135 -0
- dj_digger-0.1.0/docs/export-fields.md +215 -0
- dj_digger-0.1.0/docs/implementation-workflow.md +194 -0
- dj_digger-0.1.0/docs/mcp.md +99 -0
- dj_digger-0.1.0/pyproject.toml +53 -0
- dj_digger-0.1.0/references/copy-set.sh +283 -0
- dj_digger-0.1.0/references/export-music-audit.sh +663 -0
- dj_digger-0.1.0/schema-bundle.json +26 -0
- dj_digger-0.1.0/schemas/catalog-v6.sql +167 -0
- dj_digger-0.1.0/schemas/catalog-v7.sql +271 -0
- dj_digger-0.1.0/schemas/catalog-v8.sql +296 -0
- dj_digger-0.1.0/schemas/catalog-v9.sql +363 -0
- dj_digger-0.1.0/schemas/dj-analysis-run.schema.json +116 -0
- dj_digger-0.1.0/schemas/dj-analysis.schema.json +1206 -0
- dj_digger-0.1.0/schemas/dj-sections.schema.json +300 -0
- dj_digger-0.1.0/schemas/dj-set.schema.json +408 -0
- dj_digger-0.1.0/schemas/library-artifacts.schema.json +94 -0
- dj_digger-0.1.0/schemas/snapshot-manifest.schema.json +84 -0
- dj_digger-0.1.0/schemas/tracks.schema.json +288 -0
- dj_digger-0.1.0/scripts/AGENTS.md +39 -0
- dj_digger-0.1.0/scripts/CLAUDE.md +39 -0
- dj_digger-0.1.0/scripts/acceptance_library_pilot.py +228 -0
- dj_digger-0.1.0/skills/AGENTS.md +38 -0
- dj_digger-0.1.0/skills/CLAUDE.md +38 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/SKILL.md +62 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/acid-rave.json +1 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/adversarial.json +1 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/baseline/acid-rave.m3u8 +4 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/baseline/acid-rave.md +3 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/baseline/acid-rave.set.json +1 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/dj-analysis-run.json +1 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/dj-analysis.tsv +5 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/dj-sections.jsonl +4 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/tracks.tsv +5 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/with-skill/acid-rave.m3u8 +4 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/with-skill/acid-rave.md +24 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/acid-rave/with-skill/acid-rave.set.json +1 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/baseline/adversarial.m3u8 +2 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/baseline/adversarial.md +3 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/baseline/adversarial.set.json +1 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/dj-analysis-run.json +1 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/dj-analysis.tsv +5 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/dj-sections.jsonl +2 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/tracks.tsv +5 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/with-skill/adversarial.m3u8 +2 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/with-skill/adversarial.md +17 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/cases/adversarial/with-skill/adversarial.set.json +1 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/evals/harness.py +249 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/references/compatibility-engine.md +40 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/references/set-emission.md +74 -0
- dj_digger-0.1.0/skills/electronic-dj-set-curator/references/source-contracts.md +26 -0
- dj_digger-0.1.0/src/dj_digger/AGENTS.md +38 -0
- dj_digger-0.1.0/src/dj_digger/CLAUDE.md +38 -0
- dj_digger-0.1.0/src/dj_digger/__init__.py +1 -0
- dj_digger-0.1.0/src/dj_digger/analysis/AGENTS.md +41 -0
- dj_digger-0.1.0/src/dj_digger/analysis/CLAUDE.md +41 -0
- dj_digger-0.1.0/src/dj_digger/analysis/__init__.py +1 -0
- dj_digger-0.1.0/src/dj_digger/analysis/aggregation.py +10 -0
- dj_digger-0.1.0/src/dj_digger/analysis/audio.py +20 -0
- dj_digger-0.1.0/src/dj_digger/analysis/config.py +14 -0
- dj_digger-0.1.0/src/dj_digger/analysis/ebur128.py +119 -0
- dj_digger-0.1.0/src/dj_digger/analysis/eligibility.py +27 -0
- dj_digger-0.1.0/src/dj_digger/analysis/exporters.py +400 -0
- dj_digger-0.1.0/src/dj_digger/analysis/extractor.py +388 -0
- dj_digger-0.1.0/src/dj_digger/analysis/ffmpeg.py +142 -0
- dj_digger-0.1.0/src/dj_digger/analysis/persistence.py +256 -0
- dj_digger-0.1.0/src/dj_digger/analysis/pipeline.py +217 -0
- dj_digger-0.1.0/src/dj_digger/analysis/rhythm.py +199 -0
- dj_digger-0.1.0/src/dj_digger/analysis/segmentation.py +126 -0
- dj_digger-0.1.0/src/dj_digger/analysis/semantics.py +35 -0
- dj_digger-0.1.0/src/dj_digger/analysis/spectrum.py +91 -0
- dj_digger-0.1.0/src/dj_digger/analysis/windows.py +41 -0
- dj_digger-0.1.0/src/dj_digger/analysis/worker.py +147 -0
- dj_digger-0.1.0/src/dj_digger/analysis/worker_client.py +254 -0
- dj_digger-0.1.0/src/dj_digger/analysis.toml +30 -0
- dj_digger-0.1.0/src/dj_digger/application.py +507 -0
- dj_digger-0.1.0/src/dj_digger/artifacts/__init__.py +5 -0
- dj_digger-0.1.0/src/dj_digger/artifacts/discovery.py +33 -0
- dj_digger-0.1.0/src/dj_digger/background.py +104 -0
- dj_digger-0.1.0/src/dj_digger/catalog/AGENTS.md +39 -0
- dj_digger-0.1.0/src/dj_digger/catalog/CLAUDE.md +39 -0
- dj_digger-0.1.0/src/dj_digger/catalog/__init__.py +1 -0
- dj_digger-0.1.0/src/dj_digger/catalog/current_analysis.py +78 -0
- dj_digger-0.1.0/src/dj_digger/catalog/database.py +184 -0
- dj_digger-0.1.0/src/dj_digger/catalog/factory.py +15 -0
- dj_digger-0.1.0/src/dj_digger/catalog/migrations.py +114 -0
- dj_digger-0.1.0/src/dj_digger/catalog/models.py +17 -0
- dj_digger-0.1.0/src/dj_digger/catalog/read_repositories.py +72 -0
- dj_digger-0.1.0/src/dj_digger/catalog/repositories.py +640 -0
- dj_digger-0.1.0/src/dj_digger/catalog/sql/catalog-v6.sql +167 -0
- dj_digger-0.1.0/src/dj_digger/catalog/sql/catalog-v7.sql +271 -0
- dj_digger-0.1.0/src/dj_digger/catalog/sql/catalog-v8.sql +296 -0
- dj_digger-0.1.0/src/dj_digger/catalog/sql/catalog-v9.sql +363 -0
- dj_digger-0.1.0/src/dj_digger/catalog/sql/migrate-v6-to-v7.sql +135 -0
- dj_digger-0.1.0/src/dj_digger/catalog/sql/migrate-v7-to-v8.sql +27 -0
- dj_digger-0.1.0/src/dj_digger/catalog/sql/migrate-v8-to-v9.sql +74 -0
- dj_digger-0.1.0/src/dj_digger/cli.py +580 -0
- dj_digger-0.1.0/src/dj_digger/completion.py +105 -0
- dj_digger-0.1.0/src/dj_digger/config.py +310 -0
- dj_digger-0.1.0/src/dj_digger/curation/__init__.py +20 -0
- dj_digger-0.1.0/src/dj_digger/curation/catalog.py +746 -0
- dj_digger-0.1.0/src/dj_digger/curation/models.py +201 -0
- dj_digger-0.1.0/src/dj_digger/duplicates/__init__.py +1 -0
- dj_digger-0.1.0/src/dj_digger/duplicates/fingerprint.py +70 -0
- dj_digger-0.1.0/src/dj_digger/duplicates/mastering.py +85 -0
- dj_digger-0.1.0/src/dj_digger/duplicates/mastering_comparison.py +132 -0
- dj_digger-0.1.0/src/dj_digger/duplicates/mastering_repository.py +212 -0
- dj_digger-0.1.0/src/dj_digger/duplicates/mastering_service.py +17 -0
- dj_digger-0.1.0/src/dj_digger/duplicates/quality.py +109 -0
- dj_digger-0.1.0/src/dj_digger/duplicates/repository.py +195 -0
- dj_digger-0.1.0/src/dj_digger/duplicates/service.py +432 -0
- dj_digger-0.1.0/src/dj_digger/exports/AGENTS.md +40 -0
- dj_digger-0.1.0/src/dj_digger/exports/CLAUDE.md +40 -0
- dj_digger-0.1.0/src/dj_digger/exports/__init__.py +6 -0
- dj_digger-0.1.0/src/dj_digger/exports/atomic.py +24 -0
- dj_digger-0.1.0/src/dj_digger/exports/audit.py +92 -0
- dj_digger-0.1.0/src/dj_digger/exports/formats.py +95 -0
- dj_digger-0.1.0/src/dj_digger/exports/snapshot.py +127 -0
- dj_digger-0.1.0/src/dj_digger/exports/tracks.py +167 -0
- dj_digger-0.1.0/src/dj_digger/logging.py +22 -0
- dj_digger-0.1.0/src/dj_digger/mcp_server.py +53 -0
- dj_digger-0.1.0/src/dj_digger/metadata/__init__.py +1 -0
- dj_digger-0.1.0/src/dj_digger/metadata/exiftool.py +368 -0
- dj_digger-0.1.0/src/dj_digger/progress.py +41 -0
- dj_digger-0.1.0/src/dj_digger/resources.py +11 -0
- dj_digger-0.1.0/src/dj_digger/rich_progress.py +110 -0
- dj_digger-0.1.0/src/dj_digger/scanning/__init__.py +5 -0
- dj_digger-0.1.0/src/dj_digger/scanning/classifiers.py +28 -0
- dj_digger-0.1.0/src/dj_digger/scanning/lifecycle.py +102 -0
- dj_digger-0.1.0/src/dj_digger/scanning/scanner.py +108 -0
- dj_digger-0.1.0/src/dj_digger/schemas/dj-analysis-run.schema.json +116 -0
- dj_digger-0.1.0/src/dj_digger/schemas/dj-analysis.schema.json +1206 -0
- dj_digger-0.1.0/src/dj_digger/schemas/dj-sections.schema.json +300 -0
- dj_digger-0.1.0/src/dj_digger/schemas/dj-set.schema.json +408 -0
- dj_digger-0.1.0/src/dj_digger/schemas/library-artifacts.schema.json +94 -0
- dj_digger-0.1.0/src/dj_digger/schemas/snapshot-manifest.schema.json +84 -0
- dj_digger-0.1.0/src/dj_digger/schemas/tracks.schema.json +288 -0
- dj_digger-0.1.0/src/dj_digger/set_copy.py +303 -0
- dj_digger-0.1.0/src/dj_digger/terminal.py +25 -0
- dj_digger-0.1.0/tests/AGENTS.md +47 -0
- dj_digger-0.1.0/tests/CLAUDE.md +47 -0
- dj_digger-0.1.0/tests/docker_analysis_smoke.py +39 -0
- dj_digger-0.1.0/tests/fixtures/acid-rave-core.m3u8 +4 -0
- dj_digger-0.1.0/tests/fixtures/blank-source-id.toml +9 -0
- dj_digger-0.1.0/tests/fixtures/codex_sessions/legacy-root.jsonl +5 -0
- dj_digger-0.1.0/tests/fixtures/codex_sessions/malformed-and-unknown.jsonl +3 -0
- dj_digger-0.1.0/tests/fixtures/codex_sessions/paginated-root.jsonl +4 -0
- dj_digger-0.1.0/tests/fixtures/codex_sessions/qa-repair-cycle.jsonl +4 -0
- dj_digger-0.1.0/tests/fixtures/codex_sessions/root-with-subagent-child-one.jsonl +3 -0
- dj_digger-0.1.0/tests/fixtures/codex_sessions/root-with-subagent-child-two.jsonl +3 -0
- dj_digger-0.1.0/tests/fixtures/codex_sessions/root-with-subagent.jsonl +4 -0
- dj_digger-0.1.0/tests/fixtures/database-inside-source.toml +9 -0
- dj_digger-0.1.0/tests/fixtures/dj-analysis-run.json +14 -0
- dj_digger-0.1.0/tests/fixtures/dj-analysis.tsv +2 -0
- dj_digger-0.1.0/tests/fixtures/dj-digger.toml +15 -0
- dj_digger-0.1.0/tests/fixtures/dj-sections.jsonl +1 -0
- dj_digger-0.1.0/tests/fixtures/duplicate-source-id.toml +15 -0
- dj_digger-0.1.0/tests/fixtures/exports-inside-source.toml +9 -0
- dj_digger-0.1.0/tests/fixtures/mastering/README.md +5 -0
- dj_digger-0.1.0/tests/fixtures/tracks.tsv +2 -0
- dj_digger-0.1.0/tests/integration/analysis_fixture.py +72 -0
- dj_digger-0.1.0/tests/integration/test_copy_set_compatibility.py +94 -0
- dj_digger-0.1.0/tests/integration/test_scan_history.py +95 -0
- dj_digger-0.1.0/tests/integration/test_tranche7_acceptance.py +252 -0
- dj_digger-0.1.0/tests/integration/test_v1a_pipeline.py +72 -0
- dj_digger-0.1.0/tests/integration/test_v1b_cutover.py +91 -0
- dj_digger-0.1.0/tests/mastering_fixture.py +28 -0
- dj_digger-0.1.0/tests/performance/README.md +219 -0
- dj_digger-0.1.0/tests/performance/__init__.py +1 -0
- dj_digger-0.1.0/tests/performance/benchmark_queries.py +416 -0
- dj_digger-0.1.0/tests/performance/fixtures.py +326 -0
- dj_digger-0.1.0/tests/performance/query_plans.py +28 -0
- dj_digger-0.1.0/tests/test_agent_benchmark.py +101 -0
- dj_digger-0.1.0/tests/test_agent_benchmark_compare.py +84 -0
- dj_digger-0.1.0/tests/test_analysis_eligibility.py +158 -0
- dj_digger-0.1.0/tests/test_analysis_exporters.py +171 -0
- dj_digger-0.1.0/tests/test_analysis_persistence.py +156 -0
- dj_digger-0.1.0/tests/test_analysis_pipeline.py +500 -0
- dj_digger-0.1.0/tests/test_analysis_worker.py +252 -0
- dj_digger-0.1.0/tests/test_application_contracts.py +369 -0
- dj_digger-0.1.0/tests/test_artifacts.py +28 -0
- dj_digger-0.1.0/tests/test_background_jobs.py +87 -0
- dj_digger-0.1.0/tests/test_catalog_migrations.py +601 -0
- dj_digger-0.1.0/tests/test_cli.py +151 -0
- dj_digger-0.1.0/tests/test_cli_analyze.py +165 -0
- dj_digger-0.1.0/tests/test_cli_background.py +121 -0
- dj_digger-0.1.0/tests/test_cli_completion.py +125 -0
- dj_digger-0.1.0/tests/test_cli_copy.py +184 -0
- dj_digger-0.1.0/tests/test_cli_duplicates.py +277 -0
- dj_digger-0.1.0/tests/test_cli_mcp.py +21 -0
- dj_digger-0.1.0/tests/test_cli_refresh.py +186 -0
- dj_digger-0.1.0/tests/test_cli_status_codes.py +75 -0
- dj_digger-0.1.0/tests/test_cli_status_doctor.py +209 -0
- dj_digger-0.1.0/tests/test_config.py +135 -0
- dj_digger-0.1.0/tests/test_curation_catalog.py +93 -0
- dj_digger-0.1.0/tests/test_current_analysis.py +288 -0
- dj_digger-0.1.0/tests/test_database.py +94 -0
- dj_digger-0.1.0/tests/test_database_commands.py +111 -0
- dj_digger-0.1.0/tests/test_docker_agent_contract.py +34 -0
- dj_digger-0.1.0/tests/test_docker_smoke.py +129 -0
- dj_digger-0.1.0/tests/test_duplicate_fingerprint.py +193 -0
- dj_digger-0.1.0/tests/test_duplicate_quality.py +210 -0
- dj_digger-0.1.0/tests/test_duplicates_service.py +236 -0
- dj_digger-0.1.0/tests/test_ebur128.py +68 -0
- dj_digger-0.1.0/tests/test_exiftool.py +402 -0
- dj_digger-0.1.0/tests/test_extractor.py +287 -0
- dj_digger-0.1.0/tests/test_ffmpeg.py +292 -0
- dj_digger-0.1.0/tests/test_golden_set.py +44 -0
- dj_digger-0.1.0/tests/test_library_pilot_reporting.py +25 -0
- dj_digger-0.1.0/tests/test_lifecycle.py +286 -0
- dj_digger-0.1.0/tests/test_mastering_comparison.py +42 -0
- dj_digger-0.1.0/tests/test_mastering_integration.py +15 -0
- dj_digger-0.1.0/tests/test_mastering_metrics.py +84 -0
- dj_digger-0.1.0/tests/test_mastering_persistence.py +104 -0
- dj_digger-0.1.0/tests/test_mcp_server.py +34 -0
- dj_digger-0.1.0/tests/test_packaging.py +54 -0
- dj_digger-0.1.0/tests/test_performance_fixtures.py +71 -0
- dj_digger-0.1.0/tests/test_playlist_emission.py +36 -0
- dj_digger-0.1.0/tests/test_progress.py +33 -0
- dj_digger-0.1.0/tests/test_query_plans.py +235 -0
- dj_digger-0.1.0/tests/test_read_repositories.py +188 -0
- dj_digger-0.1.0/tests/test_rhythm.py +166 -0
- dj_digger-0.1.0/tests/test_scanner.py +58 -0
- dj_digger-0.1.0/tests/test_segmentation.py +42 -0
- dj_digger-0.1.0/tests/test_semantics.py +29 -0
- dj_digger-0.1.0/tests/test_set_copy.py +415 -0
- dj_digger-0.1.0/tests/test_set_schema.py +121 -0
- dj_digger-0.1.0/tests/test_skill_tranche6.py +96 -0
- dj_digger-0.1.0/tests/test_snapshot.py +77 -0
- dj_digger-0.1.0/tests/test_spectrum.py +50 -0
- dj_digger-0.1.0/tests/test_sqlite_concurrency.py +283 -0
- dj_digger-0.1.0/tests/test_strict_current_contracts.py +173 -0
- dj_digger-0.1.0/tests/test_tracks_export.py +342 -0
- dj_digger-0.1.0/tests/test_windows.py +26 -0
- dj_digger-0.1.0/tests/validate_fixtures.py +143 -0
- dj_digger-0.1.0/uv.lock +1197 -0
|
@@ -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,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.
|