Skip to content

Latest commit

 

History

History
111 lines (90 loc) · 5.31 KB

README.md

File metadata and controls

111 lines (90 loc) · 5.31 KB

Knowledge Base (docs/helpers/)

A persistent, single-writer knowledge base. Lessons learned here carry over to future tasks, so the same mistakes are not made twice and past decisions do not need to be re-derived.

Files

  • faq.md — recurring pitfalls and their solutions (RabbitMQ Stream plugin, E2E broker ports, gh default limits, socket_select loop gotchas, server-push frame key rule). Entry ids FAQ-NNN.
  • decisions.md — project decisions with rationale (protocol conventions, exception hierarchy, coverage policy, naming) and a reference to the issue/PR/commit that introduced them. Entry ids DEC-NNN.

Both files are linted by bin/kb-lint.php, which runs inside composer lint.

Rules

  1. Read before you start — the index, not the file. Every file opens with a generated tag index. Load the index, pick the tags matching the files in your diff, then read only those ### entries. Reading either file end to end is a waste of context and is not what the index is for.
  2. Only the retro step writes here. coder / coder-high and review / review-critical propose candidate entries in their report — title, suggested tags, trigger, one paragraph — and the retro step decides what lands and commits it. Two writers gave us duplicates, unlabelled entries and a file nobody could load selectively; the retro step (step 14 of docs/workflow.md) is the single writer. A subagent that "just appends" outside that step is doing the wrong thing.
  3. One topic per entry. The problem, the solution/decision, optionally an issue/PR/commit reference. Do not restate what AGENTS.md already says — AGENTS.md already covers naming conventions, the "Implementing a New Protocol Command" template and the server-push frame table, so link to it instead of duplicating it.
  4. Prefer a gate over an entry. If an automated check (regression test, PHPStan rule, PHPCS rule) could catch the class of defect, add the check. The knowledge base is a buffer for what cannot be automated yet, not a destination. PHPStan runs at level 9 here — a missing type or unreachable branch is a static-analysis catch, not a knowledge-base entry.
  5. In doubt, ask. If it is unclear whether something belongs here (or where), ask the user.

Entry front matter

Markdown has no per-section front matter, so every entry carries a single-line HTML comment immediately after its ### heading. It renders as nothing and parses with one regex:

### Some entry title
<!-- id=FAQ-001 date=2025-01-01 tags=foo,bar trigger="when X" hits=0 status=active -->

The body of the entry.

Grammar: <key>=<value>, all on one line. A value is either bare (no whitespace) or double-quoted. The comment must be the very next line after the heading. No value may contain -->, quoted or not: an HTML comment ends at its first one, so the rest of the entry would render as visible text.

Key Required Meaning
id yes FAQ-NNN in faq.md, DEC-NNN in decisions.md; unique across both files and never reused
date yes ISO-8601 YYYY-MM-DD — when the entry was learned (the referenced issue/PR, or the commit that introduced it)
tags yes comma-separated [a-z0-9-] tags, no spaces; these feed the tag index
trigger yes quoted phrase answering "when should an agent load this?"
hits yes how many cycles actually used the entry; the retro increments it
status yes active | promoted | stale
gate only for promoted the test/rule that replaced the entry

Tag index

Each file has a generated index between the markers <!-- kb-index:start --> and <!-- kb-index:end -->, mapping every tag to the entry ids that carry it. It is regenerated by:

php bin/kb-lint.php --fix

composer lint fails when the index is out of sync with the entries, so it is never stale. Loading one entry looks like this:

sed -n '/^<!-- kb-index:start/,/^<!-- kb-index:end/p' docs/helpers/faq.md   # the index
awk '/^### /{p=0} /id=FAQ-002/{p=1} p' docs/helpers/faq.md                  # one entry

Decay

The knowledge base is capped at 300 lines per file (the generated index does not count, nor does the ## Tag index heading and the blank lines around it). bin/kb-lint.php warns above that; the retro step brings it back under by applying two rules:

  • promoted — the lesson is now encoded as a test, a PHPStan rule or a lint rule. The entry collapses to a one-liner naming the gate in gate="…"; the detail lives in the check itself. kb-lint enforces the collapse (at most two body lines) and refuses a promoted entry without a gate.
  • stale — 0 hits over 20 cycles. kb-lint.php does not compute this from hits itself: the retro is the one that judges an entry stale (0 hits over STALE_AFTER_CYCLES cycles) and sets status=stale; kb-lint then only lists entries already marked that way, in a machine-checkable form the retro can act on, and removes them at the next pass. If nobody loaded it in 20 cycles it is not knowledge, it is sediment.

An entry is never edited in place to say something different: change the content, change the date, and say what changed and why.