Add release_decision.contribution_rules[] audit (v0.17)#81
Merged
Conversation
Adds a deterministic per-finding audit of how each finding contributed to the release decision. Exactly one row per report.findings entry, including suppressed; the (rule, category) pair documents which branch of the gate fired. Bumps report_schema_version 0.16 -> 0.17. Documents the existing v0.8 classification as the new "Release decision truth table" in STABILITY.md (10 rows + prose explainers covering baseline asymmetry and exit-code-vs-decision split). No semantic change: decision, blockers[], review_items[], fail_policy.exit_code, and strict-mode exit are byte-identical to v0.16. The audit reflects existing behavior, it does not modify it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
P2 #1 — build_release_decision crashed on Finding(id=None) because ContributionRule.finding_id is required-as-string. Direct/internal callers (test fixtures, plugin checks emitting Findings before assign_finding_ids, explain-finding rebuilding from a stripped report) hit a Pydantic ValidationError. Fix the _rule helper to fall back through finding.fingerprint to finding.check_id, both of which are guaranteed-present strings on a valid Finding. Adds an explicit regression test exercising both the fingerprint and check_id fallbacks. P2 #2 — sample expected reports carried /private/tmp/shipgate_regen/ paths in generated_reports[] from the v0.17 regen. Restored to the original repo convention (relative paths like expected/report.md) by running scan from each sample dir with output_dir='expected'. P3 #3 — added release_decision.contribution_rules[] to the canonical agent surface: a one-line entry in docs/agent-contract-current.md "Read these first for release gating", a new entry in contract.MANUAL_REVIEW_SIGNALS so contract --json exposes it (with a comment explaining why reviewers triaging review_items want the audit row), and the regenerated llms-full.txt that aggregates the contract doc. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
release_decision.contribution_rules[]— a deterministic per-finding audit of how each finding contributed to the release decision. Exactly one row perreport.findingsentry, including suppressed. The(rule, category)pair documents which branch of the gate fired.report_schema_version0.16→0.17. Documents the existing v0.8 classification as the new "Release decision truth table" inSTABILITY.md— 10 rows + prose explainers covering baseline asymmetry and the exit-code-vs-decision split.decision,blockers[],review_items[],fail_policy.exit_code, and strict-mode exit are byte-identical to v0.16. The audit reflects existing behavior, it does not modify it.What's in the audit
{ "finding_id": "fp_f092940f62fbb012", "fingerprint": "fp_f092940f62fbb012", "check_id": "SHIP-POLICY-APPROVAL-MISSING", "category": "blocker", "rule": "policy_block_new", "rationale": "blocks_release=true and baseline_status=new; explicit policy blocker." }categoryenum:blocker | review_item | excludedruleenum:policy_block_new | severity_block_new | policy_baseline_accepted | severity_baseline_accepted | review_required | sub_threshold | suppressedBoth enums inlined in
docs/report-schema.v0.17.jsonso consumers can switch on them.Why
Per the architecture review's M8 trust-hardening item: a reviewer reading the JSON should be able to predict the gate outcome for any finding without re-deriving the decision logic. The truth table in
STABILITY.mdis the contract;contribution_rules[]is the runtime witness that the gate followed it.The audit is purely additive — defaults to
[]for legacy reports loaded viaexplain-finding, so consumers never need an existence check. No new flags, no new exit codes, no behavior change.Test plan
test_release_decision.pytests still pass — no semantic regressionruff checkclean on changed filespython scripts/generate_schemas.pyis idempotent (running twice produces no diff)len(contribution_rules) == len(findings)invariant verified across all samplestest_v17_schema_requires_contribution_rules) freezes both enums and required keysFiles
src/agents_shipgate/core/models.py(newContributionRule,ContributionRuleName, field onReleaseDecision, schema bump)src/agents_shipgate/ci/release_decision.py(per-finding audit emission, helpers, comments documenting that the branching mirrors v0.16 exactly)scripts/generate_schemas.py(pin required keys),docs/report-schema.v0.17.json(regenerated)tests/test_release_decision.py(+16 tests),tests/test_reports.py(v0.17 lock test),tests/test_provenance_kind.py,tests/test_public_surface_contract.py(v0.16 → legacy pattern)STABILITY.md(truth table + stable field),CHANGELOG.md,.well-known/agents-shipgate.jsonREADME.md,AGENTS.md,llms.txt,llms-full.txt(regenerated),skills/agents-shipgate/SKILL.md,docs/{INDEX,examples,agent-contract-current,autofix-policy,baseline,report-reading-for-agents}.mdsamples/{support_refund_agent,simple_openai_api_agent,simple_langchain_agent,simple_crewai_agent}/expected/report.json🤖 Generated with Claude Code