@rafinery/cli 0.8.16 → 0.11.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 +130 -0
- package/bin/rafa.mjs +11 -0
- package/blueprint/.claude/agents/atlas.md +21 -3
- package/blueprint/.claude/agents/bloom.md +2 -2
- package/blueprint/.claude/agents/prism.md +42 -3
- package/blueprint/.claude/agents/sage.md +1 -1
- package/blueprint/.claude/commands/rafa.md +24 -13
- package/blueprint/.claude/rafa/contract.md +23 -0
- package/blueprint/.claude/rafa/hooks/brain-commit.mjs +4 -0
- package/blueprint/.claude/rafa/hooks/session-start.mjs +66 -0
- package/blueprint/.claude/skills/rafa-build/SKILL.md +111 -20
- 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 +22 -0
- package/blueprint/.claude/skills/rafa-leverage/SKILL.md +6 -1
- package/blueprint/.claude/skills/rafa-plan/SKILL.md +36 -1
- package/blueprint/.claude/skills/rafa-review/SKILL.md +16 -2
- package/blueprint/.claude/skills/rafa-sage/SKILL.md +8 -2
- package/blueprint/.claude/skills/rafa-scan/SKILL.md +4 -1
- package/lib/brain-repo.mjs +1 -1
- package/lib/checkpoint.mjs +26 -15
- package/lib/distill.mjs +56 -3
- package/lib/distiller/doctrine.mjs +5 -16
- package/lib/distiller/schema-ladder.mjs +186 -0
- package/lib/doctor.mjs +19 -1
- package/lib/facts.mjs +130 -0
- package/lib/gate/compile.mjs +12 -0
- package/lib/gate/verify-citations.mjs +78 -1
- package/lib/hydrate.mjs +45 -0
- package/lib/init.mjs +9 -1
- package/lib/leverage/engine.mjs +32 -3
- package/lib/leverage.mjs +11 -2
- package/lib/loop-cache.mjs +67 -0
- package/lib/mcp-client.mjs +19 -0
- package/lib/push.mjs +18 -4
- package/lib/reflex.mjs +5 -1
- package/lib/releases.mjs +78 -0
- package/lib/review.mjs +32 -6
- package/lib/session-facts.mjs +108 -0
- package/lib/skill-deps.mjs +377 -0
- package/lib/stamp.mjs +24 -0
- package/lib/update.mjs +9 -0
- package/package.json +3 -2
- package/skills-bundle/frontend-design/LICENSE.txt +177 -0
- package/skills-bundle/frontend-design/SKILL.md +55 -0
- package/{LICENSE → skills-bundle/grill-me/LICENSE} +6 -6
- package/skills-bundle/grill-me/SKILL.md +7 -0
- package/skills-bundle/grill-me/agents/openai.yaml +5 -0
- package/skills-bundle/grilling/SKILL.md +53 -0
- package/skills-bundle/improve-codebase-architecture/HTML-REPORT.md +123 -0
- package/skills-bundle/improve-codebase-architecture/LICENSE +21 -0
- package/skills-bundle/improve-codebase-architecture/SKILL.md +71 -0
- package/skills-bundle/improve-codebase-architecture/agents/openai.yaml +5 -0
- package/skills-bundle/requesting-code-review/LICENSE +21 -0
- package/skills-bundle/requesting-code-review/SKILL.md +95 -0
- package/skills-bundle/requesting-code-review/code-reviewer.md +172 -0
- package/skills-bundle/skills-manifest.json +72 -0
- package/skills-bundle/tdd/LICENSE +21 -0
- package/skills-bundle/tdd/SKILL.md +36 -0
- package/skills-bundle/tdd/agents/openai.yaml +3 -0
- package/skills-bundle/tdd/mocking.md +59 -0
- package/skills-bundle/tdd/tests.md +77 -0
- package/skills-bundle/vercel-composition-patterns/AGENTS.md +946 -0
- package/skills-bundle/vercel-composition-patterns/README.md +60 -0
- package/skills-bundle/vercel-composition-patterns/SKILL.md +89 -0
- package/skills-bundle/vercel-composition-patterns/metadata.json +11 -0
- package/skills-bundle/vercel-composition-patterns/rules/_sections.md +29 -0
- package/skills-bundle/vercel-composition-patterns/rules/_template.md +24 -0
- package/skills-bundle/vercel-composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
- package/skills-bundle/vercel-composition-patterns/rules/architecture-compound-components.md +112 -0
- package/skills-bundle/vercel-composition-patterns/rules/patterns-children-over-render-props.md +87 -0
- package/skills-bundle/vercel-composition-patterns/rules/patterns-explicit-variants.md +100 -0
- package/skills-bundle/vercel-composition-patterns/rules/react19-no-forwardref.md +42 -0
- package/skills-bundle/vercel-composition-patterns/rules/state-context-interface.md +191 -0
- package/skills-bundle/vercel-composition-patterns/rules/state-decouple-implementation.md +113 -0
- package/skills-bundle/vercel-composition-patterns/rules/state-lift-state.md +125 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,136 @@ 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
|
+
|
|
56
|
+
## 0.10.0 — wave 6: the capability arc (skill dependencies + agent upgrades)
|
|
57
|
+
|
|
58
|
+
rafa's agents get materially better at engineering — and the mechanism is the
|
|
59
|
+
owner's design: rafa **declares** third-party skill dependencies and installs
|
|
60
|
+
them **with your consent**, package-manager style, so the agents adopt YOUR
|
|
61
|
+
toolbox instead of hardcoding one.
|
|
62
|
+
|
|
63
|
+
- **The skill installer.** `rafa update`/`init` offers 7 declared skills (tdd,
|
|
64
|
+
frontend-design, vercel-composition-patterns, requesting-code-review,
|
|
65
|
+
improve-codebase-architecture, grill-me, and rafa's own grilling procedure)
|
|
66
|
+
with one-line reasons; on yes it installs them one at a time into the
|
|
67
|
+
**harness-neutral `.agents/skills/`** (one convention Claude Code, Codex,
|
|
68
|
+
and Cursor all read — Codex manifests ride along), verifies each
|
|
69
|
+
(frontmatter parses · sha256s match the tarball's own manifest · license
|
|
70
|
+
files present), and stamps `rafa.json`. Declining is remembered — re-offer
|
|
71
|
+
with `rafa update --skills`; `--yes` for CI; non-TTY without `--yes` skips
|
|
72
|
+
and stamps nothing. A declined set degrades gracefully, never breaks:
|
|
73
|
+
vendored cards never reference `.agents/` (pinned by test).
|
|
74
|
+
- **TDD by default** (atlas 4.0.0): eligible code tasks (tdd installed + a
|
|
75
|
+
harness detected) build red→green — the Done-check IS a failing test
|
|
76
|
+
authored first at a seam the dev approved at plan time; evidence (red
|
|
77
|
+
exit≠0 before green exit 0) rides the structured return; prism re-runs
|
|
78
|
+
green live and verifies red per validation tier. Refactor defers to review.
|
|
79
|
+
- **The design method**: UI tasks invoke frontend-design (token system,
|
|
80
|
+
signature element, critique-before-code) and consult Vercel's composition
|
|
81
|
+
rules (React-19-gated) — with the brain's design-system notes as the brief.
|
|
82
|
+
- **The grill gate** (prism 0.9.0): plans get a tier-bounded adversarial
|
|
83
|
+
interview before approval — grounding, unstated dependencies, VACUOUS
|
|
84
|
+
Done-checks (tautological tests caught), YAGNI. Devs also get `/grill-me`.
|
|
85
|
+
- **Severity-labeled findings** everywhere prism/review rule: Critical ·
|
|
86
|
+
Important · Minor — Minor never flips a verdict.
|
|
87
|
+
- **bloom's architecture method** (0.9.0): git-log heat scoping, the deletion
|
|
88
|
+
test, Confidence-lined candidates, first-slice-or-backlog — never big-bang.
|
|
89
|
+
- **Toolbox surfaces**: conductor 2.2.0 recalls `.agents/skills` in every
|
|
90
|
+
spawn slice; `rafa leverage --json` carries top-level `agentSkills` +
|
|
91
|
+
`skillDeps`; `rafa doctor` verifies installed skills against the bundle.
|
|
92
|
+
|
|
93
|
+
Adopt with `rafa update` — the skills prompt runs first, then the blueprint
|
|
94
|
+
sync. All licenses confirmed and vendored (MIT ×5, Apache-2.0 frontend-design).
|
|
95
|
+
|
|
96
|
+
## 0.9.0 — wave 5: trust plane + transport economics
|
|
97
|
+
|
|
98
|
+
The research-canvas QA dogfood session (2026-07-25) produced a P0–P3 bottleneck
|
|
99
|
+
backlog; its root causes converged with sage's first two learnings on the same
|
|
100
|
+
seam. This release lands the whole wave:
|
|
101
|
+
|
|
102
|
+
- **Strict loop events, no legacy path.** `report_loop_event` requires the
|
|
103
|
+
actor envelope (`model` · `agent` · `runner ∈ sandbox|ci|session`; mechanical
|
|
104
|
+
CLI emits stamp `model:"mechanical"`) and `verification {method: static|live,
|
|
105
|
+
tool?, evidence?}` on verdict/gate categories — the static-vs-executed
|
|
106
|
+
distinction is structural, so a fabricated "tests passed" can't survive the
|
|
107
|
+
schema. `dedupeKey` makes every emit idempotent; `tier` records the
|
|
108
|
+
validation tier the ruling ran at. Pre-0.9.0 emits are rejected server-side
|
|
109
|
+
(pre-launch: old CLIs discarded). Both sage learnings flipped accepted.
|
|
110
|
+
- **One beat per task boundary.** `patch_plan_item` patches ONE item's fields
|
|
111
|
+
(structure stays `push_plan`-only); `checkpoint_task` lands the item patch +
|
|
112
|
+
the prism-verdict loop event + decision records in ONE transaction,
|
|
113
|
+
idempotent on retry. A task boundary went from ~6 platform calls + a
|
|
114
|
+
full-tree resend to 2 beats.
|
|
115
|
+
- **Self-healing citations.** `verify-citations --fix` rewrites a drifted cite
|
|
116
|
+
when its token still lives at exactly ONE grep site (gone/ambiguous stay
|
|
117
|
+
failing — the checker never guesses), then re-runs clean. `rafa hydrate`
|
|
118
|
+
re-bases served cites against the local checkout on arrival.
|
|
119
|
+
- **`rafa facts` — the session-facts plane.** Bank a verified fact once (claim
|
|
120
|
+
+ the command/exit that proved it + dependsOn paths, sha-anchored); agents
|
|
121
|
+
read first and cite `SF-n unchanged`. Staleness is mechanical (dependsOn ∩
|
|
122
|
+
git diff since the verifying sha, working tree included).
|
|
123
|
+
- **The sage-due bridge.** `rafa checkpoint` caches loop-event shapes locally;
|
|
124
|
+
the SessionStart digest prints "sage due: N" with zero added platform calls,
|
|
125
|
+
and the conductor card makes honoring it a MUST — sage's trigger is
|
|
126
|
+
mechanical instead of discretionary.
|
|
127
|
+
- **`validation_tier` on plan tasks** (light|standard|full): bounds prism's
|
|
128
|
+
re-derivation depth only — the Done-check gate never relaxes.
|
|
129
|
+
- Cards/SOPs re-vendored: prism 0.8.0 (tool-authenticity rule · structured
|
|
130
|
+
return · bounded invariant citation) · atlas 3.9.0 (structured return ·
|
|
131
|
+
facts duty) · sage 0.4.0 (verification/actor/tier analysis dimensions) ·
|
|
132
|
+
conductor 2.1.0 (mechanical sage trigger). Review summary counts dedupe by
|
|
133
|
+
note id.
|
|
134
|
+
|
|
135
|
+
Adopt with `rafa update` (re-vendors hooks, cards, SOPs, contract).
|
|
136
|
+
|
|
7
137
|
## 0.8.16 — the session tail never strands (both planes, one beat)
|
|
8
138
|
|
|
9
139
|
Live-catch (2026-07-24, research-canvas): brain notes authored AFTER the last code
|
package/bin/rafa.mjs
CHANGED
|
@@ -46,6 +46,7 @@ const COMMANDS = [
|
|
|
46
46
|
"hydrate",
|
|
47
47
|
"dirty",
|
|
48
48
|
"reflex",
|
|
49
|
+
"facts",
|
|
49
50
|
"status",
|
|
50
51
|
"doctor",
|
|
51
52
|
"fold",
|
|
@@ -73,6 +74,8 @@ Commands:
|
|
|
73
74
|
Flags (init/update): --overwrite replace changed owned files without asking
|
|
74
75
|
--keep keep all changed owned files without asking
|
|
75
76
|
(default: ask per file; in a non-TTY it keeps them)
|
|
77
|
+
--skills re-offer declared skill dependencies (incl. declined)
|
|
78
|
+
--yes install all skill dependencies unprompted (CI)
|
|
76
79
|
compile Validate the brain against the contract → .rafa/manifest.json.
|
|
77
80
|
manifest The BRANCH manifest (lenient snapshot — WIP files land under
|
|
78
81
|
drafts, never fail). You never need to run this: the post-commit
|
|
@@ -113,6 +116,14 @@ Commands:
|
|
|
113
116
|
detected. List/--json; --consume <id> [verdict] AFTER banking it
|
|
114
117
|
through the gates (or judging it session-only). Corrections are
|
|
115
118
|
the highest-value knowledge signal — they must never evaporate.
|
|
119
|
+
facts The session-facts plane (wave 5.4 — memoized verification): bank a
|
|
120
|
+
VERIFIED fact once (claim + the command/exit that proved it +
|
|
121
|
+
dependsOn paths, sha-anchored); agents read first and cite
|
|
122
|
+
"SF-n unchanged" instead of re-deriving. Staleness is mechanical
|
|
123
|
+
(dependsOn ∩ git diff since the verifying sha) and NOT transitive —
|
|
124
|
+
declare the enclosing directory for subsystem-spanning facts
|
|
125
|
+
(breadth is the conservative move). add · invalidate ·
|
|
126
|
+
prune --stale · --json.
|
|
116
127
|
status Where the loop stands, from local state only: active plan +
|
|
117
128
|
task progress · stale count · corrections · conflicts.
|
|
118
129
|
--line = the one-line ambient form (statuslines/prompts) ·
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: atlas
|
|
3
|
-
version:
|
|
3
|
+
version: 4.0.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: >-
|
|
@@ -16,7 +16,7 @@ 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
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"
|
|
19
|
-
- "build-execution :: .claude/skills/rafa-build/SKILL.md :: implement per recalled knowledge · never hand-edit brain files around the gate · return what changed, cited"
|
|
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"
|
|
22
22
|
---
|
|
@@ -62,6 +62,22 @@ whole-codebase read happens in *your* window, not the conductor's, so the main s
|
|
|
62
62
|
stays lean. You **never spawn** other agents — subagents can't nest, so the conductor owns
|
|
63
63
|
the loop. Return summaries + on-disk artifacts, not the raw reads.
|
|
64
64
|
|
|
65
|
+
**Structured return (wave 5).** A build-execution report ends with the machine
|
|
66
|
+
block the conductor assembles Logs from — never re-paraphrased prose:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{ "filesChanged": ["path", "…"], "commitSha": "…",
|
|
70
|
+
"notes": "one-paragraph what/why",
|
|
71
|
+
"factsDiscovered": ["SF-n banked: <claim>", "…"] }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Session facts (wave 5 — read first, bank once).** Before re-deriving any
|
|
75
|
+
environment/tooling fact, read `.rafa/session-facts.json` (`rafa facts`) and
|
|
76
|
+
cite `SF-<n> unchanged` when it holds. When YOU verify something expensive
|
|
77
|
+
(a harness exists, an install works, an env constraint), bank it once:
|
|
78
|
+
`rafa facts add --claim="…" --command="…" --exit=N [--depends=a,b]` — the next
|
|
79
|
+
spawn inherits it instead of re-learning it.
|
|
80
|
+
|
|
65
81
|
## The brain is your index, once it exists
|
|
66
82
|
Generic at provision-time, repo-aware after the scan: **if a brain exists at
|
|
67
83
|
`.rafa/brain/`, consult it as your index before re-reading code** — route via its cited
|
|
@@ -91,7 +107,9 @@ Never act cold; never over-load.
|
|
|
91
107
|
*name* is a contract; its *value* is a secret. If a note genuinely needs a value, stop and ask
|
|
92
108
|
the dev — don't harvest it. (Enforced in [the scan skill](../skills/rafa-scan/SKILL.md) step 4.)
|
|
93
109
|
- **Toolbox-first execution (automatic — never an offer).** Before implementing any
|
|
94
|
-
task step, CHECK the repo's installed toolbox — committed `.claude/skills/`,
|
|
110
|
+
task step, CHECK the repo's installed toolbox — committed `.claude/skills/`, the
|
|
111
|
+
**harness-neutral `.agents/skills/`** (consent-installed skill dependencies —
|
|
112
|
+
tdd, frontend-design, vercel-composition-patterns are yours to INVOKE),
|
|
95
113
|
`.mcp.json` servers, commands — for a capability that already does it, and INVOKE
|
|
96
114
|
it (Skill tool / MCP) instead of hand-rolling. The conductor passes the matching
|
|
97
115
|
inventory slice in your spawn prompt; consult it first. Only what is actually
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bloom
|
|
3
|
-
version: 0.
|
|
3
|
+
version: 0.9.0
|
|
4
4
|
model: opus # a false flag mutes the whole ledger — best model, never cheap
|
|
5
5
|
groundTruth: code-trend
|
|
6
6
|
description: >-
|
|
@@ -13,7 +13,7 @@ description: >-
|
|
|
13
13
|
tools: Read, Grep, Glob, Bash, Skill, Write, mcp__rafinery
|
|
14
14
|
color: green
|
|
15
15
|
duties:
|
|
16
|
-
- "improve-pass :: .claude/skills/rafa-improve/SKILL.md :: cited · prioritized P0–P3 · leverage-ranked · cite-checked (unresolved dropped) · ledger + debt trend regenerated"
|
|
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
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"
|
|
19
19
|
- "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"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: prism
|
|
3
|
-
version: 0.
|
|
3
|
+
version: 0.9.0
|
|
4
4
|
model: opus # the trust anchor — a hallucinated verdict/finding is the worst failure; best model, never cheap
|
|
5
5
|
groundTruth: code-vs-claim
|
|
6
6
|
description: >-
|
|
@@ -14,8 +14,8 @@ tools: Read, Grep, Glob, Bash, Write, mcp__rafinery
|
|
|
14
14
|
color: orange
|
|
15
15
|
duties:
|
|
16
16
|
- "scan-validation :: .claude/skills/rafa-validate/SKILL.md :: PASS = hard gates pass · score ≥ 85 · 0 blockers · majors ≤ 2 · no unflagged salient-but-wrong exemplar (5b override → auto-ITERATE regardless of score)"
|
|
17
|
-
- "plan-gate :: .claude/skills/rafa-plan/SKILL.md :: PASS = every task grounded in brain + code (none hallucinated) · every child
|
|
18
|
-
- "execution-validation :: .claude/skills/rafa-build/SKILL.md :: done only when the child's Done-check demonstrably holds — run it yourself against the working tree; FAIL returns cited reasons to the producer"
|
|
17
|
+
- "plan-gate :: .claude/skills/rafa-plan/SKILL.md :: PASS = every task grounded in brain + code (none hallucinated) · every child's Done-check present AND non-vacuous (grilled per validation_tier — light = invariants only · standard = bounded probes · full = the whole interview) · TDD-eligible code tasks name their seam in the Done-check · blast radius named from coverage; else REJECT with cited reasons"
|
|
18
|
+
- "execution-validation :: .claude/skills/rafa-build/SKILL.md :: done only when the child's Done-check demonstrably holds — run it yourself against the working tree · TDD tasks: green re-run live, red per tier (static-attested at standard, worktree re-run at full) · findings labeled Critical/Important/Minor — ITERATE iff any Critical or Important, Minor never flips the verdict; FAIL returns cited reasons to the producer"
|
|
19
19
|
- "distillation-validation :: .claude/skills/rafa-distill/SKILL.md :: every working-set file judged against MERGED MAIN (never the fork point) with a confirming/refuting file:line — survivors enter the org brain only through compile; refutations go back to their author, cited"
|
|
20
20
|
- "okf-surface :: .claude/skills/rafa-okf/SKILL.md :: every checker LINKS warn judged (unwritten knowledge vs typo) — never ignored, never auto-failed"
|
|
21
21
|
---
|
|
@@ -37,6 +37,45 @@ brain as a trusted index, whatever you are validating is the thing on trial —
|
|
|
37
37
|
against the code (ground truth) and the stated acceptance criteria. Trust nothing in
|
|
38
38
|
it until you've confirmed it.
|
|
39
39
|
|
|
40
|
+
**Tool authenticity (wave 5 — the npx-placeholder trap).** A tool result is
|
|
41
|
+
evidence ONLY if the tool actually ran: name the binary (path or resolved
|
|
42
|
+
command) and the REAL exit code. `npx <name>` can silently resolve a joke/
|
|
43
|
+
placeholder package and "pass" — a class that already produced one fabricated
|
|
44
|
+
verdict in the field. If you cannot execute the check (no keys, no deps, no
|
|
45
|
+
env), the claim is `method: "static"` — say so in the same breath, never
|
|
46
|
+
smooth it into an unqualified PASS. Fabricating a `live` result is the one
|
|
47
|
+
unforgivable failure: the whole trust model prices from it.
|
|
48
|
+
|
|
49
|
+
**Structured return (wave 5).** Your report ends with the machine block the
|
|
50
|
+
conductor assembles Logs and loop events from — never re-paraphrased prose:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{ "verdict": "PASS|ITERATE",
|
|
54
|
+
"evidence": [{ "claim": "…", "method": "static|live", "tool": "…", "exitCode": 0 }],
|
|
55
|
+
"residualRisk": "what was NOT proven, named — or the explicit empty string" }
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The `evidence` entries feed `report_loop_event.verification` verbatim; the
|
|
59
|
+
static-vs-live split is structural, not prose discipline.
|
|
60
|
+
|
|
61
|
+
**Bounded invariant citation (wave 5 — no-redundant-reverification).** An
|
|
62
|
+
invariant YOU (or a prior prism pass this plan) verified once is citable as
|
|
63
|
+
`SF-<n> unchanged` **iff** `.rafa/session-facts.json` shows its `dependsOn`
|
|
64
|
+
untouched since its verifying sha (the session-start digest surfaces staleness;
|
|
65
|
+
`rafa facts` lists it). Re-deriving an unchanged, evidence-backed fact is waste,
|
|
66
|
+
not rigor. The bound is hard: anything NOT in the facts file — and everything
|
|
67
|
+
about the artifact under test itself — stays trust-nothing. **Invalidation is
|
|
68
|
+
NOT transitive** (dependsOn is intersected with the diff, imports are never
|
|
69
|
+
walked — pinned by test): trust a fact only as far as its declared breadth, and
|
|
70
|
+
when a fact you rely on spans a subsystem whose dependsOn names single files,
|
|
71
|
+
treat it as under-declared — re-verify instead of citing it.
|
|
72
|
+
|
|
73
|
+
**Validation tier (wave 5).** A task's `validation_tier` (plan §7) bounds your
|
|
74
|
+
RE-DERIVATION DEPTH — how much surrounding context you re-read and re-prove:
|
|
75
|
+
light = the Done-check itself + direct evidence · standard = + the touched
|
|
76
|
+
files' immediate seams · full = unbounded re-derivation. The Done-check gate
|
|
77
|
+
NEVER relaxes at any tier, and your emitted loop event carries the tier it ran at.
|
|
78
|
+
|
|
40
79
|
## Duties (each duty's bar is in the frontmatter; the SOP carries the procedure)
|
|
41
80
|
1. **Scan validation** — judge the brain in `.rafa/brain/` against the repo per
|
|
42
81
|
[the validate skill](../skills/rafa-validate/SKILL.md). Verdict + score + severity-
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
version: 2.0
|
|
2
|
+
version: 2.2.0
|
|
3
3
|
description: rafa — the repo's engineering SOP. Use whenever the dev wants to plan a feature or change, build/execute against the active plan, improve code health, or ground work in the repo's brain — intent counts, the dev does NOT need to type /rafa. Also explicit: /rafa <init|scan|improve|plan|build|push|leverage|migrate|update|help> [--brain-only]. Admin verbs (init/scan/push/migrate/update) run ONLY when explicitly invoked.
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -59,10 +59,15 @@ MCP tools, checkpoints, pushes, decisions logging — is AGENT-INTERNAL machiner
|
|
|
59
59
|
dev speaks intent; YOU run the machinery. Never instruct the dev to run a command you
|
|
60
60
|
can run yourself. The only human acts: init (provision) · `npx rafa pull` (once per
|
|
61
61
|
clone) · ci-setup approval · npm publish. **Toolbox is a recall surface:** at bootstrap,
|
|
62
|
-
load the committed toolbox
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
load the committed toolbox — `.claude/skills/` (this harness) **and
|
|
63
|
+
`.agents/skills/` (the HARNESS-NEUTRAL third-party skills — one convention
|
|
64
|
+
Claude Code · Codex · Cursor all read; installed by `rafa update` with
|
|
65
|
+
consent, wave 6)** — plus `.mcp.json` and commands, alongside brain status
|
|
66
|
+
(`rafa leverage --json` is the deterministic read); pass the matching slice
|
|
67
|
+
into every atlas/bloom spawn prompt — agents USE the fit capability instead of
|
|
68
|
+
hand-rolling (only what's installed, never guessed; a DECLINED skill dep means
|
|
69
|
+
the SOP's fallback path, never a nag; personal `~/.claude/` stays
|
|
70
|
+
live-recommend-only). **Actor envelope:** stamp `actorMeta {model,
|
|
66
71
|
agent, runner: "session"}` on every state-plane write (checkpoints, plan pushes,
|
|
67
72
|
decisions, reports) and export `RAFA_ACTOR_MODEL` before CLI calls — the platform records
|
|
68
73
|
WHO/WHAT executed; "unreported" when unknown, never guessed.
|
|
@@ -240,14 +245,20 @@ explicitly typed; an ACCEPTED boundary offer counts as the explicit invocation.
|
|
|
240
245
|
|
|
241
246
|
## sage — the silent L5 observer (runs IMPLICITLY, zero-command; owner 2026-07-13)
|
|
242
247
|
|
|
243
|
-
Devs never type `/rafa sage`. **Trigger
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
248
|
+
Devs never type `/rafa sage`. **Trigger — MECHANICAL as of wave 5 (owner
|
|
249
|
+
2026-07-25):** the SessionStart digest computes it — a `[rafa · sage] sage due:
|
|
250
|
+
N loop events…` line (the checkpoint-written loop-event cache vs the learnings
|
|
251
|
+
ledger, compared locally). **When that line is present, spawning sage at the
|
|
252
|
+
next completion boundary — build final-verify · distill close · bootstrap — is
|
|
253
|
+
a MUST, not a judgment call**: the line IS the trigger condition already
|
|
254
|
+
evaluated; a discretionary trigger is how sage never fired organically. Spawn
|
|
255
|
+
per [rafa-sage](../skills/rafa-sage/SKILL.md); announce ONE line, proceed; its
|
|
256
|
+
proposals ride the NEXT bootstrap digest. No digest line = not due (skip
|
|
257
|
+
silently). Writing proposals is the just-do rung; the consent moment is
|
|
258
|
+
ACCEPTING one (accepted = a versioned, MR-reviewed card/SOP edit — proposals
|
|
259
|
+
never self-apply). `/rafa sage` is the explicit override. Full mechanics
|
|
260
|
+
(≥10-event threshold, `get_loop_events` shape read, scrub step, ledger schema,
|
|
261
|
+
the person-free/asset-free creed) live in the skill.
|
|
251
262
|
|
|
252
263
|
## migrate · update — brain-side schema migration (no skill; the intelligence-only half)
|
|
253
264
|
|
|
@@ -382,6 +382,7 @@ blocked_by: [payments-c2] # optional · item ids this waits on — a dependency
|
|
|
382
382
|
blocked_reason: "vendor sandbox access" # optional · external blocks (no dependency id to point at)
|
|
383
383
|
priority: 2 # optional · 0 none · 1 urgent · 2 high · 3 medium · 4 low (Linear scale)
|
|
384
384
|
estimate: 3 # optional · points (Linear estimate / Jira story points)
|
|
385
|
+
validation_tier: standard # optional · light|standard|full — bounds prism's re-derivation DEPTH only (wave 5); the Done-check gate itself never relaxes. Planner assigns from blast radius: contract/state/graph surface → full · types/docs/leaf-UI → light · default standard
|
|
385
386
|
branch: feat/webhooks # optional · ↔ Linear branchName
|
|
386
387
|
baseSha: abc123 # optional · commit it was cut from
|
|
387
388
|
domains: [payments] # optional · EPIC only · the blast radius — the brain link
|
|
@@ -454,6 +455,23 @@ imported comments are never scraped into decisions.
|
|
|
454
455
|
fields do NOT bump it** — e.g. the note size stamps (`bodyTokens`,
|
|
455
456
|
`cites[].targetTokens`, §1): ingest tolerates their absence, so a legacy manifest
|
|
456
457
|
without them stays valid at the same `schemaVersion`.
|
|
458
|
+
- **The reconciliation schema ladder (0.11.0 — owner's 4-case doctrine).** When a
|
|
459
|
+
version bump DOES ship, distillation is the upgrade moment — the reconciler
|
|
460
|
+
resolves target-vs-source-vs-runner before judging: target below source → full
|
|
461
|
+
target rewrite onto the newer schema; source below target → incoming candidates
|
|
462
|
+
lift before judging; both equal-but-old → the merged target rewrites onto the
|
|
463
|
+
runner's latest; both current → plain diff (today). Either side newer than the
|
|
464
|
+
runner → **abort loudly** (update the runner; knowledge is never downgraded).
|
|
465
|
+
Transforms are registered per step AND per OKF type in the CLI
|
|
466
|
+
(`lib/distiller/schema-ladder.mjs`): each step declares rule · playbook · improvement
|
|
467
|
+
explicitly — a function, or the EXPLICIT `"unchanged"` (still re-stamps the note's
|
|
468
|
+
`schemaVersion:`); an unregistered step or class fails loudly — the ladder never
|
|
469
|
+
guesses a schema. Class resolves by CHAIN: the governed directory first (inside the
|
|
470
|
+
transport the path IS identity — the CAS row key), then the portable filename suffix
|
|
471
|
+
(`.rule.md` · `.playbook.md` · `.improvement.md`) for files travelling outside the
|
|
472
|
+
canonical tree; a contradiction between the two is a loud error. Only durable
|
|
473
|
+
knowledge migrates; derived/generated files
|
|
474
|
+
(coverage · checklist · ledger · reports · the manifest) regenerate at the new schema.
|
|
457
475
|
- **Validate-and-correct:** `rafa compile` validates every file. On failure it emits
|
|
458
476
|
a structured error — `path · field · rule` — to the **authoring agent** (atlas for
|
|
459
477
|
notes, bloom for improvements/ledger, prism for checklist). The agent edits the
|
|
@@ -573,12 +591,17 @@ state**, marked by `envelope.plane: "state"`:
|
|
|
573
591
|
| `resolve_working_file` | branch working set | `distilled` / `refuted` (+ cited note) at merge-to-main distillation; `keep-current` for adjudication decisions; CAS on status — a racing distill fails loudly |
|
|
574
592
|
| `fold_working_set` | branch working set | branch→parent-branch MECHANICAL fold (no LLM, no prism — rigor only at main): absent → re-keyed · identical → merged · divergent → `needs-adjudication` on the parent row |
|
|
575
593
|
| `push_plan` / `list_plans` / `update_plan_status` / `set_active_plan` / `log_decision` | **plans** — (repo) work objects | the push-on-approval channel (§7 v2): approval pushes the whole work-item TREE (items[], bodies stored); `list_plans` = names only; statuses push back (5-value enum — blocked is derived); `log_decision` records the deliberation trail (paraphrase + pivotal quotes); the active pointer is explicit, never inferred |
|
|
594
|
+
| `patch_plan_item` | plans (one item) | wave 5.2 — field-level patch on ONE item (no full-tree resend): provided fields replace, absent stay; CLEARING a field and any STRUCTURE change (kind/parent/add/remove/domains/external/merged) remain `push_plan`-only, so "a vanished optional field must not survive" keeps holding at tree granularity; snapshot-before-change rides noteRevisions like a re-push |
|
|
595
|
+
| `checkpoint_task` | plans + loopEvents + planDecisions (**ONE transaction**) | wave 5.2 — the ONE-beat boundary write: optional item patch + the loop-event ruling + decision records land atomically (all-or-nothing; `mcp.call` is an action, so composing the separate tools can never be atomic — this is one internalMutation). Idempotent end-to-end (patch no-ops on same values · loop event dedupes on `dedupeKey` · decisions dedupe on client-stable ids). The embedded loopEvent obeys `report_loop_event`'s exact rules — one rulebook, no side door. `checkpoint_sync` stays separate: per-file CAS partial-accept is a different failure model than an atomic beat |
|
|
576
596
|
| `report_improvement_status` | **events only** — no store | a LIVE session signal (bloom's fixed-in-passing during build). The improvement ledger row is untouched — it has ONE writer, the ingest (K1); the platform overlays the report as pending-reconciliation until the next brain push confirms it |
|
|
577
597
|
| `reconcile_claim` | **reconciliations queue** — (repo) run rows | executor claim (`plane:"state"`): ACID no-running-sibling assert → returns the attempt token; delegates to `reconciliations.claim`; stamps the actor envelope `{model, agent, runner}` (runner ∈ `sandbox`\|`ci`\|`session`, enum-checked at the boundary) on the row |
|
|
578
598
|
| `reconcile_heartbeat` | reconciliations queue | extends the wall-clock lease + sets the phase; **attempt-fenced** (a non-current attempt is rejected, nothing written); actor envelope re-stamped |
|
|
579
599
|
| `reconcile_log_append` | **reconciliationLogs** — the run log tail | batched chunks, **secret-screened PER LINE** (the same `looksLikeSecret` screen — a credential chunk is rejected by chunk/line index, nothing stored or echoed) + **attempt-fenced**; `seq`-ordered; UNLOGGED (emits its own `reconcile.log` event, counts only) |
|
|
580
600
|
| `reconcile_report` | reconciliations queue (+ knowledge node on success) | terminal outcome + node delta + meter; **attempt-fenced**; success COMPOSES the pointer advance atomically (insert node + move pointer, one mutation); refutation/deletion ride the success outcomes; actor envelope stamped |
|
|
581
601
|
| `list_working_sets` | branch working set (**READ**) | enumerates branches with LIVE candidate rows + counts only (no bodies) — closes the 07-14 sensor gap (`get_working_set` needs a branch arg; nothing listed them); feeds the SessionStart digest pending line |
|
|
602
|
+
| `report_loop_event` | **loopEvents** — the loop-outcome ledger (sage's evidence) | ONE structured outcome per ruling, shapes only (enum category + per-category enum outcome + `subject` shape ref, secret-screened). Wave 5 trust plane, STRICT (no legacy path): **required actor envelope** `{model, agent, runner ∈ sandbox\|ci\|session}` (mechanical CLI emits use `model:"mechanical"`); **required `verification {method: static\|live, tool?, evidence?}`** on `prism-verdict`/`gate-result`/`review-verdict` — the static-vs-executed distinction is structural, never prose; optional `dedupeKey` (≤120) makes the emit **idempotent** (same `(repo, key)` never lands twice — response says `deduped`) and `tier ∈ light\|standard\|full` records the §7 `validation_tier` the ruling ran at |
|
|
603
|
+
| `get_loop_events` | loopEvents (**READ**) | newest-first shape read (optional category filter, limit ≤500): category/outcome/subject + actorMeta/verification/dedupeKey/tier + at — no bodies, no code; sage splits miss patterns by verification method, actor, and tier |
|
|
604
|
+
| `report_learning` | **agentLearnings** — sage's summary-row mirror | sage ONLY (wave 4.1): mirrors the SUMMARY ROW of one committed ledger entry (`.claude/rafa/learnings/<id>.md` stays the single truth, MR-gated, never self-applied). Asset-free ENFORCED server-side: enum status/leverage/categories, `.claude/`-only diff target, length caps, code-fence + secret screens; upsert by id |
|
|
582
605
|
|
|
583
606
|
State tools work with or without an ingested brain (a working set can exist —
|
|
584
607
|
and a plan can be pushed — before the first scan) and are exempt from the
|
|
@@ -181,6 +181,10 @@ try {
|
|
|
181
181
|
// rafa review's scored-ranges artifact (wave 2.3) — regenerated per
|
|
182
182
|
// review, machine state like distill-verdicts; never brain knowledge.
|
|
183
183
|
"review.json",
|
|
184
|
+
// wave 5: session-scoped machine state — memoized verification + the
|
|
185
|
+
// checkpoint-written loop-event cache the sage-due digest reads.
|
|
186
|
+
"session-facts.json",
|
|
187
|
+
"loop-events-tail.json",
|
|
184
188
|
];
|
|
185
189
|
const gi = join(rafa, ".gitignore");
|
|
186
190
|
const cur = existsSync(gi) ? readFileSync(gi, "utf8") : "";
|
|
@@ -300,6 +300,72 @@ try {
|
|
|
300
300
|
}
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
+
// Session facts (wave 5.4 — memoized verification): banked verified facts +
|
|
304
|
+
// mechanical staleness (dependsOn ∩ git diff since the verifying sha, working
|
|
305
|
+
// tree included). Spawned agents read the file FIRST and cite "SF-n unchanged"
|
|
306
|
+
// instead of re-deriving. Local reads only — no platform call.
|
|
307
|
+
{
|
|
308
|
+
const doc = readJson(join(rafaDir, "session-facts.json"));
|
|
309
|
+
if (doc?.schemaVersion === 1 && Array.isArray(doc.facts) && doc.facts.length) {
|
|
310
|
+
let stale = 0;
|
|
311
|
+
for (const f of doc.facts) {
|
|
312
|
+
try {
|
|
313
|
+
const changed = execSync(`git diff --name-only ${f.verifiedAtSha}`, {
|
|
314
|
+
cwd: root,
|
|
315
|
+
encoding: "utf8",
|
|
316
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
317
|
+
})
|
|
318
|
+
.split("\n")
|
|
319
|
+
.filter(Boolean);
|
|
320
|
+
if (
|
|
321
|
+
(f.dependsOn ?? []).some((p) =>
|
|
322
|
+
changed.some((c) => c === p || c.startsWith(p.endsWith("/") ? p : p + "/")),
|
|
323
|
+
)
|
|
324
|
+
)
|
|
325
|
+
stale++;
|
|
326
|
+
} catch {
|
|
327
|
+
stale++; // unknown sha — fail-honest, count it stale
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
lines.push(
|
|
331
|
+
`[rafa · facts] ${doc.facts.length} session fact(s) banked (.rafa/session-facts.json — spawned agents read it FIRST and cite "SF-n unchanged" instead of re-deriving)` +
|
|
332
|
+
(stale ? ` · ${stale} STALE — re-verify or \`rafa facts prune --stale\`` : ""),
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Sage-due bridge (wave 5.5 — mechanical detection): the checkpoint-written
|
|
338
|
+
// loop-event cache vs the learnings ledger, compared LOCALLY (zero platform
|
|
339
|
+
// calls). Sage's trigger was a discretionary end-of-session SOP step and
|
|
340
|
+
// never fired organically — detection now lands front-of-session where
|
|
341
|
+
// reminders get obeyed; only the SPAWN stays with the conductor.
|
|
342
|
+
{
|
|
343
|
+
const cache = readJson(join(rafaDir, "loop-events-tail.json"));
|
|
344
|
+
if (cache?.schemaVersion === 1 && Array.isArray(cache.events)) {
|
|
345
|
+
let ledgerAt = null;
|
|
346
|
+
const ledgerPath = join(root, ".claude", "rafa", "learnings", "ledger.md");
|
|
347
|
+
if (existsSync(ledgerPath)) {
|
|
348
|
+
const m = readFileSync(ledgerPath, "utf8").match(
|
|
349
|
+
/^-\s*Generated:\s*([0-9]{4}-[0-9]{2}-[0-9]{2}(?:[T ][0-9:.Z+-]+)?)/m,
|
|
350
|
+
);
|
|
351
|
+
if (m) {
|
|
352
|
+
const t = Date.parse(m[1]);
|
|
353
|
+
if (Number.isFinite(t)) ledgerAt = t;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
const fresh =
|
|
357
|
+
ledgerAt == null
|
|
358
|
+
? cache.events
|
|
359
|
+
: cache.events.filter((e) => Number.isFinite(e.at) && e.at > ledgerAt);
|
|
360
|
+
if (fresh.length >= 10)
|
|
361
|
+
lines.push(
|
|
362
|
+
`[rafa · sage] sage due: ${fresh.length} loop events since the last learnings pass` +
|
|
363
|
+
(ledgerAt == null ? " (no ledger yet — sage has never run here)" : "") +
|
|
364
|
+
` — spawn sage at the next completion boundary (zero-command; this line is the trigger, not a suggestion).`,
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
303
369
|
// Benchmark liveness (harness-arc: the proof engine is workflow-woven, never a
|
|
304
370
|
// dev-typed command) — a scanned brain with no MEASURED benchmark is a gap the
|
|
305
371
|
// scan SOP's Prove-it step closes. Absence sensor only; never a nag mid-flow.
|