C1 Provenance — Who Wrote This Diff: Attribution For Agent-Produced Code
Standard: AIHC.2.C1 · Bloom's: Apply · Structure: PBL.
Notice the Say-See-Do cycles running on Maya R.'s actual work — not a canned exercise — and that every capability claim is cited to the frozen doc-set. The exit ticket climbs Bloom's to Apply, and the lesson closes by writing to the ledger.
Learning objective
(Bloom's: Apply) Apply provenance discipline to agent-produced code on payments-service:
make every merged change answer three questions from the record alone — what did the agent
produce, what did the human verify, and where is the session that did the work — by writing
attribution into commit/PR descriptions, wiring the session-to-PR link into your flow, and
fixing the convention in CLAUDE.md so it survives you — AIHC.2.C1 (Provenance).
Work at hand: your pipeline now merges code that Claude wrote, your reviewer subagent
first-passed, and you verified (L5's four-leg record). But git log tells none of that story:
your fee-fix commit reads like every other commit you've ever made. Six months from now,
"who wrote this and what was checked" should be answerable by a teammate at 2 a.m. without
paging you — that answerability is what C1 means by provenance being first-class (X5).
SSD cycle 1 — the record must say what the workflow knew
- SAY: Provenance isn't a confession; it's a load-bearing index. A change produced by an agent and verified by a human is a different object from a change a human wrote — different failure modes, different review needs, different questions when it breaks. If the record flattens the two, every future debugging session starts by reconstructing what the record should have carried. Claude Code participates in your git flow natively — §2: you do git conversationally ("commit my changes with a descriptive message"), and §1 lists git end-to-end (stage, commit-message, branch, PR) as core workflow — which means the commit message is composed inside the very session that knows the provenance. The knowledge is present at write time; the discipline is refusing to let it evaporate.
- SEE: Your real fee-fix change, recorded two ways: ``` AS MERGED (L5): fix: correct fee rounding in calculate_fee()
PROVENANCE-COMPLETE (what the session knew at commit time): fix: correct fee rounding in calculate_fee()
produced-by: Claude Code session (general-purpose), under lesson-2 contract v2
first-pass: payments-first-pass-reviewer (checklist items 1, 4, 6)
verified-by: Maya — four-leg record in PR description (legs a–d, one FAIL returned+fixed)
human-authored: contract, must-not-change list, verification verdicts
``
Same diff, same tests — but only one of these can answer the 2 a.m. questions. Note the last
line: provenance runs *both* directions. It records what the agent produced AND what the
human actually did — claiming agent work as yours and letting agent work pass as yours are
the same record-corruption with different social prices.
- **DO:** Take the three merged PRs from your lesson-1 baseline (#241, #238, #235 — pre-pipeline)
plus the fee-fix PR, and for each write the one-line provenance verdict the current record
supports:fully-answerable / partially answerable / unanswerable` against the three
objective questions (what produced, what verified, where's the session). No rewriting history
— this is the "before" column your convention exists to end.
SSD cycle 2 — the session-to-PR link: provenance the tool already carries
- SAY: One leg of provenance is mechanical and already built: §3, Pull requests — create
the PR from inside the session ("create a pr for my changes"), and "
gh pr createauto-links the session to the PR; find it later withclaude --from-pr 1234." That link is the "where is the session that did the work" answer, for free — but only if the PR is created through the session rather than pasted together afterward in the browser. Provenance that depends on remembering to write things down loses to provenance the workflow emits as exhaust. - SEE: The retrieval, six months later, as it would run (described):
$ claude --from-pr 312 # resumes/opens the session that produced PR #312 — the contract, the reviewer's # first-pass report, the elicitation answers, and your verification commands, # in the order they actually happenedNext to it, the alternative for PR #241: nothing. The session that produced it (if any) is unfindable, because nothing ties it to the PR number. (Fania pressed the credits into the record sleeve — who played the solo isn't a thing you ask around about, it's a thing you read off the object itself.) - DO: Your ledger-migration review will produce your next real PR. Commit now, in your
runbook/notes, to the in-session PR flow for it: PR created via the session, and a
session-linked: yes (claude --from-pr <n>)line in the PR description so the link's existence is itself recorded and checkable. Then verify the claim the doc-set makes — after the PR exists, runclaude --from-pr <n>(described) and confirm it resolves; a provenance mechanism you've never exercised is a mechanism you're assuming (that's your L5 discipline applied to the record itself).
SSD cycle 3 — the convention outlives the intention: fix it in CLAUDE.md
- SAY: Cycles 1–2 produced good behavior; C1 at band 2 requires it to be standing. The
carrier for a standing team convention is the project
CLAUDE.md— §4: project scope is shared "team, via source control," loaded every session — written to §4's concreteness bar ("be concrete enough to verify"), so compliance is visible in a diff, not in anyone's goodwill. This is context, not enforcement (§4) — an honest limit you already know from L6 — so the convention should be cheap enough to follow that drift is laziness, not cost. - SEE: The convention, drafted at checkable size:
markdown ## Provenance (agent-assisted changes) Every PR containing agent-produced code states, in the PR description: 1. produced-by: which agent/subagent + which contract (link or path) 2. first-pass: which reviewer ran + which checklist items it owns 3. verified-by: who ran the verification record; record pasted in the PR (see L5 format) 4. session-linked: yes/no — PRs are created in-session so `--from-pr` resolves Changes with NO agent involvement state `agent: none` — absence is declared, not implied.Line 5 is the one teams skip and regret: without it, silence is ambiguous between "no agent" and "nobody wrote it down," and the whole record decays to vibes. - DO: Write the real section into
payments-service/CLAUDE.md, adjusted to your team's vocabulary, and run your L2 unverifiable-line audit against it: every line checkable by reading a PR, none requiring interrogation of the author. Then apply it once, retroactively, to the fee-fix PR (edit its description to the convention) so the convention's first compliant instance exists as a worked reference you produced.
SSD cycle 4 — provenance under review: reading a record skeptically
- SAY: A provenance record is a claim like any other (your L5 rule: a claim gets a check,
not a shrug). The band-2 reviewer habit: when a PR arrives claiming
verified-by, spot-check that the verification it names could actually have produced the verdicts it reports — a record can be complete in form and false in content, and form-checking alone would just move the vibes one layer up. - SEE: A PR description that passes the convention's form and still fails a spot-check
(described):
first-pass: payments-first-pass-reviewer— but the diff touchesdb/migrations/, which items 1/4/6 don't cover and your L7 deny lane shouldn't even have allowed the session to edit. Two record-vs-reality collisions, both catchable by reading. - DO: Trade PRs with yourself: take the retroactively-conventioned fee-fix PR from cycle 3
and spot-check it cold, as the 2 a.m. teammate — do the named contract, reviewer scope, and
verification legs actually cover this diff's files? File anything that doesn't hold in
docs/failure-log.md(L6 format) as a provenance-class entry; the log's gap field should name the record, not the agent.
Independent at-bat
Unscaffolded: your PII log-scrub task (checklist item 4) is next in the backlog and will be
agent-produced under an L2-style contract. Run its entire provenance chain alone: in-session
PR, convention-complete description, verification record pasted, --from-pr link exercised,
and a one-line agent: none declaration on whichever companion commit (if any) you wrote by
hand. The chain is complete when a teammate could answer all three provenance questions from
the PR page alone — check it by actually reading the PR page as that teammate before merging.
Exit ticket
(Graded against your PR records, your CLAUDE.md convention, and the cited doc-set sections — never against intentions.)
- (Remember) Per §3, what does
gh pr createdo to the session, and what command uses that link later? - (Understand) Why does the convention require
agent: noneto be declared rather than letting absence imply it? Answer in terms of what an ambiguous silence does to the record's value. - (Apply) A teammate merges an agent-produced hotfix with the message
fix: null check. Write the convention-complete PR description they should have written, inventing nothing — mark each field they alone can fill as<author must supply>. - (Analyze) In cycle 4's SEE, the record claimed a first-pass that couldn't cover the diff. Which convention field, which L7 lane, and which L5 leg each independently could have caught it — and which of the three catches it earliest?
- (Evaluate) Judge your own convention: which field will your team most likely rubber-stamp into meaninglessness within a quarter, and what one change (wording, placement, or a spot-check ritual) most cheaply protects it?
ledger_write
ledger_write:
learner_id: L1-DEV-MAYA
lesson_id: L1-dev-maya-08-c1-provenance
anchors: [AIHC.2.C1]
bloom_reached: Apply
exit_ticket_score: ""
auto_score: ""
self_score: ""
calibration_gap: " — computed once Maya's self_score exists"
starting_mastery:
AIHC.2.C1: "not previously evidenced — first measurement this lesson"
journal_prompt: >
Cycle 1 made you grade four of your own merged PRs "unanswerable/partial/full." Write the
honest sentence about how it felt to see your own name on records that can't say what you
did versus what the agent did — and which direction of mis-attribution you were closer to.
structure_used: PBL
referents_used: [salsa-fania-liner-notes]
next_lesson_seed: >
Lesson 9 assembles the team-facing governance proposal: the L7 project-scope flag list,
the L6 hook draft, and this lesson's convention, sorted into advisory vs. permissioned vs.
enforced layers — C2, with hooks as the enforcement floor.
RUBRIC SELF-AUDIT
| # | Indicator | Verdict | Evidence |
|---|---|---|---|
| R1 | One objective, Bloom's-leveled, named anchor | PASS | States "Bloom's: Apply," names AIHC.2.C1 only |
| R2 | Every tool claim traces to the doc-set | PASS | §1 (git end-to-end), §2 (conversational git), §3 (in-session PR creation; gh pr create auto-link + --from-pr, quoted verbatim), §4 (project CLAUDE.md scope, concreteness bar, context-not-enforcement) cited at point of use; the convention's content is explicitly framed as Maya's team policy, not a product claim |
| R3 | 3–6 cycles, one point each | PASS | 4 cycles: the record must carry what the workflow knew; the mechanical session-to-PR link; the standing convention in CLAUDE.md; skeptical reading of provenance records |
| R4 | SEE verified against ground truth | PASS | SEEs quote §3 verbatim behavior, reuse her real commit/PR artifacts from L1/L5, and the cycle-4 collision is constructed from her own established reviewer scope (items 1/4/6) and L7 deny lane — nothing about the product exceeds the freeze |
| R5 | Every DO on real work-at-hand | PASS | DOs grade her real merged PRs, wire the flow for her real migration PR, write her real CLAUDE.md section, retro-fix her real fee-fix PR, and log findings in her real failure log |
| R6 | Media doctrine honored | PASS | Static commit/PR/markdown text only; no motion/process content |
| R7 | Exit ticket 3–5 Qs, Bloom's-climbing | PASS | 5 Qs, Remember→Understand→Apply→Analyze→Evaluate, graded against records + doc-set |
| R8 | Ledger write complete | PASS | auto_score/self_score = ""; journal prompt present; seed recorded |
| R9 | Scaffolding fades; at-bat genuinely independent | PASS | Cycle 1 gives a full worked before/after; cycle 3 gives a draft she must rewrite and audit; cycle 4's spot-check is unmodeled beyond one SEE; the at-bat is a complete provenance chain with only an end-state test — part-faded per arc position |
| R10 | Referents elected-only, flavor-only | PASS | One Fania liner-notes referent (cycle 2), decorative; the link mechanism stands on §3 |
| R11 | Info-at-point-of-use honored | PASS | --from-pr introduced in the cycle where she exercises it; §4 scope facts appear at the CLAUDE.md-writing DO; no front-loaded reading |
| R12 | No replication | PASS | No prior lesson or exemplar touches attribution, the session-to-PR link, or record-reading; the failure-log reuse follows L6's format but files a new class of entry; all DOs/exit Qs new |
Escalation: all load-bearing indicators PASS → auto-ships (Playbook §5, AIHC X2/B3).