@renzrollon/interlock 1.0.0

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.
Files changed (125) hide show
  1. package/.claude-plugin/marketplace.json +19 -0
  2. package/.claude-plugin/plugin.json +58 -0
  3. package/CHANGELOG.md +380 -0
  4. package/LICENSE +21 -0
  5. package/README.md +358 -0
  6. package/agents/ping.md +8 -0
  7. package/agents/worker.md +8 -0
  8. package/bin/interlock +2655 -0
  9. package/bin/interlock-graph +6 -0
  10. package/bin/interlock-run +508 -0
  11. package/bin/interlock-ship-acp +39 -0
  12. package/hooks/_shared.mjs +162 -0
  13. package/hooks/guard-commit.mjs +77 -0
  14. package/hooks/guard-tasks.mjs +107 -0
  15. package/hooks/guard-tests.mjs +63 -0
  16. package/hooks/preflight.mjs +107 -0
  17. package/lib/artifacts.mjs +316 -0
  18. package/lib/autonomy.mjs +149 -0
  19. package/lib/conformance.mjs +132 -0
  20. package/lib/doctor.mjs +1176 -0
  21. package/lib/drift.mjs +409 -0
  22. package/lib/eval-history.mjs +304 -0
  23. package/lib/evals-calibrate.mjs +317 -0
  24. package/lib/evals-capture.mjs +437 -0
  25. package/lib/evals-promote.mjs +257 -0
  26. package/lib/evals-triage.mjs +216 -0
  27. package/lib/findings.mjs +340 -0
  28. package/lib/graph/cli.mjs +266 -0
  29. package/lib/graph/extract/config-json.mjs +74 -0
  30. package/lib/graph/extract/create-extractor.mjs +35 -0
  31. package/lib/graph/extract/memory.mjs +99 -0
  32. package/lib/graph/extract/openspec.mjs +80 -0
  33. package/lib/graph/extract/python.mjs +137 -0
  34. package/lib/graph/extract/regex-fallback.mjs +187 -0
  35. package/lib/graph/extract/shell.mjs +71 -0
  36. package/lib/graph/extract/typescript.mjs +217 -0
  37. package/lib/graph/extract/walk.mjs +272 -0
  38. package/lib/graph/format.mjs +51 -0
  39. package/lib/graph/graph/build.mjs +374 -0
  40. package/lib/graph/graph/query.mjs +249 -0
  41. package/lib/graph/graph/report.mjs +122 -0
  42. package/lib/graph/graph/update.mjs +47 -0
  43. package/lib/graph/paths.mjs +66 -0
  44. package/lib/graph/retrieve/context.mjs +86 -0
  45. package/lib/graph/retrieve/docs-index.mjs +116 -0
  46. package/lib/graph/retrieve/markdown.mjs +246 -0
  47. package/lib/host/acp.mjs +551 -0
  48. package/lib/host/claude-cli.mjs +285 -0
  49. package/lib/host/codex.mjs +231 -0
  50. package/lib/host/model-map.mjs +129 -0
  51. package/lib/host/qwen.mjs +176 -0
  52. package/lib/host/registry.mjs +213 -0
  53. package/lib/host.mjs +393 -0
  54. package/lib/ledger.mjs +444 -0
  55. package/lib/limits.mjs +525 -0
  56. package/lib/locators.mjs +99 -0
  57. package/lib/merge-lanes.mjs +148 -0
  58. package/lib/metrics.mjs +99 -0
  59. package/lib/notify.mjs +229 -0
  60. package/lib/outcomes.mjs +560 -0
  61. package/lib/plan-fingerprint.mjs +570 -0
  62. package/lib/project-slug.mjs +18 -0
  63. package/lib/prompts/commit.mjs +26 -0
  64. package/lib/prompts/dimensions.mjs +70 -0
  65. package/lib/prompts/handoff.mjs +86 -0
  66. package/lib/prompts/implementer.mjs +150 -0
  67. package/lib/prompts/index.mjs +250 -0
  68. package/lib/prompts/planner.mjs +70 -0
  69. package/lib/prompts/remediate.mjs +137 -0
  70. package/lib/prompts/replan.mjs +23 -0
  71. package/lib/prompts/review.mjs +107 -0
  72. package/lib/prompts/schemas.mjs +206 -0
  73. package/lib/prompts/stage.mjs +48 -0
  74. package/lib/prompts/verify.mjs +88 -0
  75. package/lib/ready.mjs +812 -0
  76. package/lib/receipt.mjs +434 -0
  77. package/lib/remediate.mjs +275 -0
  78. package/lib/report-html.mjs +623 -0
  79. package/lib/report.mjs +1124 -0
  80. package/lib/review-core.mjs +713 -0
  81. package/lib/risk.mjs +370 -0
  82. package/lib/run-log.mjs +1004 -0
  83. package/lib/run-paths.mjs +239 -0
  84. package/lib/run.mjs +2921 -0
  85. package/lib/ship-stage.mjs +223 -0
  86. package/lib/spill.mjs +150 -0
  87. package/lib/surface.mjs +195 -0
  88. package/lib/verify.mjs +1074 -0
  89. package/lib/waves.mjs +2661 -0
  90. package/package.json +40 -0
  91. package/shared/CONTEXT-HYGIENE.md +84 -0
  92. package/shared/DECISION-LEDGER.md +141 -0
  93. package/shared/EXPLORE-BRIEF.md +96 -0
  94. package/shared/INVARIANT-SWEEP.md +57 -0
  95. package/shared/SESSION-SHAPES.md +261 -0
  96. package/shared/SKILL-CANDIDATE-BRIEF.md +106 -0
  97. package/shared/TEST-PROFILE.md +204 -0
  98. package/shared/TOOL-ECONOMY.md +155 -0
  99. package/skills/bootstrap/SKILL.md +226 -0
  100. package/skills/commit/SKILL.md +99 -0
  101. package/skills/dispatch/SKILL.md +78 -0
  102. package/skills/docs-digest/SKILL.md +109 -0
  103. package/skills/evals/SKILL.md +160 -0
  104. package/skills/explain-code/SKILL.md +42 -0
  105. package/skills/explain-code/commit-teachin.md +136 -0
  106. package/skills/explain-code/module-walkthrough.md +358 -0
  107. package/skills/explore/SKILL.md +159 -0
  108. package/skills/fix-tests/SKILL.md +120 -0
  109. package/skills/graph/SKILL.md +136 -0
  110. package/skills/manual-test-plan/SKILL.md +121 -0
  111. package/skills/mr/SKILL.md +170 -0
  112. package/skills/report/SKILL.md +121 -0
  113. package/skills/review-artifacts/SKILL.md +127 -0
  114. package/skills/review-code/REVIEW.template.md +49 -0
  115. package/skills/review-code/SKILL.md +156 -0
  116. package/skills/review-code/dimensions/architecture.md +10 -0
  117. package/skills/review-code/dimensions/devops.md +12 -0
  118. package/skills/review-code/dimensions/language.md +12 -0
  119. package/skills/review-code/dimensions/qa.md +12 -0
  120. package/skills/review-code/dimensions/security.md +12 -0
  121. package/skills/review-code/dimensions/technical-lead.md +19 -0
  122. package/skills/ship/SKILL.md +67 -0
  123. package/skills/spec/SKILL.md +264 -0
  124. package/skills/spec/continuity.md +66 -0
  125. package/workflows/ship.js +565 -0
@@ -0,0 +1,160 @@
1
+ ---
2
+ name: evals
3
+ description: Author an Interlock eval case from an observed model-behaviour failure, and read a completed eval results run. Use when you have a reproduced failure — an archived proposal, a changelog entry, a run artifact, or a transcript — worth regression-testing against a real model, or when an eval run has finished and you need to know whether it is a regression, run-to-run variance, or no signal. Authoring needs cited evidence; the verdict comes from `interlock evals triage`, never from your own reading.
4
+ license: MIT
5
+ compatibility: Requires the early-access eval harness (`claude plugin eval`, enabled with CLAUDE_CODE_WALNUT_SPIRE=1) to RUN a suite. Authoring a case and triaging an existing results file need only Node.js >= 18 and the bundled interlock CLI.
6
+ allowed-tools: Bash(interlock *) Bash(claude plugin eval *) Read Grep Glob Write
7
+ metadata:
8
+ type: authoring
9
+ outputs:
10
+ - evals/<case>/case.yaml
11
+ - evals/<case>/graders/*.md
12
+ ---
13
+
14
+ This skill covers the two jobs the eval harness does not do for you: turning an
15
+ observed failure into a case, and reading a finished run. Everything with a
16
+ correct answer — is this a regression? — belongs to `interlock evals triage`, not
17
+ to you. Your job is evidence, grader choice, and explanation.
18
+
19
+ ## 1. Authoring a case — only from an observed failure
20
+
21
+ A case regression-tests a **reproduced** failure: a model read correct
22
+ instructions and did the wrong thing anyway. Before you write anything, require
23
+ the evidence:
24
+
25
+ - an archived proposal (`openspec/changes/archive/*/proposal.md` `## Why`),
26
+ - a `CHANGELOG.md` entry,
27
+ - a run artifact or a transcript,
28
+ - a **captured skeleton** — `interlock evals capture --run <runId> [--task <id>]
29
+ --out <dir>` turns a recorded ship-run trajectory into a case draft whose
30
+ provenance names the trajectory and the events it was derived from, or
31
+ - a `file:line` span in the prompt or skill under test that shows the surface
32
+ the model talked past.
33
+
34
+ **A captured skeleton is a draft, not a finished case.** It is admissible
35
+ evidence because it is a run artifact and a reader can follow its citation back
36
+ to the trajectory. But every value capture derived rather than read carries a
37
+ `CONFIRM` marker — the grader pattern when no value could be quoted, and the
38
+ prompt when the trajectory recorded none. **Resolve every `CONFIRM` marker
39
+ against the cited trajectory, or ask the user, before authoring the case. Never
40
+ author a case that still carries one**, and never move a skeleton into `evals/`
41
+ unresolved: an unconfirmed pattern is a regression test for a failure nobody has
42
+ shown happened.
43
+
44
+ **If no observed failure is offered, say so and stop.** Do not author a
45
+ speculative case. A suite of hypotheticals teaches the team to ignore it, which
46
+ is the one thing an advisory gate cannot survive. A case that only duplicates an
47
+ existing `node:test` assertion is refused for the same reason — the unit suite
48
+ already covers it deterministically.
49
+
50
+ Record the citation in the case (`provenance:` in `case.yaml`, plus a comment
51
+ explaining what went wrong). The structural gate `test/evals.test.mjs` fails a
52
+ case with no provenance.
53
+
54
+ ### The case files
55
+
56
+ Every case pins `schema_version` and lives in its own directory under `evals/` —
57
+ never under `skills/`, `agents/`, `commands/` or `workflows/`, which would shadow
58
+ a component. Follow `evals/handoff-status-enum/` as the format exemplar; it was
59
+ written to establish these conventions. Where a case needs a fixture workspace,
60
+ use `case.yaml` with `context.scaffold_script` and run with `--scaffold`;
61
+ otherwise the same `case.yaml` shape without it.
62
+
63
+ ## 2. Choosing a grader — cheapest that expresses the assertion
64
+
65
+ The harness has six grader types. Four are free and deterministic — `regex`,
66
+ `tool_used`, `tool_order`, `file_exists` — and two call a judge — `llm`,
67
+ `baseline`.
68
+
69
+ **Pick the cheapest grader that expresses the assertion.** If the assertion is
70
+ set-membership, tool-invocation, file-existence, or ordering shaped, it is
71
+ deterministic and a judged grader is the wrong tool — more expensive, and prone
72
+ to run-to-run variance triage will (correctly) refuse to call a regression. The
73
+ strongest seed case, `handoff-status-enum`, needs no judge at all: the status is
74
+ in a fixed set, so a `regex` decides it.
75
+
76
+ **When you do reach for a judged grader, state in the grader body which part of
77
+ the assertion could not be expressed deterministically.** If you cannot name
78
+ that part, the assertion was deterministic and you chose the wrong grader.
79
+
80
+ A case you intend to run per-pull-request tag `smoke`, and a smoke case uses
81
+ **only** deterministic graders — the gate enforces this. A grader that asserts a
82
+ skill *fired* (`tool_used: Skill`) is marked `arm: with-only`: it is a
83
+ plugin-fired indicator, reported against the baseline arm, not part of the score.
84
+
85
+ ## 3. Reading a run — triage owns the verdict
86
+
87
+ Given a finished results file, **get the classification from
88
+ `interlock evals triage --results <file>`, do not derive it yourself.** Its exit
89
+ code is the verdict: `0` pass, `1` regression, `2` no signal, `3` configuration.
90
+ This is deliberate — the one gate whose rule a model could re-argue on each run
91
+ would be exactly the wrong gate to ship in a suite built to catch models
92
+ re-arguing rules.
93
+
94
+ Your contribution is **explanation, not classification**:
95
+
96
+ - When triage reports a **regression**, explain which recent change to the
97
+ surface under test plausibly caused it — the prompt sentence, the skill edit,
98
+ the contract change. Do not reclassify it as variance because it looks flaky;
99
+ triage already separated a single judged dip (variance) from a judged majority
100
+ (regression).
101
+ - When triage reports **variance**, report it as variance and say what would
102
+ confirm it (further runs failing the same judged grader).
103
+ - When triage reports **no signal** — a partial run, an interrupted run, a
104
+ rejected credential — report that evals could not run. Do not present any case
105
+ as passing or failing.
106
+
107
+ Never restate, override, or soften a verdict triage gave you.
108
+
109
+ ### Read a transcript before you explain a judged case
110
+
111
+ **For every case whose score depends on a judged grader, read at least one
112
+ transcript for that case before you write your explanation of it.** A score is
113
+ the outcome; the trace is the only place the cause is visible. The failure this
114
+ closes is a model that satisfied a judge by narrowing the task rather than by
115
+ doing it — the score moves, every other step in the loop sees a number, and
116
+ nobody sees why.
117
+
118
+ Reading is for explanation and **never for reclassification**. If the transcript
119
+ suggests a different classification than triage produced, report what you saw in
120
+ the trace and leave the verdict alone — the rule above still holds without
121
+ exception.
122
+
123
+ A run whose graders are all deterministic needs no transcript: the tool trace the
124
+ grader already read is the evidence.
125
+
126
+ Your report carries a `transcripts read:` line, always present:
127
+
128
+ ```
129
+ transcripts read: <case>/<id>, <case>/<id>
130
+ transcripts read: none
131
+ transcripts read: unavailable, because <what stopped you reading one>
132
+ ```
133
+
134
+ Use the **none** form when you read no transcript — never omit the line, because
135
+ a reader cannot otherwise tell an unexamined result from an examined one. Use the
136
+ **unavailable, because …** form when the run produced no readable transcript, and
137
+ in that case do not present your explanation as transcript-grounded. Degradation
138
+ is spoken.
139
+
140
+ ## 4. A failing case is a report, never a prompt edit
141
+
142
+ When a case fails, your output is a report: the case, the grader that failed, and
143
+ the sentence in the surface under test that plausibly caused it. **Do not edit
144
+ the skill, shared contract, agent definition, or prompt under test to make a case
145
+ pass.** Changing the surface under test is a separate, explicit decision the user
146
+ makes — silently editing a prompt to turn a case green is exactly the "edit the
147
+ test until it passes" failure the suite exists to prevent, one layer up.
148
+
149
+ ## 5. When the harness is gated
150
+
151
+ `claude plugin eval` prints `` `plugin eval` is currently in early access `` and
152
+ does nothing until `CLAUDE_CODE_WALNUT_SPIRE=1` is set in the environment — never
153
+ in committed `.claude/settings.json`, which would produce a suite that looks
154
+ configured and does not run.
155
+
156
+ When the harness refuses because early access is not enabled, **report the
157
+ prerequisite and where to set it** (the environment, or the CI job's `env:`
158
+ block). Do not report an empty run as a passing suite. Authoring a case and
159
+ triaging an existing results file both work without the harness enabled — only
160
+ running a suite needs it.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: explain-code
3
+ description: Explain code to a beginner in that stack — either a module walkthrough (what each function does, how calls link, where data flows, which patterns recur) or a commit teach-in (why each file changed, what changed, blast radius, what would break if it were left out). Use when asked to explain code, walk through a directory, or explain the last commit.
4
+ license: MIT
5
+ compatibility: Requires git for commit teach-in mode. Optional openspec CLI for change scoping.
6
+ argument-hint: "[path | --commit | --commits N]"
7
+ allowed-tools: Bash(git *) Bash(interlock-graph *) Bash(openspec *) Read Write Grep Glob
8
+ metadata:
9
+ type: teaching
10
+ ---
11
+
12
+ Teach code to someone new to this stack. **Not reviewing, not judging — teaching.**
13
+
14
+ Calibrate to a reader who knows programming fundamentals but is new to this project's language and framework. Explain the idioms that stack takes for granted, one short aside each. Do not explain what a function is.
15
+
16
+ ## Modes
17
+
18
+ | Mode | When | Load |
19
+ |------|------|------|
20
+ | **Module walkthrough** (default) | A file or directory is named, or the user asks how an area works | `${CLAUDE_SKILL_DIR}/module-walkthrough.md` |
21
+ | **Commit teach-in** | Last commit, a hash or range, "what changed", `--commit` / `--commits N` | `${CLAUDE_SKILL_DIR}/commit-teachin.md` |
22
+
23
+ When ambiguous, prefer the module walkthrough unless the user mentioned a commit or "what changed".
24
+
25
+ **After choosing a mode, read the matching sibling file and follow it** for steps, structure, and output format. This file only routes.
26
+
27
+ ## Output path
28
+
29
+ Resolve the destination before writing. Both modes use the same rule:
30
+
31
+ | Situation | Write to |
32
+ |---|---|
33
+ | Scoped to an OpenSpec change — a change name was passed, or one resolves via `openspec status --json` | `openspec/changes/<change-name>/code-explanation.md` |
34
+ | No change context (ad-hoc walkthrough) | `docs/CODE_EXPLANATION.md` |
35
+
36
+ **Do not "simplify" this back to a single path.** A change-scoped explanation belongs beside `manual-test-plan.md` in its own change directory. Writing every run to `docs/CODE_EXPLANATION.md` overwrites the previous change's explanation — and because `docs/` is the corpus `/interlock:docs-digest` indexes, each rewrite permanently marks `.claude/graph/DOCS_DIGEST.md` stale through its `source_hashes`.
37
+
38
+ ## Shared rules
39
+
40
+ - **Single agent, no fan-out.** Understanding builds sequentially; parallel investigators produce four disconnected fragments, which is the opposite of a walkthrough.
41
+ - Write the full explanation to the resolved path (overwrite), then tell the user the file is ready with a 5–10 line summary.
42
+ - Pull domain context on demand: `.claude/graph/DOCS_DIGEST.md` first, then `interlock-graph context` / `docs`. Never preload all of `docs/` — see `${CLAUDE_PLUGIN_ROOT}/shared/TOOL-ECONOMY.md` Rule 0.5.
@@ -0,0 +1,136 @@
1
+ # Commit teach-in — explain-code
2
+
3
+ Teach what changed and why — not a code review.
4
+
5
+ ## Scope
6
+
7
+ Every source file touched in the commit range (skip binaries/lockfiles; cap ~25). Skip tests unless they are the only files and the user asked about them.
8
+
9
+ ## Steps
10
+
11
+ 1. Retrieve domain context on demand — Read `.claude/graph/DOCS_DIGEST.md` if present; then `interlock-graph context` / `docs` as needed (`${CLAUDE_PLUGIN_ROOT}/shared/TOOL-ECONOMY.md` Rule 0.5).
12
+ 2. Resolve range: default `HEAD~1..HEAD`; `--commits N` → `HEAD~N..HEAD`; or an explicit hash/range from the user.
13
+ 3. Gather:
14
+ ```bash
15
+ git log -1 --format='%H%n%s%n%b' # or log for the range
16
+ git diff --stat "$FROM" "$TO"
17
+ git diff --name-status "$FROM" "$TO"
18
+ git diff "$FROM" "$TO" -- <each source file> # cap hunks ~300 lines/file
19
+ ```
20
+ 4. **Blast radius per file** — files that reference the import-specifier stem (basename without extension). For generic stems (`index`, `route`, `page`, `layout`, `config`, `types`, `utils`, `constants`, `main`, `mod`, `SKILL`, `README`, `PROMPT`) qualify with parent directory. Prefer `rg -l` / `git grep -l`; exclude self. Optional: `interlock-graph consumers <symbol>` when the graph exists. Name-match may false-positive — note incidental hits.
21
+ 5. For each changed source file, fill the **Change Context** block (required). Optionally add function breakdown only for complex new/changed logic a beginner needs.
22
+ 6. Write Commit Summary, Per-File Explanation, Change Flow, and Beginner Takeaway; write to the output path resolved in `SKILL.md`:
23
+ - Scoped to an OpenSpec change (name passed, or an active change resolves via `openspec status --json`) → `openspec/changes/<change-name>/code-explanation.md`, alongside `manual-test-plan.md`
24
+ - No change context → `docs/CODE_EXPLANATION.md`
25
+ - Per-change output is deliberate: one shared `docs/` file would overwrite the previous change's explanation and permanently mark `.claude/graph/DOCS_DIGEST.md` stale via its `source_hashes`.
26
+
27
+ ## Change Context (required)
28
+
29
+ ### Change Context (required in commit teach-in)
30
+
31
+ Use this block for every changed source file in commit mode. Status = Added / Modified / Deleted / Renamed from `git diff --name-status`.
32
+
33
+ ```markdown
34
+ #### `path/to/file.ext` — <Added | Modified | Deleted | Renamed>
35
+
36
+ **Why this file needed to change:**
37
+ Plain-language reason this file was part of the commit. Tie it back to the commit's
38
+ goal — what would be incomplete without touching this file?
39
+
40
+ **What changed:**
41
+ - Bullet the concrete edits from the diff (new function, changed signature, added
42
+ field, deleted branch…). Skip boilerplate (import reordering, whitespace).
43
+ - Explain any TypeScript / React / Next.js concept a beginner wouldn't know,
44
+ in one short aside each.
45
+
46
+ **Blast radius:**
47
+ - Who is affected downstream, based on the referencing files gathered for this path.
48
+ - Rate it: **Isolated** (self-contained), **Local** (a few callers in one area),
49
+ or **Wide** (shared util/type/config touched by many files).
50
+ - Name the specific files most likely to feel the change and how.
51
+
52
+ **If this file had been left out:**
53
+ - What would break, fail to compile, or behave wrong if this file's change were
54
+ missing from the commit but every other file's change shipped?
55
+ - Be concrete: name the type error, runtime failure, broken flow, or silent bug.
56
+ - If the file is genuinely independent (nothing else depends on the change),
57
+ say so plainly — "nothing would break; this change is self-contained."
58
+ ```
59
+
60
+ Rules for Change Context:
61
+ - Teach, don't judge. No code-review verdicts, no "should have" critiques.
62
+ - Ground every claim in the diff and blast-radius data — do **not** invent callers, functions, or failure modes you can't see.
63
+ - Be concise but complete — every changed source file gets its own block.
64
+
65
+ ## Output Format
66
+
67
+ ### Commit teach-in
68
+
69
+ Match the explain-code loop structure (no review verdicts):
70
+
71
+ ```markdown
72
+ # Code Explanation: commit <short-hash> — <subject>
73
+
74
+ ## Commit Summary
75
+
76
+ One or two sentences, in plain language: what does this commit accomplish and why?
77
+ Reference the commit subject but translate any jargon for a beginner.
78
+
79
+ ---
80
+
81
+ ## Per-File Explanation
82
+
83
+ [One Change Context block per changed source file — see above]
84
+
85
+ ---
86
+
87
+ ## Change Flow
88
+
89
+ If the commit spans multiple layers (e.g. type → data layer → component → route),
90
+ draw the dependency order as a short chain:
91
+
92
+ `types/batch.ts (new field)` → `lib/db.ts (reads field)` → `app/api/.../route.ts` → `components/BatchCard.tsx`
93
+
94
+ One line per chain. Write `(single-layer — no cross-layer flow)` if N/A.
95
+
96
+ ---
97
+
98
+ ## Beginner Takeaway
99
+
100
+ One sentence naming the single most important concept a beginner should learn
101
+ from studying this commit (e.g. "shared types are a coupling point — changing one
102
+ field ripples through every consumer").
103
+ ```
104
+
105
+ If there are no commits to explain: write only `No commits to explain yet.` and stop.
106
+
107
+ ## Tone & Style
108
+
109
+ ## Tone & Style
110
+
111
+ - **Friendly, encouraging, zero condescension** — "we" language, like a senior sitting next to you
112
+ - **Skip the obvious** — don't explain what `const x = 5` does
113
+ - **Explain the non-obvious** — why this pattern? why server vs client? why does this call SQS here?
114
+ - **Name every external service call** — never skip an infra interaction, these are critical for understanding the system
115
+ - **Use analogies** — "Think of SQS like a to-do list for a background worker — we drop a note saying 'process this batch', and a separate service picks it up later"
116
+ - **Show the full journey** — from user action → through the code → to the database/service → back to the UI
117
+ - **Keep it scannable** — headers, bullet points, tables, code blocks. No walls of text.
118
+
119
+ ---
120
+
121
+ ## What NOT to Do
122
+
123
+ - Don't review or critique the code
124
+ - Don't suggest improvements (unless asked)
125
+ - Don't explain import statements, simple variable declarations, or trivial types
126
+ - Don't explain test files
127
+ - Don't use jargon without defining it on first use
128
+ - Don't be condescending ("as you probably know" / "this is simple")
129
+ - Don't explain node_modules or third-party library internals (just say what the library does)
130
+ - Don't skip infrastructure calls — every DB query, S3 operation, SQS message, and auth check must appear in the flow
131
+ - Don't use subagents or workflows — this skill requires sequential understanding across files
132
+ - In commit teach-in, don't skip Change Context fields — every changed source file needs Why / What / Blast radius / If left out
133
+ - Don't invent blast-radius callers or breakage modes not evidenced by the diff or reference search
134
+
135
+ - In commit teach-in, don't skip Change Context fields — every changed source file needs Why / What / Blast radius / If left out
136
+ - Don't invent blast-radius callers or breakage modes not evidenced by the diff or reference search