Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ To measure any of this, `qmd bench <fixture.json> -c memories` is usable as ship

**The same three copies carry "retrieve before relying on a result", and the reason is only recorded here.** qmd's MCP snippet is at most five lines and 300 characters (`extractSnippet` in `store.js`, called with a hardcoded `300` from `mcp/server.js`), and it is anchored by literal substring matching of the first `lex` sub-query. When those terms are not in the matched text it falls back to the top of the chunk — in practice the file's first three lines, which for a memory is its title and `Applies to:`. Measured on a 527-document corpus, 28% of results came back title-only. So a search result is a lead, and answering from it is guessing; `get`/`multi_get` is the step that makes the answer real. The instruction is phrased as an absolute in all three copies on purpose — stating the failure condition invites the reader to decide a snippet looks complete this time. Do not "simplify" it back into step 2's old wording (`Read matching memories`), which worked only because the previous backend returned a whole chunk.

**Three text blocks must stay byte-identical across three files.** `capture-rules`, `strip-the-anchors`, and `applies-to` appear in both `SKILL.md`s and in `SYNC-BLOCKS.md`, enforced by `scripts/check-sync-blocks.mts` in CI. Two rules when touching them:
**Four text blocks must stay byte-identical across three files.** `capture-rules`, `strip-the-anchors`, `applies-to`, and `drop-shapes` appear in both `SKILL.md`s and in `SYNC-BLOCKS.md`, enforced by `scripts/check-sync-blocks.mts` in CI. Two rules when touching them:

- Blocks are verdict-neutral. Each skill adds its own verb *outside* the fence — capture says "skip", audit says "DROP". Never move an action verb inside the locked block.
- Never write a real tag name in prose. The drift check grabs the first matching opener, so a literal mention would shadow the canonical block and make it invisible to the verifier. `SYNC-BLOCKS.md` uses a placeholder form for exactly this reason.
Expand All @@ -83,4 +83,4 @@ To measure any of this, `qmd bench <fixture.json> -c memories` is usable as ship

**Check what contradiction a change creates.** Both skills carry emphatic guidance that can overrule a softer new instruction. The audit's "in genuine doubt, prefer DROP" is the clearest example: a new rule saying "report this rather than dropping it" loses unless that guideline is carved out explicitly. After editing, read the new text alongside the sections that push the opposite way.

Six DROP categories are duplicated between the two skills with nothing keeping them in step, and so are capture's Staleness Prevention and the audit's C.5 Staleness Signals, and the `Pending:` convention (capture's Check 3 and **Update existing** list, the audit's Step 2, DROP category A, and C.5), and rewrite-in-place editing (capture's **Update existing**, the audit's Step 4). Change one side, check the other.
Some rules still pair across the two skills with nothing keeping them in step: capture's Staleness Prevention and the audit's C.5 Staleness Signals, the `Pending:` convention (capture's Check 3 and **Update existing** list, the audit's Step 2 and C.4, row D1 of the shared block, and C.5), and rewrite-in-place editing (capture's **Update existing**, the audit's Step 4). Change one side, check the other.
34 changes: 31 additions & 3 deletions SYNC-BLOCKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Every memory must satisfy all three rules.

- **Tied to at least one project.** The content must be about the architecture, conventions, bugs, workflows, or tool interactions of at least one real project named in `Applies to:`. Multi-project entries are fine when the same convention genuinely holds across several repos, listed comma-separated. Out of scope: free-floating language, framework, or CLI knowledge with no project anchor — that belongs in the tool's own docs. Public documentation anyone could look up (language reference, framework README, public CLI docs, public API reference) is also out. Internal project docs (Confluence pages, ADRs, RFCs, team wiki) are different: a memory summarizing one *is* project knowledge, provided it links back to the source in `References:`. Test: *"Name the project(s) this applies to and why."* If the answer is "any project, it's just how the tool works" → the memory does not qualify. Every claim must also change how a session works in a project whose sessions read this KB. Listing another project in `Applies to:` does not make its internals relevant: knowledge of another project's internals is cut down to the conclusion that changes work in the reading project. A claim about another project counts as checked only if the session read that project's code, or an internal doc cited in `References:`.
- **Anonymous.** No personal names, GitHub/Slack handles, or emails anywhere in the memory — not in the problem description, not in examples, not in narration of "who did what." Describe the artifact (the bug, the pattern, the decision), not who touched it. Identifiers age badly and add no signal even in a single-user KB.
- **Project pattern, not personal preference.** Memories must capture what the *project* does, not what an individual engineer likes. A pattern qualifies when any of these hold: it is enforced by lint/formatter config, documented in a style guide or ADR, agreed by the team (written *or* verbal — chat, meeting, or the user stating the agreement in the session), **or** already used consistently in the codebase. Codebase usage is the strongest evidence that a pattern exists, but code written in the same session is no evidence at all: the pattern needs a precedent from before the session, a lint rule or ADR, or a stated agreement. Usage alone does not make the pattern worth a memory, because the code already conveys it — unless new code could break it unnoticed. If the only support is *"I prefer,"* *"I like,"* *"my style,"* it is a preference and does not qualify.
- **Project pattern, not personal preference.** Memories must capture what the *project* does, not what an individual engineer likes. A pattern qualifies when any of these hold: it is enforced by lint/formatter config, documented in a style guide or ADR, agreed by the team (written *or* verbal — chat, meeting, or the user stating the agreement in the session), **or** already used consistently in the codebase. Codebase usage is the strongest evidence that a pattern exists, but code written in the same session is no evidence at all: the pattern needs a precedent from before the session, a lint rule or ADR, or a stated agreement. Usage shows the pattern exists; whether it is worth a memory is the forcing-function's call. If the only support is *"I prefer,"* *"I like,"* *"my style,"* it is a preference and does not qualify.
- **Bad patterns present in the code** are handled by category, not by exclusion. If one engineer flags a pattern as bad without team ratification, the appropriate shape is a `learning_` warning (e.g. `learning_dont_use_X_because_Y`) — **only** when it carries trigger (*"when you use X in case Y…"*), symptom (*"…it leaks / races / drops data"*), and avoidance (*"use Z instead"*). If the team has agreed the pattern is bad and should be avoided or replaced, the team agreement itself makes it a `decision_` (e.g. `decision_architecture_deprecate_X`). Pure *"this should be refactored someday"* observations without that shape belong in the issue tracker.
<!-- /SYNC -->
```
Expand All @@ -32,7 +32,7 @@ Every memory must satisfy all three rules.
## Block 2: Strip-the-anchors test

Locations:
- `skills/continuous-learning/SKILL.md` — inside Step 4 (pre-save Check 1)
- `skills/continuous-learning/SKILL.md` — inside Step 3 (pre-save Check 1)
- `skills/memory-audit/SKILL.md` — inside criterion 1

```markdown
Expand All @@ -46,7 +46,7 @@ Locations:
## Block 3: `Applies to:` semantics

Locations:
- `skills/continuous-learning/SKILL.md` — inside Step 4 (`### Applies to` subsection)
- `skills/continuous-learning/SKILL.md` — inside Step 3 (`### Applies to` subsection)
- `skills/memory-audit/SKILL.md` — inside the `Applies to:` callout near the top

```markdown
Expand All @@ -59,6 +59,34 @@ When a memory genuinely applies to multiple projects, list them comma-separated

---

## Block 4: Shapes that do not qualify

Locations:
- `skills/continuous-learning/SKILL.md` — `## Do Not Save`
- `skills/memory-audit/SKILL.md` — `## DROP Categories`

Each row is a shape, an example, why it fails, and its exception, with no verdict. Capture's lead-in makes a match "not saved"; the audit's makes it DROP.

```markdown
<!-- SYNC:drop-shapes -->
| # | Shape | Example | Why it fails | Exception |
|---|-------|---------|--------------|-----------|
| D1 | Self-marked superseded, deferred, or abandoned | Says **SUPERSEDED**, *deferred indefinitely*, *closed without implementation*, or points at another memory as the current decision | The current memory carries the decision; a cross-link back from it is enough provenance. | A `Pending:` line marks work in flight, not deferral. |
| D2 | Record of a shipped one-time change | "Renamed folder `Install/` to `Sync/` after the command rename" | Once shipped, history answers it, and sessions read the current code, not the migration story. Without version control nothing else records the change, so judge it on behavior alone. | The change still imposes a constraint future code must honor; the memory is then about the constraint. |
| D3 | Naming or style decision an enforcer covers | "Kept the `External` prefix on adapter types" | The type system, lint, or formatter carries the decision. | It carries what the code cannot show: a rejected alternative with its reason, or a trap as trigger, symptom, and avoidance. A bare unenforced rule is D10. |
| D4 | One-time bug fix the code now shows | "The filter skipped the first element instead of the matching one; it now compares identity" | The code reads correctly today; a future regressor reads the code, not the KB. | The bug class recurs, or the memory names the tempting simplification and what it breaks, as trigger, symptom, and avoidance. |
| D5 | Description of what specific code does | "What the new `ReportPublisher` chain emits and in which order" | Merged, the code explains itself; written in the same session, it is no evidence (Rule 3). | A trap the code does not show, stated as trigger, symptom, and avoidance. |
| D6 | Generic engineering wisdom with a token project example | "Extract methods over condensing for lint compliance", one PR cited | Strip the example and a textbook tip remains (Rule 1). | — |
| D7 | Tool, language, or public API reference | "`git rebase -i` opens a todo list"; how an internal proxy's mock rules work, with project endpoints sprinkled in | Applies to any project using the tool (Rule 1); it belongs in the tool's docs or `CLAUDE.local.md`. | — |
| D8 | Fault in one engineer's environment | "Signed requests fail because this machine's clock drifts with NTP blocked" | Not project behavior, even with project anchors; it is that engineer's `CLAUDE.local.md` note. | — |
| D9 | Research for deferred or dormant work | "Options considered for feature X (deferred)" | It belongs in a planning doc; the KB is for how a session works on the active code today. | Findings a current decision depends on. |
| D10 | One-line rule | A single-sentence convention with no context or consequences | It fits one bullet in `CLAUDE.md`, where it belongs — suggest that bullet. A file is overhead for content that cannot grow. | — |
| D11 | Narrow learning covered by a sibling | A 30-line facet of the 200-line learning next to it | The sibling answers the same search. Any line the sibling lacks moves into it. | — |
<!-- /SYNC -->
```

---

## Drift verification (CI-ready)

```sh
Expand Down
2 changes: 1 addition & 1 deletion scripts/check-sync-blocks.mts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { resolve } from "node:path";

const root = resolve(import.meta.dirname, "..");
const files = ["skills/continuous-learning/SKILL.md", "skills/memory-audit/SKILL.md", "SYNC-BLOCKS.md"];
for (const tag of ["capture-rules", "strip-the-anchors", "applies-to"]) {
for (const tag of ["capture-rules", "strip-the-anchors", "applies-to", "drop-shapes"]) {
const blocks = files.map(file => {
const lines: string[] = [];
let inside = false;
Expand Down
Loading
Loading