@rafinery/cli 0.8.15 → 0.8.16

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 CHANGED
@@ -4,6 +4,29 @@ 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.8.16 — the session tail never strands (both planes, one beat)
8
+
9
+ Live-catch (2026-07-24, research-canvas): brain notes authored AFTER the last code
10
+ commit sat uncommitted in `.rafa` while `rafa checkpoint` reported clean — the
11
+ capture plane (platform working set) was synced, the git plane (brain mirror
12
+ branch) was dirty. The hooks only fire on code commit/push, so a session tail
13
+ (verify flips · late-authored notes · regenerated manifest) had nothing to ride.
14
+
15
+ - `rafa checkpoint` now owns BOTH planes: after the working-set sync (including
16
+ the "clean" path) it fires the vendored `brain-commit.mjs` worker whenever the
17
+ brain tree is dirty — the tail commits and pushes at the same beat that
18
+ creates it, and "clean" finally means capture AND mirror.
19
+ - The worker is tail-aware: when HEAD already has its 1-1 mirror, the extra run
20
+ commits with a distinct `brain(<branch>): session tail · N file(s)` subject on
21
+ the SAME `code-commit` trailer (join intact, log legible) — and an empty tail
22
+ is a no-op, never an `--allow-empty` duplicate.
23
+ - `review.json` (the review gate's scored-ranges artifact) joins the local-state
24
+ exclusion list — machine state like `distill-verdicts.json`, never knowledge.
25
+ - Fixed: the `RELEASES` ledger tail was out of ascending order (0.8.13/0.8.14
26
+ after 0.8.15), so `CURRENT` reported 0.8.13 from a 0.8.15 build.
27
+
28
+ Adopt with `rafa update` (re-vendors the hook worker).
29
+
7
30
  ## 0.8.2 — MCP scope: derived from the key, never guessed
8
31
 
9
32
  First real client MCP call surfaced it: agents GUESSED the `repo` arg (folder name)
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: sage
3
- version: 0.2.1
3
+ version: 0.3.0
4
4
  model: opus # a wrong learning re-shapes an agent for every repo — best model, never cheap
5
5
  groundTruth: sessions-over-time
6
6
  description: >-
@@ -19,6 +19,7 @@ duties:
19
19
  - "scrub :: .claude/skills/rafa-sage/SKILL.md :: every entry passes the SCRUB STEP before write — anything asset-shaped (code content, snippets, repo-specific facts, repo-identifying detail) abstracted to the pattern or DROPPED; the ledger entry schema has NO code-content-capable field"
20
20
  - "route-person-shaped :: .claude/skills/rafa-sage/SKILL.md :: a person-shaped observation is NEVER a learning — it routes to compass's consent path (rafa-insights, user brain), never sage's ledger"
21
21
  - "propose-only :: .claude/skills/rafa-sage/SKILL.md :: output is PROPOSED diffs to agent cards/SOPs — applying a change is a separate human/MR-reviewed act; sage never self-applies and never edits an agent card or SOP"
22
+ - "mirror-summary :: .claude/skills/rafa-sage/SKILL.md :: after scrub + file write, each entry's SUMMARY row is mirrored via report_learning for the platform card — a projection, never a second truth; the committed .md stays the ledger"
22
23
  - "okf-surface :: .claude/skills/rafa-okf/SKILL.md :: learnings pass the compile learning gate (id · type · title · description) — the same protocol outside the bundle"
23
24
  ---
24
25
 
@@ -128,19 +128,42 @@ try {
128
128
  .split("\n")
129
129
  .filter(Boolean)
130
130
  .slice(0, 100);
131
+
132
+ // TAIL RUN detection (0.8.16, live-catch 2026-07-24): if HEAD already has its
133
+ // 1-1 mirror commit (its code-commit trailer is in the brain log), THIS
134
+ // invocation carries the SESSION TAIL — brain deltas written AFTER the last
135
+ // code commit (verify flips · late-authored notes · regenerated manifest)
136
+ // that would otherwise strand uncommitted until the next code commit. The
137
+ // checkpoint beat fires this worker for exactly that case. A tail commit is
138
+ // additive provenance on the SAME join key (trailer unchanged); its subject
139
+ // is distinct so the log never shows two look-alike mirrors, and an empty
140
+ // tail is a NO-OP — never an --allow-empty duplicate.
141
+ let isTail = false;
142
+ try {
143
+ isTail = shR(`git log --grep "code-commit: ${fullSha}" --format=%H -n 1`) !== "";
144
+ } catch {
145
+ /* fresh mirror / unborn HEAD — normal 1-1 path */
146
+ }
147
+
131
148
  mkdirSync(join(rafa, "intent"), { recursive: true });
132
- writeFileSync(
133
- join(rafa, "intent", `${short}.md`),
134
- `---\n` +
135
- `type: IntentRecord\n` +
136
- `description: "per-commit intent trail (capture-engine P2) — provenance, consumed at merge, never org-brain truth"\n` +
137
- `code-commit: ${fullSha}\n` +
138
- `code-branch: ${branch}\n` +
139
- `timestamp: ${new Date().toISOString()}\n` +
140
- `---\n\n# ${subject}\n\n## Files\n` +
141
- files.map((f) => `- ${f}`).join("\n") +
142
- `\n`,
143
- );
149
+ // A tail run never rewrites an existing intent record — the 1-1 mirror wrote
150
+ // it, and a fresh `timestamp:` would make every tail beat a phantom delta
151
+ // (the no-op contract would never hold).
152
+ const intentPath = join(rafa, "intent", `${short}.md`);
153
+ if (!isTail || !existsSync(intentPath)) {
154
+ writeFileSync(
155
+ intentPath,
156
+ `---\n` +
157
+ `type: IntentRecord\n` +
158
+ `description: "per-commit intent trail (capture-engine P2) provenance, consumed at merge, never org-brain truth"\n` +
159
+ `code-commit: ${fullSha}\n` +
160
+ `code-branch: ${branch}\n` +
161
+ `timestamp: ${new Date().toISOString()}\n` +
162
+ `---\n\n# ${subject}\n\n## Files\n` +
163
+ files.map((f) => `- ${f}`).join("\n") +
164
+ `\n`,
165
+ );
166
+ }
144
167
 
145
168
  // Local-state exclusion (owner 2026-07-24): the hydration sidecar + sensor
146
169
  // queues are MACHINE state, never knowledge — ensure the ignore entries and
@@ -155,6 +178,9 @@ try {
155
178
  "sensor-errors.jsonl",
156
179
  "distill-verdicts.json",
157
180
  "benchmark.demo.json",
181
+ // rafa review's scored-ranges artifact (wave 2.3) — regenerated per
182
+ // review, machine state like distill-verdicts; never brain knowledge.
183
+ "review.json",
158
184
  ];
159
185
  const gi = join(rafa, ".gitignore");
160
186
  const cur = existsSync(gi) ? readFileSync(gi, "utf8") : "";
@@ -171,10 +197,26 @@ try {
171
197
 
172
198
  shR("git add -A");
173
199
  disposeHydrations(branch);
174
- shR(
175
- `git commit --allow-empty -q -m "brain(${branch}): ${subject}" ` +
176
- `-m "code-commit: ${fullSha}" -m "code-branch: ${branch}"`,
177
- );
200
+ if (isTail) {
201
+ // Session tail: commit only when something REAL is staged (disposal may
202
+ // have unstaged everything). The 1-1 join stays mechanical — same trailer.
203
+ let staged = [];
204
+ try {
205
+ staged = shR("git diff --cached --name-only").split("\n").filter(Boolean);
206
+ } catch {
207
+ /* nothing staged */
208
+ }
209
+ if (staged.length > 0)
210
+ shR(
211
+ `git commit -q -m "brain(${branch}): session tail · ${staged.length} file(s)" ` +
212
+ `-m "code-commit: ${fullSha}" -m "code-branch: ${branch}"`,
213
+ );
214
+ } else {
215
+ shR(
216
+ `git commit --allow-empty -q -m "brain(${branch}): ${subject}" ` +
217
+ `-m "code-commit: ${fullSha}" -m "code-branch: ${branch}"`,
218
+ );
219
+ }
178
220
  // Keep the REMOTE mirror branch current (owner 2026-07-23: the branch is visible
179
221
  // in the brain repo) — best-effort, bounded; a failed push retries on the next
180
222
  // commit. Never the trunk (single writer = the reconciler).
@@ -101,7 +101,9 @@ human.
101
101
  The ledger is a **committed, human-reviewed governance artifact** — diffs for MR review. It is
102
102
  **NOT** a Convex table and **NOT** inside any customer `.rafa/brain/` (asset-free: learnings are
103
103
  about OUR agents; they never mix with customer knowledge). It lives beside the contract at
104
- `.claude/rafa/learnings/` (governance, versioned with the blueprint, MR-reviewed):
104
+ `.claude/rafa/learnings/` (governance, versioned with the blueprint, MR-reviewed). The platform's
105
+ "agent learnings" card renders a **projection** of it (summary rows via `report_learning`, wave
106
+ 4.1, owner-ratified 2026-07-24) — a display overlay, never a second truth and never the store:
105
107
 
106
108
  - `learnings/<id>.md` — one file per learning (one proposed card/SOP diff, cited to event shapes).
107
109
  - `ledger.md` — generated index: counts by category / target / status, and the top-leverage few.
@@ -169,7 +171,16 @@ enforced by sage and by MR review.
169
171
  7. **Ledger + leverage.** Regenerate `ledger.md`: counts by category / target / status, and the
170
172
  **top-leverage few** (impact × ease) — the single card/SOP change that would cover the widest
171
173
  class of misses, first.
172
- 8. **Present, don't nag, don't apply.** Surface the top few high-leverage learnings succinctly as
174
+ 8. **Mirror the summary rows (wave 4.1 the platform "agent learnings" card).** For each entry
175
+ written or status-changed in step 6, call `report_learning` with the entry's SUMMARY fields
176
+ (`id · pattern · categories · evidence_shape · proposed_diff_target · proposed_change ·
177
+ status · leverage`) — AFTER the scrub step and the file write, never before. This is a
178
+ **projection, not a second truth** (owner 2026-07-24): the committed `.md` stays the single
179
+ truth; the rows only render the Activity card. Upsert by id — re-runs refresh `status`,
180
+ never duplicate. The server re-screens every field (enum checks, `.claude/`-only target,
181
+ length caps, code-fence/secret rejection) — a rejection means the entry failed the asset-free
182
+ gate: fix the ENTRY, don't re-word past the screen.
183
+ 9. **Present, don't nag, don't apply.** Surface the top few high-leverage learnings succinctly as
173
184
  PROPOSALS. sage never applies a diff; a human reviews the ledger, and any accepted change lands
174
185
  as a versioned, MR-reviewed card/SOP edit (bump `version:`, record the why). Silent otherwise.
175
186
 
@@ -27,6 +27,62 @@ const die = (m) => {
27
27
  process.exit(1);
28
28
  };
29
29
 
30
+ // The GIT-PLANE tail beat (0.8.16, live-catch 2026-07-24): brain deltas written
31
+ // AFTER the last code commit (verify flips · late-authored notes · regenerated
32
+ // manifest) have no post-commit mirror to ride, and the pre-push ceremony may
33
+ // already have run — they strand uncommitted until the next code commit. The
34
+ // checkpoint beat is the boundary that CREATES that tail, so it fires the SAME
35
+ // vendored worker the git hooks run (single implementation, tail-aware since
36
+ // 0.8.16) whenever the brain tree is dirty. One beat, both planes: "clean"
37
+ // from this command means capture AND mirror. Best-effort — a mirror problem
38
+ // never fails a checkpoint.
39
+ function mirrorTail(ROOT, branch) {
40
+ const rafa = join(ROOT, ".rafa");
41
+ const worker = join(ROOT, ".claude", "rafa", "hooks", "brain-commit.mjs");
42
+ if (!existsSync(join(rafa, ".git")) || !existsSync(worker)) return;
43
+ const shR = (cmd) =>
44
+ execSync(cmd, { cwd: rafa, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
45
+ let dirty = "";
46
+ try {
47
+ dirty = shR("git status --porcelain");
48
+ } catch {
49
+ return; // unreadable brain repo — the hooks' own paths will surface it
50
+ }
51
+ if (dirty === "") return; // git plane already clean — nothing stranded
52
+ let before = "";
53
+ try {
54
+ before = shR("git rev-parse HEAD");
55
+ } catch {
56
+ /* unborn HEAD — the worker handles it */
57
+ }
58
+ try {
59
+ execSync(`node "${worker}"`, { cwd: ROOT, stdio: ["ignore", "ignore", "ignore"], timeout: 60000 });
60
+ } catch {
61
+ /* worker is silent + non-blocking by design; fall through to the report */
62
+ }
63
+ try {
64
+ const after = shR("git rev-parse HEAD");
65
+ if (after !== before) {
66
+ let pushed = false;
67
+ try {
68
+ pushed = shR(`git rev-parse "origin/${branch}"`) === after;
69
+ } catch {
70
+ /* no remote tracking yet */
71
+ }
72
+ console.log(
73
+ `✓ brain mirror: session tail committed (${after.slice(0, 12)})` +
74
+ (pushed ? " + pushed" : " — push rides the next pre-push ceremony"),
75
+ );
76
+ } else {
77
+ console.log(
78
+ "• brain tree dirt is disposable hydration cache — nothing real to mirror",
79
+ );
80
+ }
81
+ } catch {
82
+ /* report is best-effort */
83
+ }
84
+ }
85
+
30
86
  export default async function checkpoint() {
31
87
  const ROOT = process.cwd();
32
88
 
@@ -101,6 +157,9 @@ export default async function checkpoint() {
101
157
 
102
158
  if (candidates.length === 0) {
103
159
  console.log(`✓ working set clean on ${branch} — nothing to checkpoint`);
160
+ // A clean CAPTURE plane can still hide a dirty GIT plane (the live catch:
161
+ // "checkpoint said clean" while the session tail sat uncommitted).
162
+ mirrorTail(ROOT, branch);
104
163
  // Knowledge-absence nudge (live-catch 2026-07-17: a session can do real
105
164
  // work and bank ZERO knowledge, silently — no sensor fires on absence).
106
165
  // Deterministic signal only: code edits recorded, no brain delta on this
@@ -184,6 +243,11 @@ export default async function checkpoint() {
184
243
  (conflicts ? ` · ${conflicts} conflict(s) need YOUR decision (see above)` : ""),
185
244
  );
186
245
 
246
+ // Both planes, one beat: the capture sync above, the brain mirror here.
247
+ // (Runs before the conflict exit — a contested working set is still worth a
248
+ // durable mirror of the dev's current copies; .theirs.md files are ignored.)
249
+ mirrorTail(ROOT, branch);
250
+
187
251
  // prism-verdict backstop (harness-arc wave 0): gate-result/reflex-outcome are
188
252
  // emitted mechanically by the CLI, but prism verdicts are LLM judgments only
189
253
  // the session can report. The checkpoint beat — the SOP's own emit moment —
package/lib/releases.mjs CHANGED
@@ -265,23 +265,18 @@ export const RELEASES = [
265
265
  "`rafa update` re-vendors the post-checkout hook.",
266
266
  },
267
267
  {
268
- version: "0.8.15",
268
+ version: "0.8.13",
269
269
  contract: 1,
270
270
  plans: 2,
271
271
  requires: "update",
272
272
  summary:
273
- "THE REVIEW GATE + ZERO-LEAK MIRRORS. `rafa review`: deterministic brain-" +
274
- "grounded review pre-pass diff's changed lines the cite graph rules AND " +
275
- "playbooks + open improvements + stale-cite risk + open gaps, each note " +
276
- "relevance-scored (OKF type-aware: contract class weighs heavier) into " +
277
- "deep/triage/skip engage tiers so the judge's tokens scale with the DIFF, " +
278
- "never the brain (rafa-review SOP: local-first + frontmatter-first reads, " +
279
- "10-note deep cap, skips listed never judged). LOCAL-STATE EXCLUSION: the " +
280
- "post-commit hook now ensures .rafa/.gitignore AND untracks previously " +
281
- "tracked machine state (hydration.json · sensor queues · demo benchmark · " +
282
- "distill staging · *.theirs.md) — the next mirror commit cleans the branch. " +
283
- "Plus wave-2 SOPs: delta briefing + decision recall at plan time, branch-" +
284
- "aware recall (tier-labeled), compass sitback, gap lifecycle beats.",
273
+ "LEDGER HYDRATION: `rafa hydrate improvement <id>` faults a ledger item into " +
274
+ ".rafa/improve/improvements/<id>.mdthe CANONICAL path so bloom edits the " +
275
+ "same file the org brain carries (never a path twin). SOPs updated: an " +
276
+ "improvement the plan ADOPTS is hydrated AT PLAN TIME (bloom engages from the " +
277
+ "start, not only at build end); ledger status edits always hydrate first. " +
278
+ "Platform fixes ride server-side: set_active_plan now resolves v2 epics " +
279
+ "(was v1 parent-only the not_found bug), get_improvement serves summary.",
285
280
  },
286
281
  {
287
282
  version: "0.8.14",
@@ -300,18 +295,41 @@ export const RELEASES = [
300
295
  "session-start absence sensor) — never a dev-typed command.",
301
296
  },
302
297
  {
303
- version: "0.8.13",
298
+ version: "0.8.15",
304
299
  contract: 1,
305
300
  plans: 2,
306
301
  requires: "update",
307
302
  summary:
308
- "LEDGER HYDRATION: `rafa hydrate improvement <id>` faults a ledger item into " +
309
- ".rafa/improve/improvements/<id>.mdthe CANONICAL path so bloom edits the " +
310
- "same file the org brain carries (never a path twin). SOPs updated: an " +
311
- "improvement the plan ADOPTS is hydrated AT PLAN TIME (bloom engages from the " +
312
- "start, not only at build end); ledger status edits always hydrate first. " +
313
- "Platform fixes ride server-side: set_active_plan now resolves v2 epics " +
314
- "(was v1 parent-only the not_found bug), get_improvement serves summary.",
303
+ "THE REVIEW GATE + ZERO-LEAK MIRRORS. `rafa review`: deterministic brain-" +
304
+ "grounded review pre-pass diff's changed lines the cite graph rules AND " +
305
+ "playbooks + open improvements + stale-cite risk + open gaps, each note " +
306
+ "relevance-scored (OKF type-aware: contract class weighs heavier) into " +
307
+ "deep/triage/skip engage tiers so the judge's tokens scale with the DIFF, " +
308
+ "never the brain (rafa-review SOP: local-first + frontmatter-first reads, " +
309
+ "10-note deep cap, skips listed never judged). LOCAL-STATE EXCLUSION: the " +
310
+ "post-commit hook now ensures .rafa/.gitignore AND untracks previously " +
311
+ "tracked machine state (hydration.json · sensor queues · demo benchmark · " +
312
+ "distill staging · *.theirs.md) — the next mirror commit cleans the branch. " +
313
+ "Plus wave-2 SOPs: delta briefing + decision recall at plan time, branch-" +
314
+ "aware recall (tier-labeled), compass sitback, gap lifecycle beats.",
315
+ },
316
+ {
317
+ version: "0.8.16",
318
+ contract: 1,
319
+ plans: 2,
320
+ requires: "update",
321
+ summary:
322
+ "THE SESSION TAIL NEVER STRANDS (live-catch 2026-07-24: brain notes " +
323
+ "authored AFTER the last code commit sat uncommitted while `rafa " +
324
+ "checkpoint` said clean — capture plane synced, git plane dirty). " +
325
+ "`rafa checkpoint` now owns BOTH planes: after the working-set sync it " +
326
+ "fires the vendored brain-commit worker whenever the brain tree is " +
327
+ "dirty, so the tail commits + pushes at the same beat that creates it. " +
328
+ "The worker is tail-aware: HEAD already mirrored ⇒ a distinct " +
329
+ "`session tail · N file(s)` subject on the same code-commit trailer " +
330
+ "(never a look-alike duplicate), and an empty tail is a no-op. " +
331
+ "review.json (the review gate's scored-ranges artifact) joins the " +
332
+ "local-state exclusion — machine state, never brain knowledge.",
315
333
  },
316
334
  ];
317
335
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rafinery/cli",
3
- "version": "0.8.15",
3
+ "version": "0.8.16",
4
4
  "description": "rafa — the AI engineer CLI. Vendors the rafa blueprint into your repo (shadcn-style) and runs the deterministic contract gates.",
5
5
  "type": "module",
6
6
  "bin": {