tracemantle 1.6.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.
- tracemantle-1.6.0/.gitattributes +5 -0
- tracemantle-1.6.0/.github/banner.svg +26 -0
- tracemantle-1.6.0/.github/workflows/ci.yml +112 -0
- tracemantle-1.6.0/.github/workflows/compare.yml +51 -0
- tracemantle-1.6.0/.github/workflows/release-notes.yml +98 -0
- tracemantle-1.6.0/.github/workflows/release.yml +130 -0
- tracemantle-1.6.0/.gitignore +37 -0
- tracemantle-1.6.0/.pre-commit-hooks.yaml +7 -0
- tracemantle-1.6.0/CHANGELOG.md +376 -0
- tracemantle-1.6.0/CONTRIBUTING.md +42 -0
- tracemantle-1.6.0/LICENSE +21 -0
- tracemantle-1.6.0/Makefile +47 -0
- tracemantle-1.6.0/PKG-INFO +126 -0
- tracemantle-1.6.0/README.md +90 -0
- tracemantle-1.6.0/REMEDIATION-EVIDENCE.md +765 -0
- tracemantle-1.6.0/action.yml +213 -0
- tracemantle-1.6.0/constraints-dev.txt +46 -0
- tracemantle-1.6.0/docs/SkillCheck_Technical_Debt_and_Product_Plan.docx +0 -0
- tracemantle-1.6.0/docs/case-study-silent-skill-failure.md +148 -0
- tracemantle-1.6.0/docs/case-study-v1-real-world-runs.md +141 -0
- tracemantle-1.6.0/docs/contracts.md +13 -0
- tracemantle-1.6.0/docs/evidence-workflow.md +68 -0
- tracemantle-1.6.0/docs/generated-reference.md +134 -0
- tracemantle-1.6.0/docs/implementation-status.md +82 -0
- tracemantle-1.6.0/docs/migration.md +59 -0
- tracemantle-1.6.0/docs/profiles.md +20 -0
- tracemantle-1.6.0/docs/rename-checklist.md +31 -0
- tracemantle-1.6.0/docs/verification/baseline-build.txt +12 -0
- tracemantle-1.6.0/docs/verification/baseline-controlled-performance.json +123 -0
- tracemantle-1.6.0/docs/verification/baseline-performance.json +92 -0
- tracemantle-1.6.0/docs/verification/baseline-tests.txt +74 -0
- tracemantle-1.6.0/docs/verification/calibration-v1.json +84 -0
- tracemantle-1.6.0/docs/verification/conformance.json +124 -0
- tracemantle-1.6.0/docs/verification/current-performance.json +133 -0
- tracemantle-1.6.0/docs/verification/name-audit.md +485 -0
- tracemantle-1.6.0/docs/verification/name-inventory-before.txt +132 -0
- tracemantle-1.6.0/docs/verification/performance.md +34 -0
- tracemantle-1.6.0/docs/verification/remote-ci.json +296 -0
- tracemantle-1.6.0/docs/verification/self-host.json +80 -0
- tracemantle-1.6.0/docs/verification/tests-python310.txt +87 -0
- tracemantle-1.6.0/docs/verification/tests-python312-tokenizer.txt +92 -0
- tracemantle-1.6.0/pyproject.toml +122 -0
- tracemantle-1.6.0/scripts/benchmark.py +135 -0
- tracemantle-1.6.0/scripts/calibrate_advisories.py +50 -0
- tracemantle-1.6.0/scripts/check_changelog_release.py +104 -0
- tracemantle-1.6.0/scripts/generate_reference.py +50 -0
- tracemantle-1.6.0/scripts/measure_token_error.py +144 -0
- tracemantle-1.6.0/scripts/regen_mode_conflict_fixture.py +75 -0
- tracemantle-1.6.0/scripts/regen_self_host_fixtures.py +52 -0
- tracemantle-1.6.0/scripts/score_corpus.py +118 -0
- tracemantle-1.6.0/scripts/summarize_batch.py +337 -0
- tracemantle-1.6.0/scripts/tracemantle_case_study_report.py +374 -0
- tracemantle-1.6.0/scripts/verify_artifacts.py +98 -0
- tracemantle-1.6.0/scripts/verify_reference_corpus.py +69 -0
- tracemantle-1.6.0/skills/tracemantle/SKILL.md +92 -0
- tracemantle-1.6.0/src/skillcheck/__init__.py +16 -0
- tracemantle-1.6.0/src/skillcheck/agents/__init__.py +2 -0
- tracemantle-1.6.0/src/skillcheck/agents/_ingest.py +2 -0
- tracemantle-1.6.0/src/skillcheck/agents/_response_text.py +2 -0
- tracemantle-1.6.0/src/skillcheck/agents/base.py +2 -0
- tracemantle-1.6.0/src/skillcheck/agents/claude.py +2 -0
- tracemantle-1.6.0/src/skillcheck/agents/codex.py +2 -0
- tracemantle-1.6.0/src/skillcheck/agents/cursor.py +2 -0
- tracemantle-1.6.0/src/skillcheck/agents/graph_base.py +2 -0
- tracemantle-1.6.0/src/skillcheck/agents/graph_claude.py +2 -0
- tracemantle-1.6.0/src/skillcheck/agents/graph_codex.py +2 -0
- tracemantle-1.6.0/src/skillcheck/agents/graph_cursor.py +2 -0
- tracemantle-1.6.0/src/skillcheck/agents/graph_parser.py +2 -0
- tracemantle-1.6.0/src/skillcheck/agents/parser.py +2 -0
- tracemantle-1.6.0/src/skillcheck/agents/schema.py +2 -0
- tracemantle-1.6.0/src/skillcheck/core/__init__.py +2 -0
- tracemantle-1.6.0/src/skillcheck/core/activation.py +2 -0
- tracemantle-1.6.0/src/skillcheck/core/activation_render.py +2 -0
- tracemantle-1.6.0/src/skillcheck/core/graph.py +2 -0
- tracemantle-1.6.0/src/skillcheck/core/graph_analyzers.py +2 -0
- tracemantle-1.6.0/src/skillcheck/core/graph_model.py +2 -0
- tracemantle-1.6.0/src/skillcheck/core/graph_render.py +2 -0
- tracemantle-1.6.0/src/skillcheck/core/history.py +2 -0
- tracemantle-1.6.0/src/skillcheck/core/history_io.py +2 -0
- tracemantle-1.6.0/src/skillcheck/core/semantic.py +2 -0
- tracemantle-1.6.0/src/skillcheck/core/symbolic.py +2 -0
- tracemantle-1.6.0/src/skillcheck/parser.py +2 -0
- tracemantle-1.6.0/src/skillcheck/result.py +2 -0
- tracemantle-1.6.0/src/skillcheck/schemas/critique-v1.json +73 -0
- tracemantle-1.6.0/src/skillcheck/schemas/graph-v1.json +79 -0
- tracemantle-1.6.0/src/tracemantle/__init__.py +15 -0
- tracemantle-1.6.0/src/tracemantle/__main__.py +6 -0
- tracemantle-1.6.0/src/tracemantle/agents/__init__.py +123 -0
- tracemantle-1.6.0/src/tracemantle/agents/_ingest.py +160 -0
- tracemantle-1.6.0/src/tracemantle/agents/_response_text.py +44 -0
- tracemantle-1.6.0/src/tracemantle/agents/base.py +171 -0
- tracemantle-1.6.0/src/tracemantle/agents/claude.py +25 -0
- tracemantle-1.6.0/src/tracemantle/agents/codex.py +63 -0
- tracemantle-1.6.0/src/tracemantle/agents/cursor.py +65 -0
- tracemantle-1.6.0/src/tracemantle/agents/graph_base.py +225 -0
- tracemantle-1.6.0/src/tracemantle/agents/graph_claude.py +25 -0
- tracemantle-1.6.0/src/tracemantle/agents/graph_codex.py +62 -0
- tracemantle-1.6.0/src/tracemantle/agents/graph_cursor.py +62 -0
- tracemantle-1.6.0/src/tracemantle/agents/graph_parser.py +312 -0
- tracemantle-1.6.0/src/tracemantle/agents/parser.py +242 -0
- tracemantle-1.6.0/src/tracemantle/agents/schema.py +105 -0
- tracemantle-1.6.0/src/tracemantle/bundle.py +145 -0
- tracemantle-1.6.0/src/tracemantle/cli.py +427 -0
- tracemantle-1.6.0/src/tracemantle/commands.py +747 -0
- tracemantle-1.6.0/src/tracemantle/comparison.py +135 -0
- tracemantle-1.6.0/src/tracemantle/config.py +76 -0
- tracemantle-1.6.0/src/tracemantle/config_loader.py +255 -0
- tracemantle-1.6.0/src/tracemantle/core/__init__.py +101 -0
- tracemantle-1.6.0/src/tracemantle/core/activation.py +197 -0
- tracemantle-1.6.0/src/tracemantle/core/activation_render.py +80 -0
- tracemantle-1.6.0/src/tracemantle/core/graph.py +486 -0
- tracemantle-1.6.0/src/tracemantle/core/graph_analyzers.py +349 -0
- tracemantle-1.6.0/src/tracemantle/core/graph_model.py +110 -0
- tracemantle-1.6.0/src/tracemantle/core/graph_render.py +101 -0
- tracemantle-1.6.0/src/tracemantle/core/history.py +354 -0
- tracemantle-1.6.0/src/tracemantle/core/history_io.py +276 -0
- tracemantle-1.6.0/src/tracemantle/core/semantic.py +189 -0
- tracemantle-1.6.0/src/tracemantle/core/symbolic.py +82 -0
- tracemantle-1.6.0/src/tracemantle/dependencies.py +91 -0
- tracemantle-1.6.0/src/tracemantle/display.py +14 -0
- tracemantle-1.6.0/src/tracemantle/evidence.py +106 -0
- tracemantle-1.6.0/src/tracemantle/formatters.py +330 -0
- tracemantle-1.6.0/src/tracemantle/history_store.py +81 -0
- tracemantle-1.6.0/src/tracemantle/io_limits.py +200 -0
- tracemantle-1.6.0/src/tracemantle/markdown.py +91 -0
- tracemantle-1.6.0/src/tracemantle/modes.py +222 -0
- tracemantle-1.6.0/src/tracemantle/parser.py +142 -0
- tracemantle-1.6.0/src/tracemantle/policy.py +119 -0
- tracemantle-1.6.0/src/tracemantle/product_commands.py +139 -0
- tracemantle-1.6.0/src/tracemantle/profiles/compatibility-v1.json +40 -0
- tracemantle-1.6.0/src/tracemantle/promptfoo.py +77 -0
- tracemantle-1.6.0/src/tracemantle/py.typed +0 -0
- tracemantle-1.6.0/src/tracemantle/result.py +68 -0
- tracemantle-1.6.0/src/tracemantle/rules/__init__.py +171 -0
- tracemantle-1.6.0/src/tracemantle/rules/compat.py +221 -0
- tracemantle-1.6.0/src/tracemantle/rules/description.py +427 -0
- tracemantle-1.6.0/src/tracemantle/rules/disclosure.py +155 -0
- tracemantle-1.6.0/src/tracemantle/rules/frontmatter.py +45 -0
- tracemantle-1.6.0/src/tracemantle/rules/frontmatter_common.py +63 -0
- tracemantle-1.6.0/src/tracemantle/rules/frontmatter_description.py +144 -0
- tracemantle-1.6.0/src/tracemantle/rules/frontmatter_fields.py +96 -0
- tracemantle-1.6.0/src/tracemantle/rules/frontmatter_name.py +186 -0
- tracemantle-1.6.0/src/tracemantle/rules/references.py +29 -0
- tracemantle-1.6.0/src/tracemantle/rules/sizing.py +48 -0
- tracemantle-1.6.0/src/tracemantle/rules/template.py +26 -0
- tracemantle-1.6.0/src/tracemantle/schemas/critique-v1.json +73 -0
- tracemantle-1.6.0/src/tracemantle/schemas/evidence-v1.json +165 -0
- tracemantle-1.6.0/src/tracemantle/schemas/graph-v1.json +79 -0
- tracemantle-1.6.0/src/tracemantle/storage.py +95 -0
- tracemantle-1.6.0/src/tracemantle/template_detection.py +42 -0
- tracemantle-1.6.0/src/tracemantle/tokenizer.py +40 -0
- tracemantle-1.6.0/tests/__init__.py +0 -0
- tracemantle-1.6.0/tests/conftest.py +43 -0
- tracemantle-1.6.0/tests/fixtures/bad_body_long.md +505 -0
- tracemantle-1.6.0/tests/fixtures/bad_desc_empty.md +6 -0
- tracemantle-1.6.0/tests/fixtures/bad_desc_person.md +6 -0
- tracemantle-1.6.0/tests/fixtures/bad_desc_quality.md +8 -0
- tracemantle-1.6.0/tests/fixtures/bad_field_typo.md +7 -0
- tracemantle-1.6.0/tests/fixtures/bad_frontmatter_int.md +4 -0
- tracemantle-1.6.0/tests/fixtures/bad_frontmatter_list.md +6 -0
- tracemantle-1.6.0/tests/fixtures/bad_frontmatter_string.md +4 -0
- tracemantle-1.6.0/tests/fixtures/bad_name_caps.md +6 -0
- tracemantle-1.6.0/tests/fixtures/bad_name_consecutive_hyphens.md +6 -0
- tracemantle-1.6.0/tests/fixtures/bad_name_leading_hyphen.md +6 -0
- tracemantle-1.6.0/tests/fixtures/bad_name_long.md +6 -0
- tracemantle-1.6.0/tests/fixtures/bad_name_reserved.md +6 -0
- tracemantle-1.6.0/tests/fixtures/bad_name_trailing_hyphen.md +6 -0
- tracemantle-1.6.0/tests/fixtures/bad_no_frontmatter.md +4 -0
- tracemantle-1.6.0/tests/fixtures/bad_refs.md +14 -0
- tracemantle-1.6.0/tests/fixtures/canvas_design_pattern.md +6 -0
- tracemantle-1.6.0/tests/fixtures/claude_api_name.md +6 -0
- tracemantle-1.6.0/tests/fixtures/claude_only_fields.md +13 -0
- tracemantle-1.6.0/tests/fixtures/critique/malformed_prose_preamble.txt +10 -0
- tracemantle-1.6.0/tests/fixtures/critique/minimal_valid.md +6 -0
- tracemantle-1.6.0/tests/fixtures/critique/multi_section.md +31 -0
- tracemantle-1.6.0/tests/fixtures/critique/response_ansi_injection.json +10 -0
- tracemantle-1.6.0/tests/fixtures/critique/response_clean.json +8 -0
- tracemantle-1.6.0/tests/fixtures/critique/response_contradiction.json +14 -0
- tracemantle-1.6.0/tests/fixtures/critique/response_findings_mixed.json +27 -0
- tracemantle-1.6.0/tests/fixtures/critique/response_malformed.json +2 -0
- tracemantle-1.6.0/tests/fixtures/critique/response_schema_error.json +8 -0
- tracemantle-1.6.0/tests/fixtures/critique/response_warnings.json +8 -0
- tracemantle-1.6.0/tests/fixtures/critique/with_code_blocks.md +34 -0
- tracemantle-1.6.0/tests/fixtures/cursor_desc_folded_keep.md +12 -0
- tracemantle-1.6.0/tests/fixtures/cursor_desc_folded_strip.md +12 -0
- tracemantle-1.6.0/tests/fixtures/cursor_desc_literal.md +12 -0
- tracemantle-1.6.0/tests/fixtures/frontmatter_heading_partial.md +10 -0
- tracemantle-1.6.0/tests/fixtures/frontmatter_name_as_heading.md +10 -0
- tracemantle-1.6.0/tests/fixtures/golden/report.agent.txt +12 -0
- tracemantle-1.6.0/tests/fixtures/golden/report.github.txt +5 -0
- tracemantle-1.6.0/tests/fixtures/golden/report.json.txt +84 -0
- tracemantle-1.6.0/tests/fixtures/golden/report.markdown.txt +22 -0
- tracemantle-1.6.0/tests/fixtures/golden/report.text.txt +13 -0
- tracemantle-1.6.0/tests/fixtures/golden/report.text_plain.txt +10 -0
- tracemantle-1.6.0/tests/fixtures/graph/skill_basic_io.md +23 -0
- tracemantle-1.6.0/tests/fixtures/graph/skill_duplicate_section.md +17 -0
- tracemantle-1.6.0/tests/fixtures/graph/skill_duplicate_tools.md +10 -0
- tracemantle-1.6.0/tests/fixtures/graph/skill_empty_capability.md +13 -0
- tracemantle-1.6.0/tests/fixtures/graph/skill_frontmatter_tools.md +11 -0
- tracemantle-1.6.0/tests/fixtures/graph/skill_imperative_capabilities.md +25 -0
- tracemantle-1.6.0/tests/fixtures/graph/skill_no_structure.md +10 -0
- tracemantle-1.6.0/tests/fixtures/graph/skill_orphan_capability.md +12 -0
- tracemantle-1.6.0/tests/fixtures/graph/skill_section_aliases.md +18 -0
- tracemantle-1.6.0/tests/fixtures/graph/skill_unproduced_output.md +15 -0
- tracemantle-1.6.0/tests/fixtures/graph/skill_unreferenced_tool.md +13 -0
- tracemantle-1.6.0/tests/fixtures/graph/skill_unused_input.md +20 -0
- tracemantle-1.6.0/tests/fixtures/graph_responses/response_bad_line.json +13 -0
- tracemantle-1.6.0/tests/fixtures/graph_responses/response_clean.json +54 -0
- tracemantle-1.6.0/tests/fixtures/graph_responses/response_extra_capabilities.json +57 -0
- tracemantle-1.6.0/tests/fixtures/graph_responses/response_malformed.json +3 -0
- tracemantle-1.6.0/tests/fixtures/graph_responses/response_schema_error.json +6 -0
- tracemantle-1.6.0/tests/fixtures/graph_responses/response_with_contradiction.json +55 -0
- tracemantle-1.6.0/tests/fixtures/history/ledger_bad_version.json +1 -0
- tracemantle-1.6.0/tests/fixtures/history/ledger_malformed.json +1 -0
- tracemantle-1.6.0/tests/fixtures/history/ledger_malformed_entry.json +1 -0
- tracemantle-1.6.0/tests/fixtures/history/ledger_multi_run_passing.json +69 -0
- tracemantle-1.6.0/tests/fixtures/history/ledger_one_run.json +27 -0
- tracemantle-1.6.0/tests/fixtures/history/ledger_root_list.json +1 -0
- tracemantle-1.6.0/tests/fixtures/history/ledger_runs_not_list.json +1 -0
- tracemantle-1.6.0/tests/fixtures/history/ledger_with_regression.json +48 -0
- tracemantle-1.6.0/tests/fixtures/homepage_field.md +7 -0
- tracemantle-1.6.0/tests/fixtures/license_field.md +7 -0
- tracemantle-1.6.0/tests/fixtures/metadata_field.md +18 -0
- tracemantle-1.6.0/tests/fixtures/mode_conflicts.json +362 -0
- tracemantle-1.6.0/tests/fixtures/non_template_bracket_acronym.md +7 -0
- tracemantle-1.6.0/tests/fixtures/non_template_with_placeholder_word.md +6 -0
- tracemantle-1.6.0/tests/fixtures/repository_field.md +7 -0
- tracemantle-1.6.0/tests/fixtures/self_host/critique_clean.json +8 -0
- tracemantle-1.6.0/tests/fixtures/self_host/graph_clean.json +130 -0
- tracemantle-1.6.0/tests/fixtures/template_bracket_placeholder.md +7 -0
- tracemantle-1.6.0/tests/fixtures/template_explicit_flag.md +7 -0
- tracemantle-1.6.0/tests/fixtures/template_placeholder_description.md +6 -0
- tracemantle-1.6.0/tests/fixtures/template_with_real_violations.md +7 -0
- tracemantle-1.6.0/tests/fixtures/templates/SKILL.md +6 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/README.md +5 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/bad-compatibility.md +7 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/bad-metadata-values.md +8 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/bad-metadata.md +7 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/boolean-key.md +7 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/changed-permission.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/control.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/controls.md +6 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/description-change.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/duplicate-name.md +7 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/duplicate-nested.md +9 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/external-links.md +7 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/failed.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/fenced-links.md +12 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/future.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/helper-change.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/incomplete.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/inferred.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/infrastructure.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/inline-close.md +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/mapping-key.md +8 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/missing-evidence.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/model-alias.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/model-judgment.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/nonstring-key.md +7 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/recursive-alias.md +8 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/reference-links.md +8 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/skipped.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/stale.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/untrusted.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/valid-alias.md +9 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/valid-bom.md +6 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/valid-crlf.md +6 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/valid-empty-block.md +3 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/valid-multiline.md +8 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/valid-standard.md +10 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/wrong-bundle.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/wrong-checker.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/wrong-config.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/wrong-fixture.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/cases/wrong-profile.json +4 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/held-out/code-json.txt +100 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/held-out/code-python.txt +200 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/held-out/large.txt +1200 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/held-out/prose-ar.txt +30 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/held-out/prose-en.txt +30 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/held-out/prose-es.txt +30 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/held-out/prose-ja.txt +30 -0
- tracemantle-1.6.0/tests/fixtures/tracemantle/held-out/small.txt +1 -0
- tracemantle-1.6.0/tests/fixtures/unknown_field.md +7 -0
- tracemantle-1.6.0/tests/fixtures/upstream/promptfoo-0.118.10/LICENSE +19 -0
- tracemantle-1.6.0/tests/fixtures/upstream/promptfoo-0.118.10/PROVENANCE.json +9 -0
- tracemantle-1.6.0/tests/fixtures/upstream/promptfoo-0.118.10/sample-export.json +692 -0
- tracemantle-1.6.0/tests/fixtures/upstream/skills-ref-69ef37e/LICENSE +202 -0
- tracemantle-1.6.0/tests/fixtures/upstream/skills-ref-69ef37e/PROVENANCE.json +55 -0
- tracemantle-1.6.0/tests/fixtures/upstream/skills-ref-69ef37e/README.md +113 -0
- tracemantle-1.6.0/tests/fixtures/upstream/skills-ref-69ef37e/pyproject.toml +30 -0
- tracemantle-1.6.0/tests/fixtures/upstream/skills-ref-69ef37e/skills_ref/__init__.py +20 -0
- tracemantle-1.6.0/tests/fixtures/upstream/skills-ref-69ef37e/skills_ref/cli.py +105 -0
- tracemantle-1.6.0/tests/fixtures/upstream/skills-ref-69ef37e/skills_ref/errors.py +25 -0
- tracemantle-1.6.0/tests/fixtures/upstream/skills-ref-69ef37e/skills_ref/models.py +39 -0
- tracemantle-1.6.0/tests/fixtures/upstream/skills-ref-69ef37e/skills_ref/parser.py +112 -0
- tracemantle-1.6.0/tests/fixtures/upstream/skills-ref-69ef37e/skills_ref/prompt.py +58 -0
- tracemantle-1.6.0/tests/fixtures/upstream/skills-ref-69ef37e/skills_ref/validator.py +177 -0
- tracemantle-1.6.0/tests/fixtures/user_extension/skillcheck.toml +2 -0
- tracemantle-1.6.0/tests/fixtures/user_extension/user_extension_field.md +7 -0
- tracemantle-1.6.0/tests/fixtures/valid_basic.md +6 -0
- tracemantle-1.6.0/tests/fixtures/valid_full.md +23 -0
- tracemantle-1.6.0/tests/fixtures/valid_good_desc.md +8 -0
- tracemantle-1.6.0/tests/golden/claude-doc-helper/SKILL.md +6 -0
- tracemantle-1.6.0/tests/golden/claude-doc-helper/expected.txt +2 -0
- tracemantle-1.6.0/tests/golden/clean-baseline/SKILL.md +6 -0
- tracemantle-1.6.0/tests/golden/clean-baseline/expected.txt +1 -0
- tracemantle-1.6.0/tests/golden/person-voice-first/SKILL.md +6 -0
- tracemantle-1.6.0/tests/golden/person-voice-first/expected.txt +2 -0
- tracemantle-1.6.0/tests/golden/person-voice-second/SKILL.md +6 -0
- tracemantle-1.6.0/tests/golden/person-voice-second/expected.txt +2 -0
- tracemantle-1.6.0/tests/golden/unknown-fields/SKILL.md +9 -0
- tracemantle-1.6.0/tests/golden/unknown-fields/expected.txt +3 -0
- tracemantle-1.6.0/tests/test_activation.py +211 -0
- tracemantle-1.6.0/tests/test_agent_prompts.py +199 -0
- tracemantle-1.6.0/tests/test_agent_prompts_smoke.py +152 -0
- tracemantle-1.6.0/tests/test_batch15_summarize.py +86 -0
- tracemantle-1.6.0/tests/test_build_plan_acceptance.py +142 -0
- tracemantle-1.6.0/tests/test_build_plan_core.py +164 -0
- tracemantle-1.6.0/tests/test_build_plan_product.py +276 -0
- tracemantle-1.6.0/tests/test_changelog_release_check.py +99 -0
- tracemantle-1.6.0/tests/test_cli.py +429 -0
- tracemantle-1.6.0/tests/test_cli_critique.py +320 -0
- tracemantle-1.6.0/tests/test_cli_critique_agent.py +142 -0
- tracemantle-1.6.0/tests/test_cli_graph.py +224 -0
- tracemantle-1.6.0/tests/test_cli_graph_agent.py +303 -0
- tracemantle-1.6.0/tests/test_cli_history.py +453 -0
- tracemantle-1.6.0/tests/test_compat.py +286 -0
- tracemantle-1.6.0/tests/test_compat_data_freshness.py +97 -0
- tracemantle-1.6.0/tests/test_config_loader.py +88 -0
- tracemantle-1.6.0/tests/test_config_validation.py +190 -0
- tracemantle-1.6.0/tests/test_critique_parser.py +303 -0
- tracemantle-1.6.0/tests/test_critique_prompt.py +137 -0
- tracemantle-1.6.0/tests/test_critique_schema.py +212 -0
- tracemantle-1.6.0/tests/test_description.py +289 -0
- tracemantle-1.6.0/tests/test_description_scorer_tuning.py +220 -0
- tracemantle-1.6.0/tests/test_disclosure.py +198 -0
- tracemantle-1.6.0/tests/test_explain_score.py +207 -0
- tracemantle-1.6.0/tests/test_fail_on_regression.py +197 -0
- tracemantle-1.6.0/tests/test_format_github.py +118 -0
- tracemantle-1.6.0/tests/test_formatter_golden.py +238 -0
- tracemantle-1.6.0/tests/test_frontmatter.py +416 -0
- tracemantle-1.6.0/tests/test_golden_warnings.py +125 -0
- tracemantle-1.6.0/tests/test_graph_analyzers.py +194 -0
- tracemantle-1.6.0/tests/test_graph_divergence.py +170 -0
- tracemantle-1.6.0/tests/test_graph_heuristic.py +556 -0
- tracemantle-1.6.0/tests/test_graph_parser.py +283 -0
- tracemantle-1.6.0/tests/test_graph_prompts.py +179 -0
- tracemantle-1.6.0/tests/test_graph_render.py +186 -0
- tracemantle-1.6.0/tests/test_history_io.py +276 -0
- tracemantle-1.6.0/tests/test_history_model.py +259 -0
- tracemantle-1.6.0/tests/test_history_regression.py +135 -0
- tracemantle-1.6.0/tests/test_ingest_sanitization.py +71 -0
- tracemantle-1.6.0/tests/test_io_limits.py +128 -0
- tracemantle-1.6.0/tests/test_measure_token_error.py +73 -0
- tracemantle-1.6.0/tests/test_mode_conflicts.py +215 -0
- tracemantle-1.6.0/tests/test_name_compliance.py +119 -0
- tracemantle-1.6.0/tests/test_parser.py +95 -0
- tracemantle-1.6.0/tests/test_pre_commit.py +85 -0
- tracemantle-1.6.0/tests/test_published_schemas.py +170 -0
- tracemantle-1.6.0/tests/test_readme_test_count_claim.py +54 -0
- tracemantle-1.6.0/tests/test_references.py +292 -0
- tracemantle-1.6.0/tests/test_self_host.py +148 -0
- tracemantle-1.6.0/tests/test_semantic_bridge.py +400 -0
- tracemantle-1.6.0/tests/test_sizing.py +94 -0
- tracemantle-1.6.0/tests/test_template_detection.py +24 -0
- tracemantle-1.6.0/tests/test_tokenizer.py +56 -0
- tracemantle-1.6.0/tests/test_type_annotations.py +20 -0
- tracemantle-1.6.0/tests/test_untrusted_input.py +307 -0
- tracemantle-1.6.0/tests/test_v1_2_false_positive_fixes.py +189 -0
- tracemantle-1.6.0/tests/test_v1_architecture.py +87 -0
- tracemantle-1.6.0/tests/test_v1_completion.py +91 -0
- tracemantle-1.6.0/tests/test_version_coherence.py +117 -0
- tracemantle-1.6.0/tests/test_yaml_anchors.py +99 -0
- tracemantle-1.6.0/tests/test_yaml_types.py +120 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 200" fill="none">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bg" x1="0" y1="0" x2="800" y2="200" gradientUnits="userSpaceOnUse">
|
|
4
|
+
<stop offset="0%" stop-color="#0f0f23"/>
|
|
5
|
+
<stop offset="100%" stop-color="#1a1a3e"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="accent" x1="0" y1="0" x2="1" y2="1">
|
|
8
|
+
<stop offset="0%" stop-color="#d4a574"/>
|
|
9
|
+
<stop offset="100%" stop-color="#e8c9a0"/>
|
|
10
|
+
</linearGradient>
|
|
11
|
+
</defs>
|
|
12
|
+
<rect width="800" height="200" rx="12" fill="url(#bg)"/>
|
|
13
|
+
<!-- check icon -->
|
|
14
|
+
<g transform="translate(220, 55)">
|
|
15
|
+
<circle cx="40" cy="40" r="36" stroke="url(#accent)" stroke-width="3" fill="none" opacity="0.9"/>
|
|
16
|
+
<polyline points="22,42 36,56 60,28" stroke="#4ade80" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
|
17
|
+
</g>
|
|
18
|
+
<!-- title -->
|
|
19
|
+
<text x="400" y="108" text-anchor="middle" font-family="ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace" font-size="42" font-weight="700" fill="url(#accent)">
|
|
20
|
+
<tspan dx="52">TraceMantle</tspan>
|
|
21
|
+
</text>
|
|
22
|
+
<!-- subtitle -->
|
|
23
|
+
<text x="400" y="142" text-anchor="middle" font-family="-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif" font-size="15" fill="#8b8ba7" letter-spacing="0.5">
|
|
24
|
+
Static analysis and release evidence for agent skill bundles
|
|
25
|
+
</text>
|
|
26
|
+
</svg>
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
workflow_call:
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
pull_request:
|
|
9
|
+
branches: [main]
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
test:
|
|
16
|
+
runs-on: ${{ matrix.os }}
|
|
17
|
+
strategy:
|
|
18
|
+
fail-fast: false
|
|
19
|
+
matrix:
|
|
20
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
21
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
22
|
+
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
25
|
+
|
|
26
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
27
|
+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
|
28
|
+
with:
|
|
29
|
+
python-version: ${{ matrix.python-version }}
|
|
30
|
+
|
|
31
|
+
- name: Install dependencies
|
|
32
|
+
run: |
|
|
33
|
+
python -m pip install --upgrade pip
|
|
34
|
+
pip install -c constraints-dev.txt -e ".[dev]"
|
|
35
|
+
|
|
36
|
+
- name: Run tests
|
|
37
|
+
# The coverage floor is applied here rather than in pyproject addopts,
|
|
38
|
+
# which would also fail single-file local runs. See the comment there.
|
|
39
|
+
run: python -m pytest tests/ -v --tb=short --cov-fail-under=80
|
|
40
|
+
|
|
41
|
+
lint:
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
45
|
+
|
|
46
|
+
- name: Set up Python
|
|
47
|
+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
|
48
|
+
with:
|
|
49
|
+
python-version: "3.12"
|
|
50
|
+
|
|
51
|
+
- name: Install dev dependencies
|
|
52
|
+
run: pip install -c constraints-dev.txt -e ".[dev]"
|
|
53
|
+
|
|
54
|
+
- name: Ruff check
|
|
55
|
+
run: ruff check src tests scripts
|
|
56
|
+
|
|
57
|
+
- run: python scripts/generate_reference.py --check
|
|
58
|
+
|
|
59
|
+
- name: Mypy strict
|
|
60
|
+
# Bare mypy uses the [tool.mypy] files list (src plus the checked-in
|
|
61
|
+
# scripts), so the utility scripts are type-gated alongside the package.
|
|
62
|
+
run: mypy
|
|
63
|
+
|
|
64
|
+
package:
|
|
65
|
+
needs: [test, lint, tokenizer]
|
|
66
|
+
# Smoke-check that the project builds and the wheel installs on every push
|
|
67
|
+
# and PR. Attestation and PyPI publishing happen only on tag pushes, in
|
|
68
|
+
# release.yml, so this job stays read-only.
|
|
69
|
+
runs-on: ubuntu-latest
|
|
70
|
+
steps:
|
|
71
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
72
|
+
|
|
73
|
+
- name: Set up Python
|
|
74
|
+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
|
75
|
+
with:
|
|
76
|
+
python-version: "3.12"
|
|
77
|
+
|
|
78
|
+
- name: Install reproducible build tools
|
|
79
|
+
run: pip install -c constraints-dev.txt build hatchling
|
|
80
|
+
|
|
81
|
+
- name: Build exact release artifacts
|
|
82
|
+
run: python -m build --no-isolation --outdir candidate-dist
|
|
83
|
+
|
|
84
|
+
- name: Verify wheel and source installs
|
|
85
|
+
run: python scripts/verify_artifacts.py candidate-dist --output artifact-verification.json
|
|
86
|
+
|
|
87
|
+
- name: Retain verified artifacts
|
|
88
|
+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
89
|
+
with:
|
|
90
|
+
name: tracemantle-dist
|
|
91
|
+
path: candidate-dist/*
|
|
92
|
+
if-no-files-found: error
|
|
93
|
+
|
|
94
|
+
- name: Retain artifact verification report
|
|
95
|
+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
96
|
+
with:
|
|
97
|
+
name: tracemantle-verification
|
|
98
|
+
path: artifact-verification.json
|
|
99
|
+
if-no-files-found: error
|
|
100
|
+
|
|
101
|
+
tokenizer:
|
|
102
|
+
runs-on: ubuntu-latest
|
|
103
|
+
steps:
|
|
104
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
105
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
|
106
|
+
with:
|
|
107
|
+
python-version: "3.12"
|
|
108
|
+
- run: pip install -c constraints-dev.txt -e ".[dev,tiktoken]"
|
|
109
|
+
- run: python -m pytest tests/ -q --cov-fail-under=80
|
|
110
|
+
- run: python scripts/calibrate_advisories.py --output calibration.json
|
|
111
|
+
- run: pip install -c constraints-dev.txt strictyaml click
|
|
112
|
+
- run: python scripts/verify_reference_corpus.py --output conformance.json
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Trusted bundle comparison
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
inputs:
|
|
5
|
+
base_revision:
|
|
6
|
+
description: Full trusted base commit SHA
|
|
7
|
+
required: true
|
|
8
|
+
candidate_revision:
|
|
9
|
+
description: Candidate commit SHA to inspect without executing
|
|
10
|
+
required: true
|
|
11
|
+
bundle_path:
|
|
12
|
+
description: Relative bundle directory in both revisions
|
|
13
|
+
required: true
|
|
14
|
+
default: skills/tracemantle
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
jobs:
|
|
18
|
+
compare:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
22
|
+
with:
|
|
23
|
+
ref: ${{ inputs.base_revision }}
|
|
24
|
+
path: trusted
|
|
25
|
+
persist-credentials: false
|
|
26
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
27
|
+
with:
|
|
28
|
+
ref: ${{ inputs.candidate_revision }}
|
|
29
|
+
path: candidate
|
|
30
|
+
persist-credentials: false
|
|
31
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
|
32
|
+
with:
|
|
33
|
+
python-version: "3.12"
|
|
34
|
+
- name: Install only the trusted tool
|
|
35
|
+
run: pip install -c trusted/constraints-dev.txt ./trusted
|
|
36
|
+
- name: Compare against immutable trusted policy
|
|
37
|
+
env:
|
|
38
|
+
BASE_REVISION: ${{ inputs.base_revision }}
|
|
39
|
+
BUNDLE_PATH: ${{ inputs.bundle_path }}
|
|
40
|
+
shell: bash
|
|
41
|
+
run: |
|
|
42
|
+
set -euo pipefail
|
|
43
|
+
args=()
|
|
44
|
+
if [ -d candidate/evidence/records ]; then
|
|
45
|
+
while IFS= read -r -d '' record; do
|
|
46
|
+
args+=(--evidence "$record")
|
|
47
|
+
done < <(find candidate/evidence/records -maxdepth 1 -type f -name '*.json' -print0)
|
|
48
|
+
fi
|
|
49
|
+
tracemantle compare "trusted/$BUNDLE_PATH" "candidate/$BUNDLE_PATH" \
|
|
50
|
+
--trusted-root trusted --base-revision "$BASE_REVISION" \
|
|
51
|
+
--format github "${args[@]}"
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
name: Release notes
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: write
|
|
9
|
+
pull-requests: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
promote-unreleased:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
16
|
+
with:
|
|
17
|
+
ref: main
|
|
18
|
+
fetch-depth: 0
|
|
19
|
+
|
|
20
|
+
- name: Promote [Unreleased] to released version heading
|
|
21
|
+
id: promote
|
|
22
|
+
shell: bash
|
|
23
|
+
env:
|
|
24
|
+
TAG: ${{ github.event.release.tag_name }}
|
|
25
|
+
run: |
|
|
26
|
+
set -euo pipefail
|
|
27
|
+
version="${TAG#v}"
|
|
28
|
+
today=$(date -u +%Y-%m-%d)
|
|
29
|
+
python3 - "$version" "$today" <<'PY'
|
|
30
|
+
import re
|
|
31
|
+
import sys
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
|
|
34
|
+
version, today = sys.argv[1], sys.argv[2]
|
|
35
|
+
path = Path("CHANGELOG.md")
|
|
36
|
+
text = path.read_text(encoding="utf-8")
|
|
37
|
+
|
|
38
|
+
# Locate the [Unreleased] block: its content runs until the next ## heading.
|
|
39
|
+
match = re.search(r"^##\s*\[Unreleased\]\s*\n", text, re.MULTILINE)
|
|
40
|
+
if not match:
|
|
41
|
+
print("CHANGELOG.md has no [Unreleased] heading; nothing to promote.")
|
|
42
|
+
sys.exit(0)
|
|
43
|
+
|
|
44
|
+
start = match.end()
|
|
45
|
+
next_heading = re.search(r"^##\s*\[", text[start:], re.MULTILINE)
|
|
46
|
+
end = start + next_heading.start() if next_heading else len(text)
|
|
47
|
+
body = text[start:end].strip()
|
|
48
|
+
|
|
49
|
+
if not body:
|
|
50
|
+
print("[Unreleased] is empty; nothing to promote.")
|
|
51
|
+
# Signal an empty promotion to the next step.
|
|
52
|
+
Path("PROMOTED.flag").write_text("empty", encoding="utf-8")
|
|
53
|
+
sys.exit(0)
|
|
54
|
+
|
|
55
|
+
# A heading for the released version already exists, so the developer
|
|
56
|
+
# promoted by hand. Promoting again would duplicate entries, but going
|
|
57
|
+
# quiet is what stranded nine shipped fixes outside the v1.4.1 notes:
|
|
58
|
+
# the hand promotion was partial and the remainder stayed here. There
|
|
59
|
+
# is content and nowhere safe to put it, so fail instead of no-oping.
|
|
60
|
+
if re.search(rf"^##\s*\[{re.escape(version)}\]", text, re.MULTILINE):
|
|
61
|
+
print(
|
|
62
|
+
f"[{version}] heading already present, but [Unreleased] still has entries. "
|
|
63
|
+
f"They shipped in {version} and are not recorded under it. Move them under "
|
|
64
|
+
f"[{version}] by hand, or hold them for the next version.",
|
|
65
|
+
file=sys.stderr,
|
|
66
|
+
)
|
|
67
|
+
print(body, file=sys.stderr)
|
|
68
|
+
sys.exit(1)
|
|
69
|
+
|
|
70
|
+
new_block = (
|
|
71
|
+
f"## [Unreleased]\n\n"
|
|
72
|
+
f"## [{version}] - {today}\n\n{body}\n\n"
|
|
73
|
+
)
|
|
74
|
+
updated = text[:match.start()] + new_block + text[end:].lstrip()
|
|
75
|
+
path.write_text(updated, encoding="utf-8")
|
|
76
|
+
Path("PROMOTED.flag").write_text("promoted", encoding="utf-8")
|
|
77
|
+
print(f"Promoted [Unreleased] -> [{version}] - {today}")
|
|
78
|
+
PY
|
|
79
|
+
if [ -f PROMOTED.flag ]; then
|
|
80
|
+
echo "result=$(cat PROMOTED.flag)" >> "$GITHUB_OUTPUT"
|
|
81
|
+
rm PROMOTED.flag
|
|
82
|
+
else
|
|
83
|
+
echo "result=skipped" >> "$GITHUB_OUTPUT"
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
- name: Open PR with the promoted CHANGELOG
|
|
87
|
+
if: steps.promote.outputs.result == 'promoted'
|
|
88
|
+
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0
|
|
89
|
+
with:
|
|
90
|
+
commit-message: |
|
|
91
|
+
docs(changelog): promote [Unreleased] to [${{ github.event.release.tag_name }}]
|
|
92
|
+
title: "docs(changelog): promote [Unreleased] to [${{ github.event.release.tag_name }}]"
|
|
93
|
+
body: |
|
|
94
|
+
Automated promotion triggered by the `${{ github.event.release.tag_name }}` GitHub release.
|
|
95
|
+
Moves the `[Unreleased]` block under a new `[${{ github.event.release.tag_name }}]` heading dated today.
|
|
96
|
+
branch: changelog/promote-${{ github.event.release.tag_name }}
|
|
97
|
+
base: main
|
|
98
|
+
labels: docs, automation
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Publishes to PyPI and attests build provenance when an immutable version tag
|
|
4
|
+
# is pushed. The v*.*.* filter matches patch tags (v1.2.3) but not the moving
|
|
5
|
+
# major tag (v1), so the moving tag does not trigger a duplicate publish.
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
tags:
|
|
9
|
+
- 'v*.*.*'
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
quality:
|
|
16
|
+
uses: ./.github/workflows/ci.yml
|
|
17
|
+
|
|
18
|
+
release:
|
|
19
|
+
needs: quality
|
|
20
|
+
if: vars.TRACEMANTLE_PUBLISH_ENABLED == 'true'
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
# Trusted publishing resolves against this environment on the PyPI side.
|
|
23
|
+
environment: pypi
|
|
24
|
+
permissions:
|
|
25
|
+
contents: read
|
|
26
|
+
id-token: write # PyPI trusted publishing (OIDC) and provenance signing
|
|
27
|
+
attestations: write # actions/attest-build-provenance
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
30
|
+
|
|
31
|
+
- name: Set up Python
|
|
32
|
+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
|
33
|
+
with:
|
|
34
|
+
python-version: "3.12"
|
|
35
|
+
|
|
36
|
+
# Runs before publishing so a CHANGELOG that release-notes.yml cannot
|
|
37
|
+
# promote stops the release instead of shipping unrecorded entries.
|
|
38
|
+
# See scripts/check_changelog_release.py for the two rejected states.
|
|
39
|
+
- name: Verify the CHANGELOG can be promoted for this tag
|
|
40
|
+
run: python3 scripts/check_changelog_release.py "${GITHUB_REF_NAME}"
|
|
41
|
+
|
|
42
|
+
- name: Download the exact quality-gated artifacts
|
|
43
|
+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
|
44
|
+
with:
|
|
45
|
+
name: tracemantle-dist
|
|
46
|
+
path: dist
|
|
47
|
+
|
|
48
|
+
- name: Refuse the legacy distribution
|
|
49
|
+
run: |
|
|
50
|
+
python - <<'PYCODE'
|
|
51
|
+
import pathlib, zipfile
|
|
52
|
+
artifacts = sorted(pathlib.Path("dist").iterdir())
|
|
53
|
+
assert len(artifacts) == 2
|
|
54
|
+
assert all(p.name.startswith("tracemantle-") for p in artifacts)
|
|
55
|
+
for path in artifacts:
|
|
56
|
+
if path.suffix == ".whl":
|
|
57
|
+
with zipfile.ZipFile(path) as wheel:
|
|
58
|
+
metadata = next(n for n in wheel.namelist() if n.endswith(".dist-info/METADATA"))
|
|
59
|
+
assert "\nName: tracemantle\n" in "\n" + wheel.read(metadata).decode()
|
|
60
|
+
PYCODE
|
|
61
|
+
|
|
62
|
+
- name: Verify wheel installs and version matches the tag
|
|
63
|
+
run: |
|
|
64
|
+
set -euo pipefail
|
|
65
|
+
pip install -c constraints-dev.txt dist/tracemantle-*.whl
|
|
66
|
+
installed="$(tracemantle --version | awk '{print $NF}')"
|
|
67
|
+
tag="${GITHUB_REF_NAME#v}"
|
|
68
|
+
if [ "$installed" != "$tag" ]; then
|
|
69
|
+
echo "Built version '$installed' does not match tag '$tag'." >&2
|
|
70
|
+
echo "Bump the version in pyproject.toml and __init__.py before tagging." >&2
|
|
71
|
+
exit 1
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
- name: Attest build provenance
|
|
75
|
+
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
|
|
76
|
+
with:
|
|
77
|
+
subject-path: |
|
|
78
|
+
dist/tracemantle-*.whl
|
|
79
|
+
dist/tracemantle-*.tar.gz
|
|
80
|
+
|
|
81
|
+
- name: Publish to PyPI
|
|
82
|
+
# Pinned to a version tag, not a commit SHA: this action runs a Docker
|
|
83
|
+
# container whose image (ghcr.io/pypa/gh-action-pypi-publish) is tagged
|
|
84
|
+
# by release version, never by commit SHA. A SHA ref makes the inner
|
|
85
|
+
# pull request an image tag that does not exist (manifest unknown), and
|
|
86
|
+
# would pin nothing anyway since the image is fetched by tag regardless.
|
|
87
|
+
#
|
|
88
|
+
# Keep this current with the build backend. The step above installs
|
|
89
|
+
# hatchling with constraints, so the wheel carries the Metadata-Version
|
|
90
|
+
# that the selected hatchling emits. v1.12.4 (January 2025) bundles a twine that
|
|
91
|
+
# rejects Metadata-Version 2.5, which is what hatchling writes today,
|
|
92
|
+
# and it failed the 1.5.0 publish with "not a valid metadata version".
|
|
93
|
+
uses: pypa/gh-action-pypi-publish@v1.14.2
|
|
94
|
+
|
|
95
|
+
# After a TraceMantle release, Action users may select `@v1`, so the moving
|
|
96
|
+
# major tag has to follow every patch release. Moving it by hand was missed
|
|
97
|
+
# for v1.3.0 and v1.4.1, which left `@v1` resolving to v1.2.3 for two months
|
|
98
|
+
# while the action installs from its own checkout. This job runs only after a
|
|
99
|
+
# successful publish and holds the only `contents: write` scope in the file,
|
|
100
|
+
# so the publishing job above stays least-privilege.
|
|
101
|
+
move-major-tag:
|
|
102
|
+
needs: release
|
|
103
|
+
runs-on: ubuntu-latest
|
|
104
|
+
permissions:
|
|
105
|
+
contents: write
|
|
106
|
+
steps:
|
|
107
|
+
- name: Point the major tag at this release
|
|
108
|
+
env:
|
|
109
|
+
GH_TOKEN: ${{ github.token }}
|
|
110
|
+
TAG: ${{ github.ref_name }}
|
|
111
|
+
SHA: ${{ github.sha }}
|
|
112
|
+
run: |
|
|
113
|
+
set -euo pipefail
|
|
114
|
+
# Plain vN.N.N only. The `v*.*.*` trigger glob also matches prerelease
|
|
115
|
+
# tags such as v2.0.0-rc1, which must not move the stable major tag.
|
|
116
|
+
if ! printf '%s' "$TAG" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
|
|
117
|
+
echo "Tag '$TAG' is not a plain vN.N.N release tag; major tag unchanged."
|
|
118
|
+
exit 0
|
|
119
|
+
fi
|
|
120
|
+
major="${TAG%%.*}"
|
|
121
|
+
echo "Moving '$major' to $SHA ($TAG)."
|
|
122
|
+
# PATCH updates the existing ref. POST creates it on the first release
|
|
123
|
+
# of a new major line, where the major tag does not exist yet.
|
|
124
|
+
if gh api "repos/${GITHUB_REPOSITORY}/git/refs/tags/${major}" >/dev/null 2>&1; then
|
|
125
|
+
gh api -X PATCH "repos/${GITHUB_REPOSITORY}/git/refs/tags/${major}" \
|
|
126
|
+
-f sha="$SHA" -F force=true
|
|
127
|
+
else
|
|
128
|
+
gh api -X POST "repos/${GITHUB_REPOSITORY}/git/refs" \
|
|
129
|
+
-f ref="refs/tags/${major}" -f sha="$SHA"
|
|
130
|
+
fi
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
.env
|
|
2
|
+
.DS_Store
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.py[cod]
|
|
5
|
+
*.egg-info/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
.mypy_cache/
|
|
11
|
+
.coverage
|
|
12
|
+
.coverage.*
|
|
13
|
+
htmlcov/
|
|
14
|
+
*.egg
|
|
15
|
+
CLAUDE.md
|
|
16
|
+
# Field test artifacts (kept locally, not in git)
|
|
17
|
+
runs/
|
|
18
|
+
|
|
19
|
+
# Launch post drafts (kept locally, never push)
|
|
20
|
+
launch-post/
|
|
21
|
+
LAUNCH_CHECKLIST.md
|
|
22
|
+
LAUNCH_POST_*.md
|
|
23
|
+
|
|
24
|
+
# Per-skill history ledgers written by `tracemantle --history`; running the tool
|
|
25
|
+
# against a file in the repo drops one next to it and it must never be committed.
|
|
26
|
+
.skillcheck-history.json
|
|
27
|
+
|
|
28
|
+
# Verification venvs (created by end-to-end verification runs)
|
|
29
|
+
.venv-verify/
|
|
30
|
+
|
|
31
|
+
# Agent scratchpads (kept locally; never push)
|
|
32
|
+
.codex
|
|
33
|
+
review.md
|
|
34
|
+
.venv/
|
|
35
|
+
|
|
36
|
+
candidate-dist/
|
|
37
|
+
.tracemantle/
|