
Agent Change Walkthrough
- 22 installs
- 44 repo stars
- Updated July 10, 2026
- cameroncooke/cameroncooke-skills
agent-change-walkthrough is a skill that produces a single-story, end-to-end walkthrough of AI-authored code changes with annotated diffs and risk analysis.
About
agent-change-walkthrough is a skill that generates a single-story walkthrough of AI-authored code changes from runtime trigger to final behavior. It gathers git-based evidence, orders steps dependency-first, and shows before/after code with prose explanations written for a developer new to the repository. Developers use it to understand or review what an agent changed and why. It also documents trade-offs, alternatives, and risk analysis inline.
- Turns an AI-authored diff into one coherent implementation story
- Weaves changed and unchanged code with annotated before/after snippets
- Includes trade-offs, alternatives, and risk analysis for a reader new to the codebase
Agent Change Walkthrough by the numbers
- 22 all-time installs (skills.sh)
- Ranked #990 of 1,879 Documentation skills by installs in the Skillselion catalog
- Data as of Jul 28, 2026 (Skillselion catalog sync)
agent-change-walkthrough capabilities & compatibility
- Capabilities
- code explanation · diff summary · documentation generation
- Works with
- github
- Use cases
- documentation · code review
What agent-change-walkthrough says it does
Generate one coherent implementation story that explains how the code works end-to-end after the change.
Git-based evidence (source of truth for output)
Order story steps by **dependency-first causality**:
npx skills add https://github.com/cameroncooke/cameroncooke-skills --skill agent-change-walkthroughAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 22 |
|---|---|
| repo stars | ★ 44 |
| Last updated | July 10, 2026 |
| Repository | cameroncooke/cameroncooke-skills ↗ |
What it does
Produce a readable, end-to-end narrative of an AI-authored code change with annotated diffs so reviewers understand how a feature works.
Who is it for?
Explaining or reviewing what an AI agent changed in a diff, as a narrative a newcomer can follow.
Skip if: Summarizing conversation history or investigation process rather than final code behavior.
When should I use this skill?
When asked to explain what changed, walk through a diff, summarize agent edits, show how a feature works, or explain an implementation step by step.
What you get
A coherent implementation story that explains how the code works after the change, with before/after snippets and trade-offs.
- Narrative code-change walkthrough with annotated before/after snippets
By the numbers
- Structured as a 4-plus step workflow from capturing intent to writing each step as developer narrative
Files
Generate one coherent implementation story that explains how the code works end-to-end after the change.
Step 1: Capture implementation intent
Restate the requested change in plain language.
Include:
- User problem being solved
- Scope boundaries
- Explicit non-goals
If requirements are ambiguous, state assumptions before proceeding.
Step 2: Build evidence from conversation + git
Collect both sources before writing:
1. Conversation context (planning input only)
- Requested outcome
- Constraints and acceptance criteria
- Domain context needed to interpret the code correctly
2. Git-based evidence (source of truth for output)
- Changed file list
- Diff per changed file (analyze full diffs locally, but only quote the minimum needed hunks in output)
- Relevant unchanged context needed to explain behavior
- The before version of every changed behavior — including logic that was moved, extracted, or rewritten across files. Recover it from the base revision; never settle for "this is new" without checking whether equivalent logic existed elsewhere before.
Use commands such as:
git status --short
git diff --name-only
git diff -- <file>
git show -- <file>
git show <base>:<path/to/file> # recover the before version of a file
git log -p -S '<symbol or phrase>' # find where moved/extracted logic previously livedUse history only when needed to disambiguate intent:
git log --oneline -- <file>Never include conversation process, investigation history, or request negotiation as walkthrough steps. The walkthrough must describe implementation behavior only. Never include full file dumps, raw secrets, credentials, tokens, private keys, or copied production payloads in the final output.
Step 3: Build the story stack
Order story steps by dependency-first causality: 1. Introduce contracts/types/schemas/interfaces before showing call sites that use them 2. Introduce function/class definitions before showing new call paths that invoke them 3. Then continue in runtime flow order from trigger to final behavior
If runtime order and dependency order conflict, prefer dependency order and add one short transition sentence that reconnects to runtime flow.
Skip non-essential detail while preserving causal clarity.
Step 4: Write each step as natural developer narrative
For each story step:
- Use a clear step title that describes behavior (no file path in the heading)
- Mark the step as
UNCHANGED CONTEXTorCHANGEDin the heading - For
UNCHANGED CONTEXTsteps, open the body with the literal note line> Unchanged — pre-existing code shown for flow context only; nothing in this snippet was touched by this change.so unchanged code can never be mistaken for new or modified work - Place
Filename:<relative/path/to/file.ext:start_line>`` immediately above each snippet - Optionally place
Symbol:<function/method/class>`` above each snippet when useful - Show the code following the before/after rules below
- Explain the logic in prose below the code blocks it describes — a one-sentence framing line above a snippet is fine, but the substantive explanation of how the code works always follows the code, never replaces or precedes it
- Explain what this step causes next in the flow
- Avoid forward references: do not use a field/type/function in a step before showing where it is defined or introduced
Avoid rigid template labels such as Why this step exists: or Impact:. Write readable, connected prose instead. Keep headings and narrative readable; put precise location in the snippet header.
Write for a reader new to the codebase
Write every explanation in plain English for a competent developer who has never seen this repository. Knowing the language is assumed; knowing the codebase, its internal tools, or its domain vocabulary is not.
- Explain every project-specific term at first mention, in the same sentence — internal frameworks, config conventions, repo/service names, and domain vocabulary. Write "gated behind a new feature flag (
organizations:example-flag); flags are switched on per customer from a separate configuration repo, so merging this change activates nothing by itself" — not "registered via FlagPole with rollout in options-automator". - Anchor project-specific mechanisms to the general concept they implement (feature flag, database migration, background job, cache layer) so the reader has something familiar to hold on to.
- When behavior involves an interaction between builds, branches, requests, or services, walk a short numbered concrete scenario first (1.
mainhas a full build, 2. PR1 uploads a partial one, 3. PR2 is opened on top of PR1, ...) and only then describe the mechanism in the abstract. - State the problem in plain language before the solution mechanism — in the setup paragraph and within each step.
- Keep identifiers verbatim in and around code, but never let an identifier's name carry the explanation on its own.
Before/after rules for changed code
Every CHANGED step must show both the before and the after. Never show only the new code:
- Small changes (one or two changed lines in a hunk): use a git-style mini-diff:
- old behavior
+ new behavior- Larger changes: show two separate code blocks, clearly labeled Before and After, each with its own
Filename:header pointing at where that version lives (or lived). - The before must be shown even when it lived in a different file or had a different shape. If code was extracted, moved, or rewritten, recover the prior logic from the base revision and present it as the Before block under its original filename. A simplified or pseudocode Before is acceptable when the original is long or noisy — label it
Before (simplified)— but the After block must always be verbatim from the new code. - Moved or refactored code is never presented as brand-new. When code is removed from one file and equivalent logic appears in another, treat that as one step: Before from the old location, After from the new location, followed by prose stating exactly what is mechanically identical and what actually changed — renamed variables, different data sources, revised conditions, or adjusted business rules, however subtle.
Call out the semantic effect of every changed hunk in the prose below its snippet.
Branch-complete example data
When a changed step contains conditional branches, set/collection operations, or merge/categorization logic, the example block must prove the behavior, not just illustrate it:
- Provide one concrete example per distinct logic branch or input combination that produces a different result — every arm of an
if/elif/else, and every meaningful membership combination (in A but not B, in B but not A, in both, in/out of a declared set, empty input). - Present the scenarios as a compact table or a labeled scenario list, with sanitized synthetic values, so a reader can verify each branch's output by inspection.
- For simple single-path data-shape changes, a single before/after payload example remains sufficient.
Do not copy verbatim payloads from logs, production data, or repository fixtures that may contain sensitive information.
Step 5: Integrate analysis inline
Embed analysis at the relevant story step:
- Trade-offs chosen at that step
- Viable alternatives and why not chosen
- Performance implications
- Failure modes and compatibility risk
Use natural language callouts in prose; keep them concise and specific.
Step 6: End with concise close-out
After the final story step, add a short close-out with:
- What changed overall
- Why behavior is now different
- What to monitor or validate next
Output contract
Return this structure:
1. # Implementation Walkthrough 2. One brief setup paragraph — the problem in plain language, then intent and scope 3. Numbered story steps (## Step 1, ## Step 2, ...) 4. ## Final Outcome
Output example
Use this structure:
````markdown
Implementation Walkthrough
Today, results produced by an agent and results produced by a human render identically, so users cannot tell which is which. This change makes the service record where each result came from and makes the UI render agent results differently. The flow from button click to render is otherwise untouched.
Step 1 — User click enters the feature entrypoint [UNCHANGED CONTEXT]
Unchanged — pre-existing code shown for flow context only; nothing in this snippet was touched by this change.
Filename: src/ui/button.ts:42 Symbol: onClick
button.onClick = () => startFeature(input)The runtime trigger is still the button click. That handler forwards the input into the existing feature path, so the change does not alter how execution begins. From here, control moves into startFeature().
Step 2 — Entrypoint forwards to service [UNCHANGED CONTEXT]
Unchanged — pre-existing code shown for flow context only; nothing in this snippet was touched by this change.
Filename: src/feature/entry.ts:10 Symbol: startFeature
export function startFeature(input: Input) {
return run(input)
}The orchestration layer continues to delegate work to run(), which means the new behavior is introduced deeper in the service layer, not at the boundary. That keeps the original control flow intact and localizes the behavior change.
Step 3 — Sync categorization extracted into its own module and revised [CHANGED]
The categorization logic that previously lived inline in run() now lives in a dedicated module. The extraction is mostly mechanical, but one business rule changed, so both versions are shown.
Before (simplified) — inline logic removed from the old location:
Filename: src/feature/service.ts (base revision)
const matched = intersect(headIds, baseIds)
const added = diff(headIds, baseIds)
const removed = head.selective ? new Set() : diff(baseIds, headIds)After (verbatim) — new module:
Filename: src/feature/categorize.ts:12 Symbol: categorize
export function categorize(head: Manifest, base: Manifest) {
const headIds = new Set(Object.keys(head.items))
const baseIds = new Set(Object.keys(base.items))
const matched = intersect(headIds, baseIds)
const added = diff(headIds, baseIds)
let removed: Set<string>
let skipped: Set<string>
if (head.declaredIds) {
removed = diff(baseIds, head.declaredIds)
skipped = intersect(diff(head.declaredIds, headIds), baseIds)
} else if (head.selective) {
removed = new Set()
skipped = diff(baseIds, headIds)
} else {
removed = diff(baseIds, headIds)
skipped = new Set()
}
return { matched, added, removed, skipped }
}The matched and added computations are mechanically identical to the old inline version — only their home moved. What actually changed: the old code knew only two modes (selective vs full), while the new code adds a third branch for an explicit declaredIds list, and selective mode now reports base-only names as skipped instead of silently dropping them.
Example input/output — one scenario per branch:
| Scenario | head items | base items | declaredIds / selective | matched | added | removed | skipped |
|---|---|---|---|---|---|---|---|
| Full mode, item dropped from head | {a} | {a, b} | — / false | {a} | {} | {b} | {} |
| Selective mode, item not uploaded | {a} | {a, b} | — / true | {a} | {} | {} | {b} |
Declared list excludes b | {a} | {a, b} | [a] | {a} | {} | {b} | {} |
Declared list includes b, not uploaded | {a} | {a, b} | [a, b] | {a} | {} | {} | {b} |
| New item only in head | {a, c} | {a} | — / false | {a} | {c} | {} | {} |
Rows 1–2 exercise the two pre-existing modes and confirm their behavior is preserved; rows 3–4 exercise the new declaredIds branch, showing that a name absent from the declared set is removed while a declared-but-not-uploaded name is merely skipped; row 5 confirms additions are mode-independent. Extracting rather than rewriting in place keeps run() readable and makes this branch table directly testable, at the cost of one extra module.
Step 4 — Service return payload updated [CHANGED]
Filename: src/feature/service.ts:88 Symbol: run
- return { state: "pending" }
+ return { state: "ready", source: "agent" }This one-line change is shown as a mini-diff. The service now includes source metadata in its return payload so downstream consumers can render source-specific UI behavior. The team chose to enrich the existing payload instead of creating a second metadata endpoint, which avoids an extra network hop, but there is a compatibility risk for legacy consumers that assume the old payload shape.
Step 5 — UI consumes enriched payload [CHANGED]
Filename: src/ui/render.ts:120 Symbol: renderState
+ if (data.source === "agent") {
+ showAgentState()
+ }Rendering now branches on the new source field, which is what makes the feature visible to users. This is purely additive (no prior branch existed here), and it is where the service-layer change becomes observable behavior.
Final Outcome
The feature still starts at the same runtime trigger and follows the same orchestration path, but categorization now lives in its own module with a new declared-list mode, and the changed service payload drives source-aware rendering. Next validation should confirm that legacy consumers handle the added source field safely and that the declared-list branch is covered by tests. ````
Validation and exit criteria
Complete only when all checks pass:
- Story begins at runtime trigger and ends at final observable behavior.
- Every changed file appears in at least one
CHANGEDstory step. - Every snippet header uses
Filename: relative/path/to/file.ext:start_lineformat; Before blocks recovered from the base revision may omit:start_linebut must name the original file and note the revision. - No forward references: definitions/contracts appear before usages that depend on them.
- Unchanged-but-critical context appears in
UNCHANGED CONTEXTsteps, each opening with the literal unchanged note line. - Every
CHANGEDstep shows both before and after — never the new code alone. One-or-two-line changes use adiffblock; larger changes use separate labeled Before/After blocks. - Moved/extracted/refactored code shows the removed code from its original location as Before (simplified allowed, labeled) and the new code verbatim as After, with prose stating what is identical and what changed.
- Each changed hunk includes reason + behavioral effect.
- Substantive logic explanation appears below the code blocks it describes, not only above them.
- Data-shape/model/API changes include concrete example input/output with sanitized representative values.
- Branch-bearing changed logic (conditionals, set/collection operations, categorization/merge rules) includes one example scenario per distinct branch or input combination that yields a different result.
- Trade-offs, alternatives, performance notes, and risk notes appear at relevant steps.
- Every project-specific term, internal tool, or convention is explained in plain English at first mention; the prose stands alone for a developer with no prior knowledge of this codebase.
- Multi-actor or multi-build behavior is introduced with a concrete numbered scenario before the abstract mechanism.
- Facts are distinguished from inference.
- Unknowns are explicitly labeled.
- Conversation process/history does not appear as a walkthrough step.
- No claim of validation is made unless validation was actually performed.
- Snippets and examples contain no credentials, keys, tokens, or other sensitive values.
If any criterion fails, state what is missing and continue refining before finalizing.
Findings Log
Maintenance-only file. Not loaded at runtime. Records why the skill's rules exist so future revisions don't regress them. Examples live in working-set.md; reserved validation cases in holdout-set.md.
2026-06-11 — Walkthrough depth revision (user feedback)
Five failure patterns reported from real walkthrough output, each mapped to a rule now in SKILL.md:
| # | Failure pattern | Root cause | Skill delta |
|---|---|---|---|
| 1 | Example data illustrated one path through branchy logic instead of proving every branch | Example guidance only asked for "concrete example data" | "Branch-complete example data" section: one scenario per branch/membership combination, table or labeled list ([EX-002]) |
| 2 | Moved/extracted code presented as brand-new; only the new file shown | No rule forced recovering the before version across files | "Before/after rules": Before recovered from base revision even across files; simplified Before allowed (labeled), After verbatim; moved code is one step with identical-vs-changed prose ([EX-001]) |
| 3 | Logic explained only above snippets, or not at all | Bullet order implied but did not require placement | Explicit rule: substantive explanation below the code blocks it describes ([EX-003]) |
| 4 | Large rewrites rendered as unified diffs (unreadable) or new-only blocks | Single "prefer mini-diff" rule regardless of change size | Size rule: 1–2 changed lines → diff block; larger → separate labeled Before/After blocks ([EX-004]) |
| 5 | Unchanged context steps mistakable for new work | [UNCHANGED CONTEXT] heading tag alone too subtle | Mandatory literal blockquote note line opening every unchanged step ([EX-005]) |
Secondary fixes from the same pass: exit criterion for Filename: headers narrowed so base-revision Before blocks may omit :start_line; orphaned "semantic effect per hunk" rule re-homed under the before/after rules.
2026-06-11 — Audience calibration (user feedback after live test)
A real walkthrough produced by the revised skill passed on structure but failed on language: prose leaned on internal tool names, flag-framework conventions, and domain shorthand, readable only by someone already in the codebase ([EX-006], which includes the user's corrected rewrite). Root cause: the skill specified structure and evidence rules but never named the audience, so the walkthrough defaulted to insider register. Skill delta: "Write for a reader new to the codebase" section in Step 4 (terms defined at first mention, mechanisms anchored to general concepts, numbered concrete scenario before abstract mechanism, problem before solution), problem-first setup paragraph in the output contract, example setup paragraph rewritten to model the style, and two new exit criteria.
Holdout validation, same day: HX-001 staged in a scratch repo and run by a fresh agent blind to the pass criteria — PASS on all four criteria (details in the HX-001 record). One observation, not yet promoted to a rule change: an elided Before block was not labeled Before (simplified), suggesting the labeling rule may be stated too far from the Before/After formatting examples to reliably fire. Revisit if it recurs. HX-002 remains unexercised.
Unresolved risks:
- Branch-completeness for combinatorial logic could explode table size; the skill does not yet cap
or sample scenarios. Watch for bloated walkthroughs on functions with many independent flags.
- "Verbatim After" conflicts with the existing no-full-file-dumps rule for very large new
functions; no explicit reconciliation rule yet.
- No automated check exists; compliance rests on the exit-criteria checklist.
Holdout Set
Reserved for validating the skill after edits. Do not tune SKILL.md wording directly against these records; move one into working-set.md first if it must drive an edit.
To validate: construct the described change in a scratch repo (or present it as a diff), run the skill, and check the output against each record's pass criteria.
HX-001: Moved validation helper with a tightened boundary
- Label: negative
- Kind: regression
- Origin: synthetic
- Source: authored 2026-06-11 to exercise the moved-code rules on a non-set-logic, non-Python case
- Status: holdout
- Expected behavior: see pass criteria below.
- Observed behavior: PASS on 2026-06-11 against the same-day SKILL.md revision, run by a fresh agent blind to these criteria in a staged scratch repo. All four criteria met; the
>→>=change was flagged as a likely accidental off-by-one with a below/at/above-limit example table. Minor deviation: the Before block elided lines with// ...but was not labeledBefore (simplified). - Skill delta: n/a — validation only.
- Anonymization: fully synthetic.
Content
The change: an inline guard in an HTTP route handler is extracted to a shared util, and during the move the boundary condition tightens from > to >=.
Removed from routes/upload.ts:
if (file.sizeBytes > MAX_UPLOAD_BYTES) {
return reject("too_large")
}Added to new file lib/limits.ts:
export function exceedsUploadLimit(sizeBytes: number): boolean {
return sizeBytes >= MAX_UPLOAD_BYTES
}with the route handler now calling exceedsUploadLimit(file.sizeBytes).
Pass criteria:
1. One step shows both locations — Before from routes/upload.ts, After from lib/limits.ts — never the new util alone. 2. The walkthrough explicitly calls out the > → >= change as a behavior change (a file of exactly MAX_UPLOAD_BYTES is now rejected), not as a mechanical move. 3. Example data covers the three distinct inputs: below limit, exactly at limit (the changed outcome), above limit. 4. The unchanged route-handler plumbing around the call site, if shown, opens with the literal unchanged note line.
HX-002: Config precedence merge with branch-bearing fallbacks
- Label: negative
- Kind: edge-case
- Origin: synthetic
- Source: authored 2026-06-11 to exercise branch-complete examples on dict-merge precedence logic
- Status: holdout
- Expected behavior: see pass criteria below.
- Observed behavior: n/a until run.
- Skill delta: n/a — validation only.
- Anonymization: fully synthetic.
Content
The change: a new function replaces a naive {...defaults, ...fileConfig} spread.
New code in config/resolve.ts:
export function resolveConfig(
defaults: Config,
fileConfig: Partial<Config>,
envOverrides: Partial<Config>,
strict: boolean,
): Config {
const merged = { ...defaults, ...fileConfig, ...envOverrides }
if (strict) {
const unknown = Object.keys(fileConfig).filter((k) => !(k in defaults))
if (unknown.length > 0) throw new ConfigError(unknown)
}
return merged
}Pass criteria:
1. The old one-line spread appears as Before (diff block acceptable — the prior code is 1 line), and the walkthrough does not present resolveConfig as having no predecessor. 2. Example data enumerates the precedence and strictness outcomes as distinct scenarios, minimum: key only in defaults; key in defaults+file; key in all three (env wins); unknown key with strict: false (passes through); unknown key with strict: true (throws); empty envOverrides. 3. Scenarios are presented as a table or labeled list with concrete values, and the explanation of precedence order sits below the code block, not only above it.
HX-003: Jargon-saturated flag rollout must read as plain English
- Label: negative
- Kind: edge-case
- Origin: synthetic
- Source: authored 2026-06-11 to exercise the audience-calibration rules on a fixture whose repo
conventions invite insider shorthand; domain deliberately differs from EX-006
- Status: holdout
- Expected behavior: see pass criteria below.
- Observed behavior: n/a until run.
- Skill delta: n/a — validation only.
- Anonymization: fully synthetic, including the internal framework names.
Content
The fixture repo has its own internal conventions that a lazy walkthrough would name without explanation: feature flags are registered through an in-house framework called Switchboard; registrations carry an expose_ui field; flags are turned on per customer from a separate repository called config-deployer, not from this repo.
The change: email digest sends gain a quiet-hours deferral, gated behind a new flag.
Base state, flags/registry.py (existing registrations, unchanged):
register(Flag("orgs:digest-batching", expose_ui=True))
register(Flag("orgs:digest-reply-threading", expose_ui=False))Working-tree change 1 — new registration appended in flags/registry.py:
register(Flag("orgs:digest-quiet-hours", expose_ui=False))Working-tree change 2 — digests/scheduler.py, the send loop:
Before:
for digest in due_digests:
send_digest(digest)After:
for digest in due_digests:
org = digest.organization
if flag_enabled("orgs:digest-quiet-hours", org) and in_quiet_hours(org, now):
defer_to_next_window(digest, org)
else:
send_digest(digest)with in_quiet_hours and defer_to_next_window added as small new helpers reading org.settings.quiet_hours (an existing stored setting).
Staging note: give flags/registry.py a short module docstring stating the repo convention ("Flags are registered here via Switchboard; expose_ui controls frontend visibility; flags are enabled per customer from the config-deployer repo"). The information must be discoverable in the repo — the test is whether the walkthrough translates it into plain English, not whether it can invent it.
Pass criteria (run with no extra audience instructions — the skill alone must produce these):
1. The setup paragraph states the problem in plain English (digests currently send at any hour, including the middle of the night for the recipient's organization) before naming any internal tool, flag, or file. 2. Switchboard, expose_ui, and config-deployer are each explained at first mention and anchored to the general concept they implement (feature-flag framework; whether a flag is visible to frontend code; per-customer rollout from a separate configuration repo — so merging activates nothing by itself). 3. The flag/setting/scheduler interaction is introduced as a numbered concrete scenario (e.g. 1. an org sets quiet hours 22:00–07:00, 2. a digest comes due at 23:00, 3. the flag is on, so it is deferred to 07:00; flag off → sends immediately) before any abstract description, and the example data covers the distinct outcomes: flag off; flag on outside quiet hours; flag on inside quiet hours. 4. No step relies on an identifier name alone to carry meaning — a developer who has never seen this repository can follow every step without asking what a term refers to.
Working Set
Examples used while editing the skill. Tuning against these is allowed.
EX-001: Extracted categorization shown as brand-new code
- Label: negative
- Kind: false-negative
- Origin: human-verified
- Source: user feedback on a real walkthrough, 2026-06-11
- Status: working
- Expected behavior: when logic is removed from one file and equivalent logic appears in another, the walkthrough shows the removed code from its original location as Before (simplified allowed, labeled) and the new code verbatim as After, then states what is identical and what changed.
- Observed behavior: walkthrough showed only the new file's function, presenting moved logic as if written from scratch; the removed inline version was never shown.
- Skill delta: "Before/after rules for changed code" section in SKILL.md;
git show <base>:<path>andgit log -p -Sadded to evidence gathering; matching exit criteria. - Anonymization: domain renamed from a snapshot/image-manifest system to a generic manifest; function and field names generalized; docstring rewritten. Algorithmic structure preserved exactly.
Content
Removed from tasks.py (inline in a larger task function):
head_by_name = {key: meta.content_hash for key, meta in head_manifest.entries.items()}
base_by_name = {key: meta.content_hash for key, meta in base_manifest.entries.items()}
declared_names = head_manifest.declared_names
matched = head_by_name.keys() & base_by_name.keys()
added = head_by_name.keys() - base_by_name.keys()
if declared_names is not None:
declared_set = set(declared_names)
removed = base_by_name.keys() - declared_set
skipped = (declared_set - head_by_name.keys()) & base_by_name.keys()
elif head_manifest.selective:
removed = set()
skipped = base_by_name.keys() - head_by_name.keys()
else:
removed = base_by_name.keys() - head_by_name.keys()
skipped = set()Added to new file categorize.py:
def categorize_entries(
head_manifest: Manifest, base_manifest: Manifest
) -> tuple[set[str], set[str], set[str], set[str]]:
"""Categorize entry names into (matched, added, removed, skipped) by selective mode.
The base is the authoritative complete set. Only the head's selective flags drive
classification:
- declared_names given: removals are names in base but not in the declared set.
- selective, no list: nothing removed; base names not uploaded are skipped.
- full: base names not in head are removed.
"""
head_names = set(head_manifest.entries.keys())
base_names = set(base_manifest.entries.keys())
matched = head_names & base_names
added = head_names - base_names
declared_names = head_manifest.declared_names
if declared_names is not None:
declared_set = set(declared_names)
removed = base_names - declared_set
skipped = (declared_set - head_names) & base_names
elif head_manifest.selective:
removed = set()
skipped = base_names - head_names
else:
removed = base_names - head_names
skipped = set()
return matched, added, removed, skippedA correct walkthrough must show both blocks as one step and call out: branch logic is mechanically identical; the new version keys sets off entry names directly instead of content-hash dicts, gains a signature/return contract, and a docstring codifying the business rules.
EX-002: Single illustrative example for branchy set logic
- Label: negative
- Kind: false-negative
- Origin: human-verified
- Source: same walkthrough as [EX-001], 2026-06-11
- Status: working
- Expected behavior: for the
categorize_entrieschange, one scenario per distinct outcome — full mode with a dropped name, selective mode with a not-uploaded name, declared set excluding a base name, declared set including a not-uploaded name, and a head-only addition — so each branch's output is verifiable by inspection. - Observed behavior: a single happy-path example that exercised only one branch, proving nothing about the other arms.
- Skill delta: "Branch-complete example data" section in SKILL.md; branch-table demonstration in the output example; matching exit criterion.
- Anonymization: shares EX-001's generalized domain.
Content
Minimum scenario set for EX-001's function (head entries, base entries, declared/selective → matched/added/removed/skipped):
| head | base | declared / selective | matched | added | removed | skipped |
|---|---|---|---|---|---|---|
| {a} | {a, b} | — / false | {a} | {} | {b} | {} |
| {a} | {a, b} | — / true | {a} | {} | {} | {b} |
| {a} | {a, b} | [a] | {a} | {} | {b} | {} |
| {a} | {a, b} | [a, b] | {a} | {} | {} | {b} |
| {a, c} | {a} | — / false | {a} | {c} | {} | {} |
EX-003: Explanation missing below code blocks
- Label: negative
- Kind: edge-case
- Origin: human-verified
- Source: user feedback, 2026-06-11
- Status: working
- Expected behavior: substantive logic explanation follows each code block; at most a one-sentence framing line above.
- Observed behavior: steps fronted all explanation before the snippet, leaving nothing tying the shown code back to behavior.
- Skill delta: explicit explain-below-code bullet in Step 4; matching exit criterion.
- Anonymization: pattern-level record; no code retained.
EX-004: Large rewrite rendered as a unified diff
- Label: negative
- Kind: edge-case
- Origin: human-verified
- Source: user feedback, 2026-06-11
- Status: working
- Expected behavior: 1–2 changed lines → git-style diff block; larger changes → separate labeled Before and After blocks, each with its own Filename header.
- Observed behavior: multi-line rewrites shown either as long interleaved +/- diffs or as the new version only.
- Skill delta: size-based formatting rule in "Before/after rules for changed code".
- Anonymization: pattern-level record; no code retained.
EX-005: Unchanged context mistakable for new work
- Label: negative
- Kind: false-positive
- Origin: human-verified
- Source: user feedback, 2026-06-11
- Status: working
- Expected behavior: every unchanged step opens with the literal note line "> Unchanged — pre-existing code shown for flow context only; nothing in this snippet was touched by this change."
- Observed behavior: only a heading tag marked unchanged steps; readers skimming code blocks took pre-existing code as part of the change.
- Skill delta: mandatory note line in Step 4 and in the output example; matching exit criterion.
- Anonymization: pattern-level record; no code retained.
EX-006: Prose assumed reader knew the codebase
- Label: negative
- Kind: fix
- Origin: human-verified
- Source: user feedback on a real walkthrough produced by the revised skill, 2026-06-11; user supplied a corrected rewrite
- Status: working
- Expected behavior: explanations stand alone for a competent developer who has never seen the repository — project-specific terms explained at first mention, mechanisms anchored to general concepts, multi-actor behavior introduced via a numbered concrete scenario, problem stated before mechanism.
- Observed behavior: setup and step prose leaned on internal tool names, flag-framework conventions, and domain shorthand with no explanation, so the walkthrough was only readable by someone already working in the codebase.
- Skill delta: "Write for a reader new to the codebase" section in Step 4; setup paragraph contract now problem-first; two new exit criteria; output example's setup paragraph rewritten to model the style.
- Anonymization: real internal tool names, flag names, branch names, and product domain replaced with the generalized manifest/build domain used by EX-001; sentence structure of both versions preserved.
Content
Failing prose (structure preserved, names generalized):
A purely additive registration following the repo's Toggles convention. api_expose=False becauseno frontend code checks this flag — it only gates backend base-selection behavior. Rollout happens
via the config-automator YAML, not in this repo, so merging this branch changes nothing for any
customer until the flag is enabled.
This assumes the reader knows what the Toggles framework is, what api_expose controls, and what the config-automator repo does.
User-supplied corrected style (same content, plain English):
This branch fixes build comparisons for a common pull request setup.
>
Sometimes a build uploads all entries. Other times it is selective, meaning it uploads
only part of the set — for example, only entries from a certain module or platform.
>
The problem happens when one pull request is built on top of another:
>
1. main has a full build with every entry.2. PR1 has a selective build with only some entries.
3. PR2 is opened on top of PR1.
4. PR2 needs to compare against PR1's build.
>
Before this change, the system ignored PR1's build because it was selective, so PR2 could not find
a baseline. After this change, PR1's selective build can serve as the baseline: the system first
rebuilds PR1's full entry set by starting from the nearest earlier full build, then applying the
selective data on top.
>
This is backend-only, behind the feature flag organizations:selective-base-builds — flags areswitched on per customer from a separate configuration repo, so merging this changes nothing by
itself. No frontend changes and no database migration.
The traits that make the rewrite work: problem first, numbered concrete scenario before mechanism, key terms bolded and defined inline, the flag anchored to the general feature-flag concept, short sentences.
Related skills
FAQ
What is the source of truth for the walkthrough?
Git-based evidence such as changed files and diffs is the source of truth; conversation context is used only as planning input.
How are steps ordered?
Steps are ordered dependency-first: contracts and definitions are introduced before the call sites that use them, then runtime flow order.