Skip to content

fix(cli): make a committed .brain/ faithful and fix two layer misfires - #1

Merged
luuuc merged 2 commits into
mainfrom
fix/init-and-classification
Sep 18, 2026
Merged

luuuc merged 2 commits into
mainfrom
fix/init-and-classification

Conversation

@luuuc

@luuuc luuuc commented Sep 18, 2026

Copy link
Copy Markdown
Owner

Summary

Two defects found while running the shipped binary end-to-end: brain init scaffolds a directory git cannot carry faithfully, and the layer classifier misfiles decisions and lessons.

Changes

init — git hygiene

  • Writes .brain/.gitignore covering *.lock. Lock files (effectiveness/.lock, trust/trust.yml.lock) are flock targets holding no memory, so committing one shipped another machine's runtime state to everyone who clones.
  • Writes a .gitkeep in each layer directory. git carries files, not directories, so every empty layer vanished on the way through a commit and created facts/ was a promise git silently broke.
  • ensureConfig generalises to ensureFile, keeping the O_EXCL write so a second init never clobbers a file you edited.

engine — classification

  • "We chose Go over Rust for the CLI" filed as a fact. The only decision signal for that verb was "chose to", but the object of a choice is usually the thing chosen. Broadened to "chose ", plus "picked " and "went with".
  • "Never run migrations without a backup" filed as a correction. It is a lesson. Corrections now key on overriding the tool's behaviour ("stop ", "override", "don't flag", "do not suggest"); bare prohibitions fall through to lessons.

Architecture Highlights

Corrections and lessons have opposite lifetimes: a lesson retires after a clean streak, a correction is permanent and immutable (.doc/definition/03-data-model.md). Filing a lesson as a correction creates a rule that can never be forgotten — the failure brAIn exists to avoid — so an ambiguous prohibition now resolves to the layer that can retire.

Neither .gitignore nor .gitkeep is load-bearing: every write path already creates its own parent, and commands work fine against a .brain/ missing its empty directories. This only makes a committed .brain/ match the one init reports creating.

Test Plan

  • .gitignore covers both lock names, verified through a real git add -A — lock files unstaged, memory files staged
  • Every layer directory has something staged after a commit, so a clone keeps the tree
  • A second init leaves an edited .gitignore alone
  • The two real-world misfires assert their corrected layers; the five prescriptive-rule cases moved from correction to lesson
  • make ci passes (build + test + lint, 0 issues)
  • Manual end-to-end: init → three remember calls land in decisions/, lessons/, corrections/

init told you to commit .brain/, then handed you a directory git could
not carry faithfully. Lock files went in — effectiveness/.lock and
trust/trust.yml.lock are flock targets holding no memory, so a clone got
another machine's runtime state. The empty layer directories stayed out,
since git carries files, so "created facts/" was a promise a commit
silently broke.

init now writes a .gitignore covering *.lock and a .gitkeep in each layer
directory. Neither is load-bearing — every write path already creates its
own parent — so this only makes a committed .brain/ match the one init
reports creating.

ensureConfig generalises to ensureFile, keeping the O_EXCL write that
stops a second init clobbering a file you edited.
Two misfires, both from signal lists that were too blunt.

"We chose Go over Rust for the CLI" landed in facts, because the only
decision signal for that verb was "chose to" — but the object of a choice
is usually the thing chosen, not an infinitive. Broadened to "chose ",
with "picked " and "went with" alongside the existing "going with".

"Never run migrations without a backup" landed in corrections, because
"never " was a correction signal. It is a lesson: a rule drawn from
something that happened. The layers have opposite lifetimes — a lesson
retires after a clean streak, a correction is permanent and immutable —
so filing one as the other creates a rule that can never be forgotten,
which is the failure brAIn exists to avoid.

Corrections now key on overriding the tool's behaviour ("stop ",
"override", "don't flag", "do not suggest"); bare prohibitions fall
through to lessons.
@luuuc luuuc added the bug Something isn't working label Sep 18, 2026
@luuuc
luuuc merged commit 17fa20d into main Sep 18, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant