ADR 0004 — Scope learned instincts to the project by default, promote to global only on repeated evidence
Status: Implemented (v2.1 extension) · Area: continuous-learning-v2 · Skill: continuous-learning-v2
continuous-learning-v2 starts from an open-source base skill (origin: ECC) that captures tool-call
observations via hooks and distills them into scored "instincts" — small, reusable learned behaviors.
That base stored every instinct in a single global pool. In practice, that meant a convention learned
in one project (a React component pattern, a project-specific test-naming rule) would surface as a
"learned instinct" inside an unrelated Python or Rust project where it didn't apply — noise at best,
actively wrong guidance at worst.
| Option | Pros | Cons |
|---|---|---|
| A. Keep a single global instinct pool (the inherited default) | Simple; every instinct visible everywhere | Cross-project contamination — instincts from one project's conventions leak into unrelated ones |
| B. Fully isolate instincts per project, no promotion path | No contamination, ever | Genuinely universal instincts ("always validate input at a boundary") have to be re-learned independently in every project |
| C. Project-scoped storage by default, with an explicit promotion path to global once evidence crosses a bar | No contamination for project-specific instincts; universal ones still generalize, but only after proof | Requires a project-identity mechanism that's stable across machines, and a promotion policy to design and tune |
Option C. Each project gets its own instinct storage partition, keyed by a hash of its git remote
URL (with any embedded credentials stripped before hashing, and a fallback to a repo-path hash for
projects with no remote) — chosen specifically so the same repository checked out on two different
machines still maps to the same project identity. Global-scope instincts still exist, but an instinct
only reaches global scope through an explicit promote step, gated on being independently observed in
two or more separate projects at a high average confidence — not on being merely useful once.
On load, project-scoped instincts take precedence over global ones with the same ID, so a project-specific override always wins over a generalized default.
- Git-remote hashing solves the "same repo, different machine" identity problem that a raw filesystem path can't — a path-based identity would treat the same project checked out to two different laptops as two different projects, defeating the purpose of learning at all.
- Requiring cross-project repetition before promotion is a deliberately conservative bar. A single project's convention is not evidence that a pattern is universal; the promotion gate exists specifically to prevent one project's idiosyncrasy from being generalized prematurely.
- Credential-stripping before hashing is a small but real security detail — a remote URL can legitimately contain an embedded token, and hashing it unmodified would mean a credential rotation silently changes a project's identity (and, worse, means the raw credential briefly exists in memory on the way to becoming a hash input in an untrusted code path).
- A migration path was needed for existing instinct data that predated credential-stripping — the system detects when stripping changes a project's computed hash and renames the existing storage directory rather than orphaning old data.
- Two directories now exist per learning system installation (project-scoped and global) instead of one — slightly more bookkeeping in the CLI, in exchange for isolation that has already prevented real cross-project noise.
- The two-project promotion threshold is a starting point, not a proven-optimal number; if it proves too conservative (genuinely universal instincts taking too long to generalize) or too loose (noise reaching global scope), it's a single tunable value to revisit — not a structural change.