Skip to content

Commit standard: require model name/version attribution on agent-authored commits #1488

Open

Description

@don-petry

Gap

Agent-authored commits do not record which model produced them. There is no commit-message standard at all: AGENTS.md says nothing about commit format, and no commit in the repo's history carries model attribution (name or version). When we later need to answer "which model wrote this change?" (regression archaeology, cost/quality analysis, incident review — cf. the identity-flip archaeology in #1316), the information is simply not there.

Analysis (current state)

Where commit messages are built — all inline git commit -m with plain conventional-commit subjects, no trailers:

Site Message shape
scripts/dev-lead-fix-issue.sh:455 feat: implement issue #N — <title>
scripts/dev-lead-fix-ci.sh:307 fix(ci): auto-fix for <check> [skip ci-relay]
scripts/dev-lead-fix-reviews.sh:685 $commit_msg (review-changes)
scripts/dev-lead-fix-reviews.sh:1015 $commit_msg (review-changes)
scripts/release-notes.sh:237 chore: update CHANGELOG for <sha> [skip ci]

The model IS already known at commit time. scripts/engine.sh tracks the exact model that produced the final output and exports it:

  • _CLAUDE_CHAIN_MODEL_USED (set at engine.sh:730, :807)
  • _GEMINI_CHAIN_MODEL_USED (set at engine.sh:610, :658)

The commit sites never consume these variables. Note the variables hold the model of the last engine call; a task that fell through the fallback chain (claude-fable-5 → claude-opus-4-8 → claude-opus-4-7, engine.sh:149-151) may have had earlier calls served by a different model.

Related loose end: ci-failure-analyst-reusable.yml:165 and persona-runner-reusable.yml:164 pass --fallback-model opus as a bare alias — the model those jobs actually run on fallback is resolved at runtime and recorded nowhere. Model attribution in commits would make such drift visible.

Interactive commits: Claude Code CLI sessions append Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> — model name but not the exact model ID/version.

Requirements

  1. Every agent-authored commit MUST carry a machine-readable trailer with the exact model ID that produced the change, e.g.:
    Model: claude-fable-5
    
    Git trailers are the native mechanism: parseable via git interpret-trailers / git log --format=%(trailers:key=Model), invisible in --oneline.
  2. The requirement is scoped to commits authored by bot identities (as declared in personas/*/persona.yml runtime.identity) — human commits and merge commits are exempt.
  3. If the model cannot be determined, the trailer records unknown rather than being omitted (so absence always means non-compliance, not a fallback path).
  4. The standard is documented in AGENTS.md and enforced in CI — not aspirational.

Acceptance criteria

  • AGENTS.md defines the Model: trailer standard: format, scope (agent-authored commits), and the exemptions.
  • All five commit sites above append Model: <resolved-model> sourced from _CLAUDE_CHAIN_MODEL_USED / _GEMINI_CHAIN_MODEL_USED (fallback unknown).
  • Decision recorded (in AGENTS.md): trailer carries the final model only, or the full chain attempted (e.g. Model-Chain:).
  • lint.yml gains a check that fails a PR if any commit authored by a persona bot identity lacks the Model: trailer (identities read from personas/*/persona.yml, not hardcoded).
  • CLAUDE.md instructs interactive Claude Code sessions to include the Model: <exact-model-id> trailer alongside the existing Co-Authored-By line.
  • shellcheck scripts/*.sh passes; existing dev-lead flows produce compliant commits in a soak run.

Implementation plan

  1. AGENTS.md — add a "Commit standard" section defining the trailer, scope, unknown rule, and the final-model-vs-chain decision.
  2. Script changes — at each of the five sites, append the trailer as a second -m argument, e.g.:
    git commit -m "$commit_msg" -m "Model: ${_CLAUDE_CHAIN_MODEL_USED:-${_GEMINI_CHAIN_MODEL_USED:-unknown}}"
    Confirm each script actually runs downstream of an engine.sh invocation in the same process tree; where it does not (e.g. release-notes.sh, which is mechanical and model-free), either exempt it in the standard or stamp Model: n/a.
  3. Enforcement — new scripts/verify-commit-model-trailer.sh (pattern: verify-persona-identity.sh): for each PR commit, if the author matches a persona runtime.identity account, require a Model: trailer. Wire into lint.yml. (GitHub ruleset commit_message_pattern was considered and rejected: rulesets cannot condition on commit author, so it would break human commits.)
  4. CLAUDE.md — one-line instruction for interactive sessions.
  5. Rollout — enforcement lands lint-warning-first for one soak cycle, then flips to failing, so in-flight PRs with pre-standard commits are not bricked.

Activity

  1. github-actions commented on Aug 8, 2026

    @github-actions
    Contributor

    Thanks for such a thorough write-up — the analysis of where model variables are already tracked but never consumed is exactly the kind of detail that makes implementation straightforward. Before we proceed: the issue mentions a 'final-model-vs-chain' decision needs to be recorded in AGENTS.md — do you have a preference, or should the implementer make the call and document the rationale?

  2. don-petry commented on Aug 9, 2026

    @don-petry
    CollaboratorAuthor

    Thanks for such a thorough write-up — the analysis of where model variables are already tracked but never consumed is exactly the kind of detail that makes implementation straightforward. Before we proceed: the issue mentions a 'final-model-vs-chain' decision needs to be recorded in AGENTS.md — do you have a preference, or should the implementer make the call and document the rationale?

    Let's include the entire chain if present.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions