@rafinery/cli 0.10.0 → 0.12.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.
- package/CHANGELOG.md +49 -0
- package/bin/rafa.mjs +10 -0
- package/blueprint/.claude/agents/atlas.md +2 -2
- package/blueprint/.claude/agents/bloom.md +3 -2
- package/blueprint/.claude/commands/rafa.md +1 -1
- package/blueprint/.claude/rafa/contract.md +27 -4
- package/blueprint/.claude/skills/rafa-build/SKILL.md +5 -1
- package/blueprint/.claude/skills/rafa-commit/SKILL.md +22 -0
- package/blueprint/.claude/skills/rafa-distill/SKILL.md +37 -4
- package/blueprint/.claude/skills/rafa-improve/SKILL.md +17 -6
- package/blueprint/.claude/skills/rafa-okf/SKILL.md +1 -1
- package/blueprint/.claude/skills/rafa-plan/SKILL.md +14 -1
- package/blueprint/.claude/skills/rafa-scan/SKILL.md +9 -1
- package/blueprint/.claude/skills/rafa-security/SKILL.md +96 -0
- package/lib/audit/core.mjs +488 -0
- package/lib/audit.mjs +279 -0
- package/lib/blueprint.mjs +1 -0
- package/lib/checkpoint.mjs +14 -5
- package/lib/distill.mjs +56 -3
- package/lib/distiller/doctrine.mjs +4 -4
- package/lib/distiller/schema-ladder.mjs +186 -0
- package/lib/doctor.mjs +16 -0
- package/lib/gate/compile.mjs +17 -13
- package/lib/init.mjs +3 -2
- package/lib/manifest.mjs +2 -1
- package/lib/mcp-client.mjs +10 -2
- package/lib/push.mjs +9 -3
- package/lib/releases.mjs +27 -0
- package/lib/stamp.mjs +24 -0
- package/lib/working-set.mjs +3 -2
- package/package.json +1 -1
- package/skills-bundle/skills-manifest.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,55 @@ The machine-readable version of this lives in [`lib/releases.mjs`](lib/releases.
|
|
|
4
4
|
CLI reads it to tell a client, on `rafa update`, exactly what an upgrade requires (nothing,
|
|
5
5
|
a re-scan, or a `rafa migrate`).
|
|
6
6
|
|
|
7
|
+
## 0.11.0 — schema-aware reconciliation (the 4-case ladder)
|
|
8
|
+
|
|
9
|
+
Distillation is where knowledge from two lineages meets — so it is now also
|
|
10
|
+
where brain SCHEMA VERSIONS meet. Before any claim-level judging, the
|
|
11
|
+
reconciler resolves target (the org brain) vs source (the branch's candidates)
|
|
12
|
+
vs the runner's own latest schema:
|
|
13
|
+
|
|
14
|
+
1. **target < source** → full target-brain rewrite onto the newer schema,
|
|
15
|
+
riding the same run's gates + push (one migration+reconcile commit).
|
|
16
|
+
2. **target > source** → incoming old-schema candidates lift into the
|
|
17
|
+
target's schema before judging.
|
|
18
|
+
3. **target == source, both < latest** → the merged target rewrites onto the
|
|
19
|
+
runner's latest.
|
|
20
|
+
4. **target == source == latest** → plain diff reconcile — the happy flow,
|
|
21
|
+
exactly as before.
|
|
22
|
+
|
|
23
|
+
Either side NEWER than the runner aborts loudly — update the runner;
|
|
24
|
+
knowledge is never downgraded. Transforms are registered per step AND per
|
|
25
|
+
OKF type (`lib/distiller/schema-ladder.mjs` — each step declares rule ·
|
|
26
|
+
playbook · improvement explicitly: a function, or the EXPLICIT "unchanged",
|
|
27
|
+
which still re-stamps the version line; derived/generated files regenerate
|
|
28
|
+
at the new schema, they never migrate); a missing step or class fails
|
|
29
|
+
loudly — the ladder never guesses a schema. v1 is the only schema in existence, so today
|
|
30
|
+
every reconcile is case 4; this ships the SEAM (fully tested) that turns a
|
|
31
|
+
future v2 into a one-entry registry change instead of a migration crisis.
|
|
32
|
+
|
|
33
|
+
**Descriptive commits (owner 2026-07-26).** Reconciliation commits now SAY
|
|
34
|
+
what the run did: the headless distiller composes
|
|
35
|
+
`reconcile(<branch>): N banked · M refuted · K adjudication — <ids…>` and
|
|
36
|
+
passes it via the new `rafa push --message=` override (the brain-for trailer
|
|
37
|
+
is untouched — provenance consumers keep their key); the session SOP carries
|
|
38
|
+
the same rule. And the commit contract (rafa-commit) now REQUIRES an
|
|
39
|
+
agent-readable body on dev commits: what concretely changed, the why the diff
|
|
40
|
+
can't show, brain-note join keys, no session deixis — the next reader of a
|
|
41
|
+
commit is usually an agent.
|
|
42
|
+
|
|
43
|
+
**The configurable prod branch reaches the CLI.** `trunkBranchOf` resolves
|
|
44
|
+
the stamped `rafa.json → prodBranch` → git's origin/HEAD → "main"; the
|
|
45
|
+
checkpoint trunk guard and the CI distill target use it (with prodBranch set,
|
|
46
|
+
"main" can be a plain feature-carrying branch). The platform side shipped the
|
|
47
|
+
`repos.prodBranch` setting + repo-page card in the same arc.
|
|
48
|
+
|
|
49
|
+
Also in this release (landed after 0.10.0's publish): distill-refutation loop
|
|
50
|
+
events carry the required actor envelope + a dedupeKey (a retried distill
|
|
51
|
+
counts each resolution once); `cliActorMeta` honors `RAFA_ACTOR_RUNNER` for
|
|
52
|
+
sandbox/CI attribution; and dependsOn invalidation is documented as NOT
|
|
53
|
+
transitive, with breadth-of-declaration taught as the conservative pattern at
|
|
54
|
+
`rafa facts add`, the CLI help, and prism's citation rule (pinned by test).
|
|
55
|
+
|
|
7
56
|
## 0.10.0 — wave 6: the capability arc (skill dependencies + agent upgrades)
|
|
8
57
|
|
|
9
58
|
rafa's agents get materially better at engineering — and the mechanism is the
|
package/bin/rafa.mjs
CHANGED
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
// rafa distill --headless CI merge-to-main distillation (org's own LLM key)
|
|
19
19
|
// rafa ci-setup write the reconcile workflow (fold + distill on PR merge)
|
|
20
20
|
// rafa leverage inspect your agent toolbox → proactive tips
|
|
21
|
+
// rafa audit [--json] self-contained security engine: dep CVEs (OSV) ·
|
|
22
|
+
// secrets (built-in ruleset) · SAST (semgrep if present)
|
|
21
23
|
// rafa benchmark reproduce the brain-vs-cold token proof on THIS repo (measured)
|
|
22
24
|
// rafa migrate bring structured files (plans/config) up to the current schema
|
|
23
25
|
//
|
|
@@ -53,6 +55,7 @@ const COMMANDS = [
|
|
|
53
55
|
"distill",
|
|
54
56
|
"ci-setup",
|
|
55
57
|
"leverage",
|
|
58
|
+
"audit",
|
|
56
59
|
"benchmark",
|
|
57
60
|
"manifest",
|
|
58
61
|
"review",
|
|
@@ -140,6 +143,13 @@ Commands:
|
|
|
140
143
|
PR merge) and name the CI secrets to configure.
|
|
141
144
|
leverage Inspect your agent toolbox (permissions, skills, MCP) and print
|
|
142
145
|
prioritized tips for getting more out of it. Advisory — changes nothing.
|
|
146
|
+
audit Self-contained security engine (rafa.audit/v1): dependency CVEs via
|
|
147
|
+
the built-in lockfile parser + OSV.dev (pnpm audit merged in),
|
|
148
|
+
secrets via the built-in ruleset (tracked files only, .env* never
|
|
149
|
+
opened, fingerprints never bytes), SAST via semgrep IF present —
|
|
150
|
+
tiers that can't run say so honestly. --json emits the envelope;
|
|
151
|
+
writes .rafa/improve/security-audit.{json,md} when .rafa exists.
|
|
152
|
+
Exit: 0 clean · 1 findings · 2 engine error. Installs nothing.
|
|
143
153
|
benchmark Reproduce the brain-vs-cold token-efficiency proof on THIS repo: cut
|
|
144
154
|
two isolated worktrees (A=cold, B=brain), run the same task fixture,
|
|
145
155
|
count harness tokens, emit a MEASURED benchmark.json. --dry-run
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: atlas
|
|
3
|
-
version: 4.
|
|
3
|
+
version: 4.1.0
|
|
4
4
|
model: opus # authoring is correctness-critical — a hallucinated note poisons the brain; best model, never cheap
|
|
5
5
|
groundTruth: code-at-sha
|
|
6
6
|
description: >-
|
|
@@ -15,7 +15,7 @@ color: blue
|
|
|
15
15
|
duties:
|
|
16
16
|
- "scan :: .claude/skills/rafa-scan/SKILL.md :: comprehensive breadth-first cited brain · verify-citations exits 0 · coverage honest (thin/gap stated, never hidden)"
|
|
17
17
|
- "repair :: .claude/skills/rafa-scan/SKILL.md :: every blocker + major in checklist.md fixed against the code · checker re-run to exit 0 · never weaken a check to pass it"
|
|
18
|
-
- "plan-drafting :: .claude/skills/rafa-plan/SKILL.md :: recall-grounded decomposition (coverage → search → notes) · blast radius named · contract §7 files · every child carries a Done-check"
|
|
18
|
+
- "plan-drafting :: .claude/skills/rafa-plan/SKILL.md :: recall-grounded decomposition (coverage → search → notes) · blast radius named · contract §7 files · every child carries a Done-check · the security audit runs BEFORE approval and its picture is presented to the dev verbatim (§3b — totals + blast-radius criticals; clean said out loud, never silence)"
|
|
19
19
|
- "build-execution :: .claude/skills/rafa-build/SKILL.md :: implement per recalled knowledge · TDD-DEFAULT when the tdd skill + a harness are present (the Done-check is a failing test FIRST at the plan-named seam; red→green evidence in the return) · UI tasks run the installed design skills per SOP (brain conventions win) · read session-facts FIRST and bank new expensive verifications (rafa facts add) · never hand-edit brain files around the gate · return what changed, cited"
|
|
20
20
|
- "scoped-refresh :: .claude/skills/rafa-scan/SKILL.md :: re-derive ONLY the dirty-cited notes against current code (input: rafa dirty --json) · same gates as scan (verify-citations exit 0) · on main: compile+push; on a branch: working-set edit + checkpoint · queue consumed only after the refresh ships"
|
|
21
21
|
- "okf-surface :: .claude/skills/rafa-okf/SKILL.md :: authored files pass rafa okf check as written — body links are markdown (never wikilinks); emit-owned sections untouched"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bloom
|
|
3
|
-
version: 0.
|
|
3
|
+
version: 0.10.0
|
|
4
4
|
model: opus # a false flag mutes the whole ledger — best model, never cheap
|
|
5
5
|
groundTruth: code-trend
|
|
6
6
|
description: >-
|
|
@@ -15,7 +15,8 @@ color: green
|
|
|
15
15
|
duties:
|
|
16
16
|
- "improve-pass :: .claude/skills/rafa-improve/SKILL.md :: cited · prioritized P0–P3 · the architecture lens applies the deletion-test/depth method with its vocabulary (Confidence-lined candidates, first-slice-or-backlog, never big-bang) · leverage-ranked · cite-checked (unresolved dropped) · ledger + debt trend regenerated"
|
|
17
17
|
- "plan-pull :: .claude/skills/rafa-plan/SKILL.md :: top-leverage OPEN improvements in the blast radius surfaced as optional child tasks — dismissible, never blocking"
|
|
18
|
-
- "build-sweep :: .claude/skills/rafa-build/SKILL.md :: newly spotted → ledger files · fixed-in-passing → status fixed · at most ONE opt-in nudge per task"
|
|
18
|
+
- "build-sweep :: .claude/skills/rafa-build/SKILL.md :: newly spotted → ledger files · fixed-in-passing → status fixed · at most ONE opt-in nudge per task · the cheap dependency tier of `rafa audit` re-runs so a mid-build lockfile change is caught"
|
|
19
|
+
- "security-profile :: .claude/skills/rafa-security/SKILL.md :: `rafa audit --json` is the engine (never LLM-pretended) · findings → category:security rows with the MECHANICAL priority map (critical→P0…dev-only→P3, annotate reachability, never downgrade) · P0 security rows are the ONE class that may surface outside the blast radius (dismissible, never blocking)"
|
|
19
20
|
- "staleness-watch :: .claude/skills/rafa-improve/SKILL.md :: median open-item age stays minimal — every sweep re-validates or closes aged items; no improvement ages silently"
|
|
20
21
|
- "okf-surface :: .claude/skills/rafa-okf/SKILL.md :: improvements/ledger pass rafa okf check as written · found: authored so timestamps are authored truth"
|
|
21
22
|
---
|
|
@@ -232,7 +232,7 @@ explicitly typed; an ACCEPTED boundary offer counts as the explicit invocation.
|
|
|
232
232
|
|---|---|---|
|
|
233
233
|
| `plan <intent>` | trio decomposition — atlas drafts brain-grounded contract §7 files (Done-checks), bloom pulls blast-radius improvements, prism validates the plan; approval → compile → `push_plan` + `set_active_plan` | [rafa-plan](../skills/rafa-plan/SKILL.md) |
|
|
234
234
|
| `build` | execute the active plan per item (in `blocked_by` order): atlas recalls+implements → prism gates `status: done` on the `## Done-check` → bloom sweeps the ledger → update file + journals → checkpoint (push_plan/log_decision/`rafa checkpoint`); final verify + clear `active.md` when all children done | [rafa-build](../skills/rafa-build/SKILL.md) |
|
|
235
|
-
| `improve` | spawn bloom → cited, prioritized P0–P3 ledger in `.rafa/improve/`; surface only the top few high-leverage items, never nag | [rafa-improve](../skills/rafa-improve/SKILL.md) |
|
|
235
|
+
| `improve` | spawn bloom → cited, prioritized P0–P3 ledger in `.rafa/improve/`; surface only the top few high-leverage items, never nag. Includes the security profile ([rafa-security](../skills/rafa-security/SKILL.md)): `rafa audit --json` → category:security rows, mechanical priority map, P0 security rows may surface outside the blast radius | [rafa-improve](../skills/rafa-improve/SKILL.md) |
|
|
236
236
|
| `scan [--brain-only]` | the full pass know → verify → improve → push — atlas maps → gate-1 checker → prism validates → iterate (max 3) → improve → push on approval → founding-scan coach offer. `--brain-only` stops after validation. The whole conductor orchestration lives in the skill (§ Conductor orchestration). | [rafa-scan](../skills/rafa-scan/SKILL.md) |
|
|
237
237
|
| `init` | first run: ensure `.rafa/active.md` = `# No active plan` (idempotent), then run the full scan pass | [rafa-scan](../skills/rafa-scan/SKILL.md) |
|
|
238
238
|
| `distill [<branch>]` | reconcile a merged branch's working set into the org brain — prism validates each file vs merged MAIN, atlas authors survivors through verify-citations · compile · push, refutes with cites, flags `needs-adjudication`. Offer-driven at bootstrap; CI runs it headlessly. | [rafa-distill](../skills/rafa-distill/SKILL.md) |
|
|
@@ -197,7 +197,8 @@ JSON. This is the exact shape the platform binds to.
|
|
|
197
197
|
{
|
|
198
198
|
"id": "dead-model-options-google-crewai",
|
|
199
199
|
"priority": "P1", // P0 | P1 | P2 | P3
|
|
200
|
-
"
|
|
200
|
+
"category": "product", // security|correctness|performance|architecture|product|ops
|
|
201
|
+
"lens": "product", // transitional mirror of category (pre-2026-07-26 name) — dropped with the backfill arc
|
|
201
202
|
"status": "open", // open | backlog | fixed | wontfix
|
|
202
203
|
"title": "…",
|
|
203
204
|
"summary": "…",
|
|
@@ -278,7 +279,7 @@ value).
|
|
|
278
279
|
schemaVersion: 1
|
|
279
280
|
id: dead-model-options-google-crewai # required · == filename stem
|
|
280
281
|
priority: P1 # required · P0 | P1 | P2 | P3
|
|
281
|
-
|
|
282
|
+
category: product # required · security|correctness|performance|architecture|product|ops
|
|
282
283
|
status: open # required · open | backlog | fixed | wontfix
|
|
283
284
|
title: Two of the four model options are dead and fail silently # required
|
|
284
285
|
summary: google_genai and crewai route to unwired agents # required
|
|
@@ -295,6 +296,11 @@ found: 2026-07-02 # optional · ISO date
|
|
|
295
296
|
Note: `title`, `summary`, `fix` are now **required frontmatter** — previously scraped
|
|
296
297
|
from prose. That scraping is gone; these are authored values.
|
|
297
298
|
|
|
299
|
+
`category` is the canonical field name (2026-07-26). The pre-rename name `lens`
|
|
300
|
+
is accepted as a **deprecated alias** by the compile gate (`category ?? lens`,
|
|
301
|
+
same enum); the manifest carries both keys during the transition. New files
|
|
302
|
+
author `category:` only.
|
|
303
|
+
|
|
298
304
|
---
|
|
299
305
|
|
|
300
306
|
## 4. Health file — `brain/checklist.md`
|
|
@@ -455,6 +461,23 @@ imported comments are never scraped into decisions.
|
|
|
455
461
|
fields do NOT bump it** — e.g. the note size stamps (`bodyTokens`,
|
|
456
462
|
`cites[].targetTokens`, §1): ingest tolerates their absence, so a legacy manifest
|
|
457
463
|
without them stays valid at the same `schemaVersion`.
|
|
464
|
+
- **The reconciliation schema ladder (0.11.0 — owner's 4-case doctrine).** When a
|
|
465
|
+
version bump DOES ship, distillation is the upgrade moment — the reconciler
|
|
466
|
+
resolves target-vs-source-vs-runner before judging: target below source → full
|
|
467
|
+
target rewrite onto the newer schema; source below target → incoming candidates
|
|
468
|
+
lift before judging; both equal-but-old → the merged target rewrites onto the
|
|
469
|
+
runner's latest; both current → plain diff (today). Either side newer than the
|
|
470
|
+
runner → **abort loudly** (update the runner; knowledge is never downgraded).
|
|
471
|
+
Transforms are registered per step AND per OKF type in the CLI
|
|
472
|
+
(`lib/distiller/schema-ladder.mjs`): each step declares rule · playbook · improvement
|
|
473
|
+
explicitly — a function, or the EXPLICIT `"unchanged"` (still re-stamps the note's
|
|
474
|
+
`schemaVersion:`); an unregistered step or class fails loudly — the ladder never
|
|
475
|
+
guesses a schema. Class resolves by CHAIN: the governed directory first (inside the
|
|
476
|
+
transport the path IS identity — the CAS row key), then the portable filename suffix
|
|
477
|
+
(`.rule.md` · `.playbook.md` · `.improvement.md`) for files travelling outside the
|
|
478
|
+
canonical tree; a contradiction between the two is a loud error. Only durable
|
|
479
|
+
knowledge migrates; derived/generated files
|
|
480
|
+
(coverage · checklist · ledger · reports · the manifest) regenerate at the new schema.
|
|
458
481
|
- **Validate-and-correct:** `rafa compile` validates every file. On failure it emits
|
|
459
482
|
a structured error — `path · field · rule` — to the **authoring agent** (atlas for
|
|
460
483
|
notes, bloom for improvements/ledger, prism for checklist). The agent edits the
|
|
@@ -512,9 +535,9 @@ i.e. the default branch's instance).
|
|
|
512
535
|
|
|
513
536
|
**Search = deterministic lexical retrieval; the server retrieves, the agent decides.**
|
|
514
537
|
Fields searched per type — rule/playbook: `title, summary, domain, type` ·
|
|
515
|
-
improvement: `title, summary,
|
|
538
|
+
improvement: `title, summary, category, blast_radius` · plan: `title, plan, parent`.
|
|
516
539
|
Score = Σ over matched case-folded query tokens of field weight (`title` 3 ·
|
|
517
|
-
`domain`/`
|
|
540
|
+
`domain`/`category`/`blast_radius`/`type`/`plan`/`parent` 2 · `summary` 1); tie-break
|
|
518
541
|
score desc then id asc; fields a type lacks are omitted, never defaulted. Candidates
|
|
519
542
|
carry `matchKind: "lexical"` (`"semantic"` reserved).
|
|
520
543
|
|
|
@@ -43,7 +43,11 @@ platform MCP (one read path — the same surface any third-party agent uses).
|
|
|
43
43
|
[rafa-commit](../rafa-commit/SKILL.md) format — `[<task-id>] <type>:
|
|
44
44
|
<subject>` (the id join-key; intent records + the branch manifest lift it
|
|
45
45
|
into per-note provenance)** → prism validates vs `## Done-check` →
|
|
46
|
-
bloom sweeps (push new / close fixed / nudge
|
|
46
|
+
bloom sweeps (push new / close fixed / nudge; **when THIS task changed a
|
|
47
|
+
lockfile/manifest, re-run the cheap dependency tier — `rafa audit --json` —
|
|
48
|
+
and report the delta to the dev in one transparent line: new/cleared
|
|
49
|
+
findings, never silence**; a new critical → a `category: security` P0 row
|
|
50
|
+
surfaced now) → update the child file's `status`
|
|
47
51
|
**and append a dated entry to the child's `## Log`** (body links: markdown,
|
|
48
52
|
per [rafa-okf](../rafa-okf/SKILL.md)) — what was done, what was
|
|
49
53
|
decided, what surprised (body prose: displayed verbatim on the platform, never
|
|
@@ -36,6 +36,28 @@ description: "rafa SOP — generate the commit message with the id join-key: the
|
|
|
36
36
|
outcome one-line ("Done-check: prism PASS") — the receipt travels with the
|
|
37
37
|
code.
|
|
38
38
|
|
|
39
|
+
## The body is REQUIRED and written for an AGENT reader (owner 2026-07-26)
|
|
40
|
+
|
|
41
|
+
A subject-only commit is a broken contract here. The next reader of this
|
|
42
|
+
message is most often an AGENT — ours (atlas recalling why a line exists, the
|
|
43
|
+
distiller judging a claim against this change, sage reading shapes) or a
|
|
44
|
+
foreign one — so the body must be SELF-CONTAINED and joinable:
|
|
45
|
+
|
|
46
|
+
- **What, concretely** — the surfaces/behaviors that changed, named (not
|
|
47
|
+
"various fixes"); a reader must know the blast radius without the diff.
|
|
48
|
+
- **Why — the intent** — the one thing the diff cannot show. State the
|
|
49
|
+
problem/decision that made this change necessary; paraphrase the pivotal
|
|
50
|
+
choice if one was made (it should also be a `log_decision`).
|
|
51
|
+
- **Join keys** — mention the brain notes this change follows or invalidates
|
|
52
|
+
(`per rule <id>` / `staleness: touches <id>`), so the cite-graph and the
|
|
53
|
+
dirty queue read straight out of the log.
|
|
54
|
+
- **No session deixis** — never "as discussed", "per the above", "the same
|
|
55
|
+
fix as before": the message must stand alone in `git log` a year later,
|
|
56
|
+
with zero conversation context.
|
|
57
|
+
|
|
58
|
+
TDD-default red commits keep their fixed form (`[<task-id>] test: red —
|
|
59
|
+
<seam>`) — the seam IS the body's content there.
|
|
60
|
+
|
|
39
61
|
## Why this exists (don't skip the bracket)
|
|
40
62
|
|
|
41
63
|
The brain-commit hook captures every subject into `intent/<sha>.md`;
|
|
@@ -39,6 +39,28 @@ code it describes.
|
|
|
39
39
|
1. **Collect** — `get_working_set(repo, branch, status: active)`. Zero files →
|
|
40
40
|
nothing to do, say so, stop. Rows already `needs-adjudication` are a HUMAN's
|
|
41
41
|
to resolve — surface them in the digest, never fold them in silently.
|
|
42
|
+
1b. **Schema ladder (0.11.0 — the owner's 4-case doctrine).** Before ANY
|
|
43
|
+
claim-level judging, resolve the version lattice: **target** = the org
|
|
44
|
+
brain's `manifest.json → schemaVersion` (else max over its notes; a
|
|
45
|
+
pre-manifest brain is the founding v1) · **source** = max over the
|
|
46
|
+
collected candidates' own `schemaVersion` · **latest** = the running CLI's
|
|
47
|
+
`SCHEMA_VERSION`. Then: **target < source → REWRITE-TARGET** (every org-
|
|
48
|
+
brain note lifts to the newer schema and rides THIS run's gates + push —
|
|
49
|
+
one migration+reconcile commit) · **target > source → UPGRADE-SOURCE**
|
|
50
|
+
(incoming candidates lift into the target's schema before judging) ·
|
|
51
|
+
**equal but < latest → REWRITE-MERGED** (both lift; the merged target is a
|
|
52
|
+
full rewrite onto latest) · **equal and == latest → DIFF** (the happy flow,
|
|
53
|
+
steps 2–6 exactly as written). **Either side > latest → ABORT LOUDLY** — a
|
|
54
|
+
newer CLI authored it; update the runner, knowledge is never downgraded.
|
|
55
|
+
Transforms are REGISTERED per step AND per OKF type
|
|
56
|
+
(`lib/distiller/schema-ladder.mjs` — each step declares rule · playbook ·
|
|
57
|
+
improvement explicitly: a function, or the EXPLICIT "unchanged", which
|
|
58
|
+
still re-stamps the note's schemaVersion line); a missing step OR class is
|
|
59
|
+
a loud error, never a guess. Only durable knowledge ladders — derived/
|
|
60
|
+
generated files (coverage · checklist · ledger · reports · manifest)
|
|
61
|
+
REGENERATE at the new schema; intent records pass through untouched. The
|
|
62
|
+
headless CLI runs this mechanically; the session path applies the same
|
|
63
|
+
lattice by hand.
|
|
42
64
|
2. **Validate (prism, context-isolated)** — the target is **merged MAIN as of
|
|
43
65
|
NOW, never the fork point and never a stale checkout**: `git fetch origin`
|
|
44
66
|
first; judge every claim against the fetched trunk. Confirm every citation
|
|
@@ -51,7 +73,13 @@ code it describes.
|
|
|
51
73
|
files lost it — re-declare); fold into an existing note when one covers the
|
|
52
74
|
topic (supersede, never duplicate).
|
|
53
75
|
4. **Gate + ship** — `rafa verify-citations` AND `rafa compile` to exit 0 →
|
|
54
|
-
`rafa push
|
|
76
|
+
`rafa push --verb=distill --message="reconcile(<branch>): <N> banked ·
|
|
77
|
+
<M> refuted · <K> adjudication — <banked ids…>"`. The reconciliation
|
|
78
|
+
commit is DESCRIPTIVE (owner 2026-07-26): its subject states what THIS run
|
|
79
|
+
did — branch, per-verdict counts, the banked note ids — so any agent
|
|
80
|
+
walking the brain log understands the commit without opening it (the
|
|
81
|
+
headless CLI composes this automatically; the session path passes it
|
|
82
|
+
explicitly). Only now has anything entered the org brain. A failed gate
|
|
55
83
|
aborts EVERYTHING: nothing resolved, nothing pushed, working set intact.
|
|
56
84
|
5. **Resolve** — `resolve_working_file(path, distilled)` for survivors — authored
|
|
57
85
|
per the OKF surface ([rafa-okf](../rafa-okf/SKILL.md); push emits the rest) —
|
|
@@ -61,9 +89,14 @@ code it describes.
|
|
|
61
89
|
which files died and why (cited); refutation is feedback, not silence. At
|
|
62
90
|
that same resolve beat emit **`report_loop_event(category:
|
|
63
91
|
"distill-refutation", outcome: refuted|distilled, subject: <path or note
|
|
64
|
-
id
|
|
65
|
-
|
|
66
|
-
|
|
92
|
+
id>, actorMeta: {model: <the judging model>, agent: "distiller@<ver>" (or
|
|
93
|
+
"prism@<ver>" on the session path), runner: session|ci|sandbox — the tier
|
|
94
|
+
this distill runs in}, dedupeKey: "<branch>·<path>·<outcome>")`** — sage's
|
|
95
|
+
evidence that a claim met the gates or was refuted (shapes only: the
|
|
96
|
+
outcome + a file/note reference, never the refuted content, never the
|
|
97
|
+
cited code). Wave 5 is STRICT: an emit without the actor envelope is
|
|
98
|
+
rejected loudly; the dedupeKey makes a re-run of the same distillation
|
|
99
|
+
count ONCE. Checkpoint-adjacent, monotonic, never a session-end sweep.
|
|
67
100
|
`resolve_working_file(path, needs-adjudication, note)` for the undecidable —
|
|
68
101
|
the next session's digest offers the decision.
|
|
69
102
|
|
|
@@ -50,7 +50,7 @@ Invoke via `/rafa improve`. The brain (#1) must exist — bloom *uses* it as the
|
|
|
50
50
|
## Output (to `.rafa/improve/`)
|
|
51
51
|
|
|
52
52
|
- `improvements/<id>.md` — one file per improvement (cited, prioritized, status-tracked).
|
|
53
|
-
- `ledger.md` — generated index: counts by priority/
|
|
53
|
+
- `ledger.md` — generated index: counts by priority/category/status + the **health/debt trend**.
|
|
54
54
|
Its **frontmatter carries the machine-read `open` · `debt_score` · `by_priority`** (per
|
|
55
55
|
[`.claude/rafa/contract.md`](../../rafa/contract.md) §5) — the platform reads *that*, never the body tables,
|
|
56
56
|
and `rafa compile` cross-checks `open`/`by_priority` against the actual improvement rows.
|
|
@@ -65,7 +65,7 @@ platform shows them; nothing is scraped from prose). Example *illustrative — f
|
|
|
65
65
|
schemaVersion: 1
|
|
66
66
|
id: rsc-route-level-use-client # required · kebab = filename stem
|
|
67
67
|
priority: P1 # required · P0|P1|P2|P3
|
|
68
|
-
|
|
68
|
+
category: architecture # required · security|correctness|performance|architecture|product|ops (pre-2026-07-26 name `lens` is a deprecated alias)
|
|
69
69
|
status: open # required · open|backlog|fixed|wontfix
|
|
70
70
|
title: Route-level "use client" silently disables RSC # required
|
|
71
71
|
summary: A route-level directive kills RSC down the whole subtree; no gate catches it # required
|
|
@@ -109,9 +109,15 @@ convention — see [RSC client boundary](/brain/rules/rsc-client-boundary.md)).
|
|
|
109
109
|
ledger speaks the repo's own language).
|
|
110
110
|
- **The big-bang guard is sovereign** (directive 1): a `Strong` candidate lands as its first
|
|
111
111
|
10-minute slice or a P2 backlog item — never a grand refactor plan.
|
|
112
|
-
3. **
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
3. **The security profile.** Run `npx @rafinery/cli audit --json` — the SELF-CONTAINED
|
|
113
|
+
engine (dep CVEs via the built-in OSV client + pnpm audit; secrets via the built-in
|
|
114
|
+
ruleset; SAST via semgrep only if present — a tier that didn't run says `ran:false`).
|
|
115
|
+
Then follow [rafa-security](../rafa-security/SKILL.md): findings → `category: security`
|
|
116
|
+
rows with the MECHANICAL priority map (critical→P0 · high→P1 · moderate→P2 ·
|
|
117
|
+
low/dev-only→P3), reachability annotated from the brain's domain map but never
|
|
118
|
+
downgraded, same-fix CVEs grouped into one row. The LLM pass (authz per route,
|
|
119
|
+
webhook verification, input validation) is observational only — never present it
|
|
120
|
+
as an authoritative audit.
|
|
115
121
|
4. **Write improvements.** One file per improvement, cited (`file:line :: token`), prioritized,
|
|
116
122
|
leverage-ranked. **Reconcile** against the existing ledger: dedup; **auto-close** improvements
|
|
117
123
|
whose code is now clean (`status: fixed`); **preserve** the dev's prior triage
|
|
@@ -119,7 +125,7 @@ convention — see [RSC client boundary](/brain/rules/rsc-client-boundary.md)).
|
|
|
119
125
|
5. **Cite-check (the fidelity gate).** Run
|
|
120
126
|
`npx @rafinery/cli verify-citations --root=.rafa/improve --dirs=improvements`. Every cite
|
|
121
127
|
must resolve; **drop or fix any that don't** — a hallucinated improvement is the cardinal sin.
|
|
122
|
-
6. **Ledger + trend.** Regenerate `ledger.md`: counts by priority/
|
|
128
|
+
6. **Ledger + trend.** Regenerate `ledger.md`: counts by priority/category/status + a **debt
|
|
123
129
|
score** (weighted open improvements) and its trend vs the last run — the compounding made
|
|
124
130
|
visible. Write the machine-read **frontmatter** `open` · `debt_score` · `by_priority`
|
|
125
131
|
([contract §5](../../rafa/contract.md)) — the platform reads that.
|
|
@@ -167,6 +173,11 @@ in that area and nudge once — *"2 P1s here, one's a 10-min fix — take it whi
|
|
|
167
173
|
ranked by leverage, **dismissible, never blocking.** Not built here; this capability produces
|
|
168
174
|
the ledger the nudge will read.
|
|
169
175
|
|
|
176
|
+
**The one exception to blast-radius scoping: `category: security` P0s.** A critical
|
|
177
|
+
CVE lives in no file the dev is touching, so a P0 security row may surface at
|
|
178
|
+
plan/build boundaries regardless of region — one line, dismissible, never blocking,
|
|
179
|
+
never re-nagged in the same session.
|
|
180
|
+
|
|
170
181
|
---
|
|
171
182
|
|
|
172
183
|
## Anti-patterns (each is a way bloom gets muted)
|
|
@@ -50,7 +50,7 @@ Conformance is our distribution wedge; verification stays the moat.
|
|
|
50
50
|
| Agent | Files | What OKF-native means for you |
|
|
51
51
|
|---|---|---|
|
|
52
52
|
| **atlas** | `brain/rules/` · `brain/playbooks/` · `brain/coverage.md` | author `type` (§2 enum) + `title` + `summary` as ever; body cross-links as markdown links; optionally author `description`/`tags` — emit derives them from `summary`/`domain` if you don't |
|
|
53
|
-
| **bloom** | `improve/improvements/` · `improve/ledger.md` | same; your files gain `type: Improvement` + `tags: [
|
|
53
|
+
| **bloom** | `improve/improvements/` · `improve/ledger.md` | same; your files gain `type: Improvement` + `tags: [category, priority]` at emit — author `found:` so timestamps are yours, not git's |
|
|
54
54
|
| **prism** | `brain/checklist.md` | verdict frontmatter as ever (emit stamps `type: Health Report` + a derived description); at validation, treat the checker's LINKS warns as a worklist — dangling links are claims of future knowledge |
|
|
55
55
|
| **sage** | `.claude/rafa/learnings/` | learnings are OKF concepts too: frontmatter + `type: Learning` + markdown links; outside the bundle but under the same protocol |
|
|
56
56
|
| **conductor / plan·build** | `plans/**` · `brain/log.md` | plan items gain `type` from `kind` at emit (per-epic `plans/index.md`); journals + bodies use markdown links; `log.md` stays the reserved trail |
|
|
@@ -23,7 +23,9 @@ Planning is a choreography, not one agent (spec: knowledge-mcp-build-agent):
|
|
|
23
23
|
the tools; the dev never asks for it. Repo not platform-connected (no `rafinery`
|
|
24
24
|
MCP in the session)? Fall back to reading `.rafa/brain/` files directly — same
|
|
25
25
|
knowledge, just unserved.*
|
|
26
|
-
- **bloom pulls** — `list_improvements` in the blast radius
|
|
26
|
+
- **bloom pulls** — `list_improvements` in the blast radius (PLUS any open
|
|
27
|
+
`category: security` P0 regardless of region — the one class that travels;
|
|
28
|
+
one line, dismissible, never blocking); surface the
|
|
27
29
|
top-leverage open items as optional *"while-you're-here"* child tasks
|
|
28
30
|
(leverage-ranked, dismissible, never blocking). **Any improvement the plan
|
|
29
31
|
ADOPTS (as a task or the plan's very subject) is hydrated NOW** —
|
|
@@ -100,6 +102,17 @@ Planning is a choreography, not one agent (spec: knowledge-mcp-build-agent):
|
|
|
100
102
|
the pivotal choices are logged as DECISIONS at approval (`log_decision`:
|
|
101
103
|
context · options · decision · rationale; actor = the dev for their calls).
|
|
102
104
|
3. **Ledger pull** (bloom) → optional leverage tasks in the blast radius.
|
|
105
|
+
3b. **Security transparency** (2026-07-26 r2 — "security is not an aftermath").
|
|
106
|
+
Run `npx @rafinery/cli audit --json` (seconds; reuse a same-session
|
|
107
|
+
`security-audit.json` if fresh) and present the picture TO THE DEV, verbatim
|
|
108
|
+
and unburied, before the plan is approved: one line of severity totals +
|
|
109
|
+
which tiers ran, then any critical/high finding whose package or file sits
|
|
110
|
+
in THIS plan's blast radius (per [rafa-security](../rafa-security/SKILL.md)'s
|
|
111
|
+
reachability method). A blast-radius critical/high → propose it as a plan
|
|
112
|
+
child task (the fix rides the work); open `category: security` P0s surface
|
|
113
|
+
regardless of region. Transparent means: the dev sees the counts even when
|
|
114
|
+
everything is clean — "dependency tier clean at <sha>" is one honest line,
|
|
115
|
+
never silence.
|
|
103
116
|
4. **Leverage-match** — recommend existing skills/tools/MCP that fit the tasks;
|
|
104
117
|
never plan to hand-roll what a capability already does.
|
|
105
118
|
5. **prism plan-validation** → REJECT/fix loop until clean.
|
|
@@ -201,6 +201,13 @@ retrieval index. Bodies read like a senior engineer explaining that one concept
|
|
|
201
201
|
6. **Flow tracing** [LLM, cited] — from each entry point, hop-by-hop to termination
|
|
202
202
|
(render / DB write / response) → `flow` playbooks. Add `how-to` playbooks for the
|
|
203
203
|
recurring "add X" procedures these flows imply.
|
|
204
|
+
**One `security-posture` playbook is required** (2026-07-26): the repo's trust
|
|
205
|
+
boundaries (what's server-exposed vs build-time), auth chokepoints (where
|
|
206
|
+
authz is enforced — cited), and the secret-handling convention (where env
|
|
207
|
+
names are read; names only, per the step-4 guardrail). This is durable
|
|
208
|
+
KNOWLEDGE, not findings — it grounds bloom's security profile
|
|
209
|
+
([rafa-security](../rafa-security/SKILL.md)): reachability annotations on
|
|
210
|
+
CVE rows come FROM this note's map.
|
|
204
211
|
|
|
205
212
|
7. **Verification & synthesis** — apply the 100× filter (a note earns a file only if it
|
|
206
213
|
answers a work-time question AND eliminates a recurring tax), then write the notes. Run
|
|
@@ -255,7 +262,8 @@ pipeline; **`--brain-only`** stops after the brain is validated (step 5 PASS)
|
|
|
255
262
|
do **not** improve or push (never improve/push an unvalidated brain).
|
|
256
263
|
6. **Improve** *(skip if `--brain-only`)* — run the improve pass ([rafa-improve](../rafa-improve/SKILL.md)):
|
|
257
264
|
spawn `bloom` → `.rafa/improve/`. It reads the *validated* brain as its index, so it only
|
|
258
|
-
runs after PASS.
|
|
265
|
+
runs after PASS. The security profile rides this step ([rafa-security](../rafa-security/SKILL.md):
|
|
266
|
+
`rafa audit --json` → category:security rows) — every scan carries it; no separate command.
|
|
259
267
|
7. **Prove it — the measured benchmark** *(skip if `--brain-only`; skip if
|
|
260
268
|
`.rafa/benchmark.json` already carries `measured: true` for this repo)* —
|
|
261
269
|
the proof engine is WORKFLOW-WOVEN, never a dev-typed command (owner
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rafa-security
|
|
3
|
+
description: "rafa SOP — the security profile: run the self-contained `rafa audit` engine (dep CVEs via OSV · secrets · SAST if present), brain-ground reachability, author category:security improvements with the mechanical priority map, emit the profile. Loaded by bloom/the conductor at profiling moments (scan's improve pass, build-time sweep) — NEVER a dev-typed verb."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# security — the profile (woven, never a command)
|
|
7
|
+
|
|
8
|
+
rafa's security posture is **woven into the loop, not a chore**: the dev never
|
|
9
|
+
types a security command. Owner doctrine (2026-07-26 r2): *"security is not an
|
|
10
|
+
aftermath — it is an integral part of the development cycle."* The engine
|
|
11
|
+
fires at every moment of that cycle:
|
|
12
|
+
|
|
13
|
+
- **plan** — the audit runs before approval and its picture is presented to
|
|
14
|
+
the dev verbatim (rafa-plan §3b): totals + blast-radius criticals; clean is
|
|
15
|
+
said out loud, never implied by silence.
|
|
16
|
+
- **build** — a task that touches the lockfile re-runs the cheap dep tier and
|
|
17
|
+
reports the delta in one line (rafa-build §2).
|
|
18
|
+
- **improve / scan** — the full three-tier profile (this SOP's procedure below).
|
|
19
|
+
- **every merge** — branch→branch merges get a platform-side dep audit at fold
|
|
20
|
+
time; canonical merges get the reconcile graph's security lane. Both mint
|
|
21
|
+
Security-tab rows — freshness at every level, not just prod.
|
|
22
|
+
|
|
23
|
+
Findings land as ordinary contract §3 improvements with `category: security`;
|
|
24
|
+
the platform's Security tab reads the merge-level rows.
|
|
25
|
+
|
|
26
|
+
## The engine — deterministic first, always
|
|
27
|
+
|
|
28
|
+
Run **`npx @rafinery/cli audit --json`** and parse the `rafa.audit/v1`
|
|
29
|
+
envelope. The engine is SELF-CONTAINED — it needs no installs, ever:
|
|
30
|
+
|
|
31
|
+
- **dependency** — built-in pnpm-lock parser + the OSV.dev advisory API,
|
|
32
|
+
merged with `pnpm audit`; per finding: package · GHSA/CVE + aliases ·
|
|
33
|
+
severity + CVSS · direct-vs-transitive chain · fixed-in · dev-only flag.
|
|
34
|
+
- **secrets** — built-in curated ruleset over tracked files (`.env*` never
|
|
35
|
+
opened; fingerprints, never secret bytes). gitleaks enhances if present.
|
|
36
|
+
- **sast** — semgrep if installed (pinned `p/security-audit`), otherwise the
|
|
37
|
+
envelope says `ran:false` with the reason. semgrep/gitleaks are OPTIONAL
|
|
38
|
+
enhancers; mention their value once when relevant (`rafa doctor` shows
|
|
39
|
+
install hints) — installing is always the dev's own consented choice.
|
|
40
|
+
**Never LLM-pretend a tier that did not run** — `tiers.<t>.ran` is the truth.
|
|
41
|
+
|
|
42
|
+
## Findings → improvements (the mechanical part)
|
|
43
|
+
|
|
44
|
+
One §3 improvement file per finding worth a row (group same-package CVEs into
|
|
45
|
+
one row when they share the fix — one lockfile bump = one improvement).
|
|
46
|
+
Required frontmatter as ever (`title` · `summary` · `fix` · `leverage` ·
|
|
47
|
+
`cites`), plus:
|
|
48
|
+
|
|
49
|
+
- `category: security` — always.
|
|
50
|
+
- **Priority maps mechanically, never by vibe**: critical → P0 · high → P1 ·
|
|
51
|
+
moderate → P2 · low or dev-only (`dev:true`) → P3. The LLM may ANNOTATE
|
|
52
|
+
(see below) but **never downgrades** a mapped priority.
|
|
53
|
+
- `fix:` carries the concrete path: the upgrade target (`fixedIn`), whether the
|
|
54
|
+
dep is direct (bump it) or transitive (dedupe/overrides/parent-bump), the
|
|
55
|
+
secret's rotation step. Comprehensive detail (chain, refs, CVSS) rides the
|
|
56
|
+
body — machine-sourced from the envelope, never re-guessed.
|
|
57
|
+
- Dependency-tier rows cite the lockfile/manifest line that pins the package;
|
|
58
|
+
secret/sast rows cite the `file:line` from the finding.
|
|
59
|
+
|
|
60
|
+
**Reconcile like any improvement**: dedupe against existing rows by the stable
|
|
61
|
+
finding id (in the body); auto-close rows whose finding vanished from a fresh
|
|
62
|
+
audit (`status: fixed` — the lockfile bump landed); preserve the dev's triage
|
|
63
|
+
(backlog/wontfix stay).
|
|
64
|
+
|
|
65
|
+
## Brain-ground the reachability (the judgment part)
|
|
66
|
+
|
|
67
|
+
The brain's domain map is what raw scanners lack. For each dependency finding,
|
|
68
|
+
answer from the brain — *is this package on a server-exposed path?* (API
|
|
69
|
+
routes, webhook handlers, auth boundary) — and write the answer into the body
|
|
70
|
+
as an annotation: `Reachability: server-exposed via <domain> — see
|
|
71
|
+
[<note>](/brain/...)` or `Reachability: build-time only`. Cited, observational,
|
|
72
|
+
and **priority-neutral** — it informs the dev's triage, it never overrides the
|
|
73
|
+
mechanical map.
|
|
74
|
+
|
|
75
|
+
The wider observational pass (authz per route, webhook verification, input
|
|
76
|
+
validation against the brain's contracts) belongs to the improve SOP's
|
|
77
|
+
security lens — cited `file:line`, labeled observational, never presented as
|
|
78
|
+
SAST output.
|
|
79
|
+
|
|
80
|
+
## The P0 exception — the one row that travels
|
|
81
|
+
|
|
82
|
+
Improvement nudges are blast-radius-scoped — EXCEPT `category: security` P0s:
|
|
83
|
+
a critical CVE lives in no file the dev is touching, so a P0 security row may
|
|
84
|
+
surface at plan/build boundaries regardless of region. Still one line, still
|
|
85
|
+
dismissible, never blocking, never re-nagged in the same session.
|
|
86
|
+
|
|
87
|
+
## Anti-patterns
|
|
88
|
+
|
|
89
|
+
- Running the engine and PARAPHRASING its output into rows without the
|
|
90
|
+
envelope's fields — the detail is machine-sourced or it doesn't ship.
|
|
91
|
+
- Downgrading a mapped priority because it "seems fine" — annotate, never
|
|
92
|
+
downgrade.
|
|
93
|
+
- A wall of per-CVE rows for one package — group by shared fix.
|
|
94
|
+
- Presenting the observational pass as scanner output.
|
|
95
|
+
- Asking the dev to install semgrep/gitleaks more than once — the doctor
|
|
96
|
+
carries the hint; a decline stands.
|