@misterhuydo/cairn-mcp 1.30.0 → 1.32.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/README.md CHANGED
@@ -225,6 +225,32 @@ invisible:
225
225
  instead of "go and find it". A link that cannot be resolved is dropped rather than
226
226
  emitted dead.
227
227
 
228
+ The two halves answer different questions and deliberately disagree. The reader half
229
+ hides shipped and abandoned work so what is *next* leads. The JSON half publishes the
230
+ plan **complete** — `done` and `stale` phases stay in `phases` with their real status,
231
+ because a consumer that cannot see finished work will confidently render an incomplete
232
+ plan. A shipped phase also carries `shipped` (the date) and `commit` (short HEAD when it
233
+ was marked done), which is what turns "this was done" into something you can point an
234
+ agent at when you are tracing a bug back to where it came from. Phases from *superseded*
235
+ plans, whose numbers a later plan reclaimed, move to a separate `shipped_phases` array —
236
+ identity and provenance only, no `detail`, so a long-lived repo's history cannot bloat
237
+ the file. That key is always present; its absence means the file predates this.
238
+
239
+ Three rules the format leaves implicit, each of which has cost a consumer real time:
240
+
241
+ - **The `roadmap-json` block is terminated by a fence at the start of a line.** Match it
242
+ that way, not with a naive non-greedy `` ``` ``. This is safe by construction: a
243
+ newline inside a JSON string is escaped, so an embedded fence can never begin a line
244
+ and only the real terminator can.
245
+ - **`detail` may itself contain fenced code**, which is exactly why the rule above
246
+ matters. A consumer that ends the block at the first `` ``` `` it meets can end it
247
+ *inside* a JSON string and spill ~125KB of machine data onto the page as prose.
248
+ - **`cursor` may name a slice, not a top-level phase.** It is the exact focus. To mark
249
+ one phase current, use `cursor_phase`, which is always the top-level ancestor and
250
+ always resolves in `phases`; `cursor_path` is the root-to-focus chain for breadcrumbs.
251
+ All three are `null` when nothing is active, so "nothing is in progress" is never
252
+ ambiguous with a broken pointer.
253
+
228
254
  The first line is the marker that says who generated the file and when
229
255
  (`<!-- slot:roadmap format=roadmap/1 provider=cairn generated=… -->`). cairn declares
230
256
  the slot in its MCP entry in `~/.claude.json`, so a cockpit does not have to guess.
@@ -348,19 +374,37 @@ is least reason to speak. Bytes survive now only as a fallback for when no usage
348
374
  record is reachable, and when that happens the line says so instead of dressing a
349
375
  file size up as a token count.
350
376
 
351
- **It only speaks at 90% of the window and above.** The window size is not observable
352
- no hook input carries it, and the transcript records usage but never a limit — so
353
- cairn infers the smallest window that could already hold what it has measured.
354
- Having *seen* 482k tokens proves the window is bigger than 200k, and that is the one
355
- direction the inference needs to be sound in. A fixed absolute threshold cannot
356
- serve both sizes: 120,000 tokens is 60% of a 200k window but 12% of a 1M one, which
357
- is why v1.20.0 announced a stopping point on a session sitting at just over half its
358
- context. Override with `CAIRN_CONTEXT_HINT_TOKENS` if you want a different bar.
359
-
360
- The one case the inference gets wrong: a 1M-window session between roughly 180k and
361
- 196k looks like a nearly-full 200k one, so it may speak once. It corrects itself as
362
- soon as usage passes 200k, and the no-repeat rule means it says it once, not every
363
- turn.
377
+ **It only speaks at 90% of the window and above** and the window is a setting, not
378
+ a measurement. Nothing cairn can read carries it: no hook input has it, the
379
+ transcript records usage but never a limit, and the model id is no help either
380
+ because a `claude-opus-5[1m]` session writes the base `claude-opus-5` into both the
381
+ transcript's `message.model` and `lastModelUsage` in `~/.claude.json`.
382
+
383
+ Through v1.31.0 cairn guessed the *smallest* window that could hold what it had
384
+ measured, which meant an unmeasured session was assumed to be 200k. That produced a
385
+ guaranteed false-alarm band: on a 1M session, every reading between 180k and 196k
386
+ looked like a nearly-full 200k one. It was measured live at 192,634 tokens, where
387
+ cairn reported **96%** and `/context` said **19%**. The band is structural rather
388
+ than a tuning error any firing point for a 200k window is a point a 1M session
389
+ also passes through — so no threshold can serve both, and the tie-break has to come
390
+ from outside.
391
+
392
+ Since v1.32.0 cairn never guesses downward. Unset, it assumes the widest window it
393
+ knows about and stays quiet; the cost of that being wrong is one missed nudge on a
394
+ genuinely full small window, against an interruption at a fifth of capacity that
395
+ teaches you to ignore the line for good. Measurement still raises the floor — having
396
+ *seen* 482k tokens proves the window is bigger than that — it simply can never lower
397
+ it.
398
+
399
+ If your window really is 200k, say so and both the threshold and the reported
400
+ percentage become exact:
401
+
402
+ ```bash
403
+ export CAIRN_CONTEXT_WINDOW=200000
404
+ ```
405
+
406
+ `CAIRN_CONTEXT_HINT_TOKENS` still overrides the trigger point outright if you want a
407
+ different bar rather than a different window.
364
408
 
365
409
  Deliberately not built: no full transcript walk (the tail only; a full walk in this
366
410
  hot path once froze every terminal in the cockpit for 4.3 seconds), no counting