@treeseed/dsh-chapters 0.2.1 → 0.2.2

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.
Files changed (66) hide show
  1. package/cordis.patch.yml +7 -0
  2. package/docs/backlog.md +1616 -0
  3. package/docs/contract.md +293 -0
  4. package/docs/development.md +183 -5
  5. package/docs/host-protected-head-ask.md +80 -0
  6. package/docs/project-state.md +319 -0
  7. package/docs/verify.md +37 -0
  8. package/lib/arrival.js +24 -0
  9. package/lib/arrival.js.map +1 -1
  10. package/lib/aux-message.d.ts +17 -0
  11. package/lib/aux-message.js +20 -0
  12. package/lib/aux-message.js.map +1 -0
  13. package/lib/client.js +536 -227
  14. package/lib/client.js.map +1 -1
  15. package/lib/commands.js +107 -1
  16. package/lib/commands.js.map +1 -1
  17. package/lib/continue-core.d.ts +6 -0
  18. package/lib/continue-core.js +18 -13
  19. package/lib/continue-core.js.map +1 -1
  20. package/lib/engine-core.d.ts +3 -0
  21. package/lib/engine-core.js +4 -3
  22. package/lib/engine-core.js.map +1 -1
  23. package/lib/engine-note.d.ts +35 -0
  24. package/lib/engine-note.js +32 -0
  25. package/lib/engine-note.js.map +1 -0
  26. package/lib/engine.d.ts +10 -0
  27. package/lib/engine.js +97 -6
  28. package/lib/engine.js.map +1 -1
  29. package/lib/index.d.ts +5 -0
  30. package/lib/index.js +199 -8
  31. package/lib/index.js.map +1 -1
  32. package/lib/injections.js +10 -0
  33. package/lib/injections.js.map +1 -1
  34. package/lib/prompt-loop.d.ts +73 -0
  35. package/lib/prompt-loop.js +141 -0
  36. package/lib/prompt-loop.js.map +1 -0
  37. package/lib/prompt-runner.d.ts +44 -0
  38. package/lib/prompt-runner.js +85 -0
  39. package/lib/prompt-runner.js.map +1 -0
  40. package/lib/prompt-state.d.ts +124 -0
  41. package/lib/prompt-state.js +96 -0
  42. package/lib/prompt-state.js.map +1 -0
  43. package/lib/prompt.d.ts +32 -2
  44. package/lib/prompt.js +31 -9
  45. package/lib/prompt.js.map +1 -1
  46. package/lib/registry.d.ts +7 -0
  47. package/lib/registry.js +2 -0
  48. package/lib/registry.js.map +1 -1
  49. package/lib/render.d.ts +22 -1
  50. package/lib/render.js +40 -7
  51. package/lib/render.js.map +1 -1
  52. package/lib/repair-run.d.ts +27 -0
  53. package/lib/repair-run.js +85 -2
  54. package/lib/repair-run.js.map +1 -1
  55. package/lib/rules.js +8 -0
  56. package/lib/rules.js.map +1 -1
  57. package/lib/save-core.js +4 -4
  58. package/lib/save-core.js.map +1 -1
  59. package/lib/store.js +11 -0
  60. package/lib/store.js.map +1 -1
  61. package/lib/tools.d.ts +3 -0
  62. package/lib/tools.js +17 -4
  63. package/lib/tools.js.map +1 -1
  64. package/lib/version.d.ts +1 -1
  65. package/lib/version.js +1 -1
  66. package/package.json +20 -16
@@ -321,3 +321,322 @@ being edited from is solved — see [docs/development.md](docs/development.md).
321
321
 
322
322
  Then [docs/contract.md](docs/contract.md) for how to declare things, and
323
323
  [docs/verify.md](docs/verify.md) before claiming any step passes.
324
+
325
+ ## Round: the bar renders, and the chain went green locally (2026-10-26/27, host 0.2.0-rc.2)
326
+
327
+ Measured, in the order the evidence arrived:
328
+
329
+ - **`prompt` and `prompt-off` pass in Chromium**, in record and in strict replay: the docked row mounts above
330
+ the composer at order 30, shows `Analyzing`/the offer, expands, drafts-or-explains, and Run reaches the
331
+ durable log as a user-role message. 10-project chain `E2E_MODEL=replay npm run test:e2e` → **EXIT=0**
332
+ (`suite` 4 passed 39.8s, `heavy` 1.8m, `arrival`, `enrich`, `fanout`, `rules`, `fork`, `plans`, `prompt`
333
+ 4 passed, `prompt-off`). `coverage:e2e` → **EXIT=0** on the same build.
334
+ - **Four causes, all found by measurement after a wrong theory each time.** (1) The tape proxy joined
335
+ `…/compatible-mode/v1` + `/v1/chat/completions` into `/v1/v1/…`, so nine legs had no assistant row at all.
336
+ (2) `off` meant disabled, empty, and broken at once; `idle` split them apart. (3) A per-turn
337
+ `Elapsed since the preceding model-visible message: …` line was unmasked, so replay diverged from record by
338
+ one character of punctuation. (4) `prompt`'s failure was a React **#310 hook-order crash** — a hook I added
339
+ sat below the component's early `return null` — and it *looked* credential-dependent because the credential
340
+ changed when the row's visibility transitioned. The journal's silence (zero `MISS tape=prompt`) is what killed
341
+ that theory in front of the evidence.
342
+ - **Rig honesty landed too:** a strict-replay `MISS` is now fatal for the leg that produced it, with a byte
343
+ baseline so it cannot blame another leg's history; the proxy falls back to an ephemeral port rather than
344
+ dying on an orphan; `applyRigEnv` and `rigEnv` became one derivation (mutation-proven); a missing profile
345
+ patch throws instead of being skipped; the chain-coverage row is mutation-proven and caught
346
+ `--project=prompt-off` substring-matching `--project=prompt`.
347
+ - **Still open, named not smoothed:** CI's acceptance job is red while the local chain is green and its
348
+ annotation carries no verdict lines (repro running); Autorun's idle edge is **unwired** — `useSessionStatus`
349
+ is documented in the dock's prop list but calling it failed twice, so the gate keeps `running` undefined and
350
+ Autorun says it is unavailable, which means objective item 3's "Autorun displaces the goal" pixel is not yet
351
+ shown and item 4 remains unit-covered only; and the `prompt` tape is 546 entries / 12 MB, needing a cap.
352
+
353
+ ### 2026-10-27 — the three bullets above are now superseded, item by item
354
+
355
+ - **Autorun's idle edge is wired, and the browser says so.** The dock was being handed `useSessionStatus` — a
356
+ `SnapshotSelectorHook`, so calling it with a session id made the host use a string as a selector and it threw
357
+ `TypeError: l is not a function`. The signal the legs needed was on a different prop all along: `useSession`'s
358
+ snapshot carries `running`. Wired through an identity selector folded by `deriveRunning` (unknown ≠ idle), the
359
+ leg now asserts arm-ability and passes: `prompt` 4 passed in Chromium, model-free replay, twice (distill and
360
+ replay). **What is still not shown is the displacement pixel** — Autorun superseding a goal's continuation — so
361
+ objective item 3 remains partly open and item 4 is still unit-covered only.
362
+ - **CI's acceptance annotation carries its verdict now,** and the failure it names is not a tape fault:
363
+ `MOUNT FAULT: the session registered none of the core tools every journey needs — missing: bash, read, edit,
364
+ write (declared=44 registered=7 …)`. Root cause found by measurement, not argument: the booted profile's preset
365
+ names 28 `@deepseek-ai/*` plugin packages, none of which is a dependency of this repository, so a development
366
+ host resolved them out of `~/node_modules` and a CI runner resolved nothing and our preset silently pruned 21
367
+ tool rows — 34 tools here against 7 there, and message 0 is the tape key. `linkPinnedToolPackages()` now links
368
+ the pinned install into `node_modules/@deepseek-ai` **before** the host spawns (never replacing what the repo
369
+ already installs), and the CI-shaped clone measured `tools=7 / chars=2880` → `tools=34 / chars=7378`. Provisioning
370
+ bubblewrap and lifting the AppArmor userns restriction were tried first and are recorded as NOT the cause, each
371
+ refuted by the runner's own artifact.
372
+ - **The `prompt` tape is 14 entries, not 546.** The bloat was repeated distills accumulating in a directory the
373
+ ad-hoc loops never cleared; `distill-tapes.sh` clears per project, and the corpus is re-anchored on the capped
374
+ build with `CORPUS_HOST` stamped (`lib=fcd1e375bab82d3d`, `distilledAt = 2026-10-27`), strict chain green twice
375
+ locally at that point. Later the same day the pin-link change invalidated those captures and the corpus was
376
+ restored to the stamped state rather than left mixed — recorded here because "green" has to name the build it
377
+ belongs to.
378
+ - **New, still open, and named:** #128 (our typecheck passes against harness types a release line behind the pin —
379
+ four sites pass `source.kind: 'plugin'`, which 0.2.0-rc.2 rejects; and `package.json` 0.2.0 vs lock 0.1.22), and
380
+ #129 (`globalSetup` boots one server from the setup process's env while Playwright applies project env to
381
+ workers, so a multi-project run shares a boot and a home; `scripts/chain-replay.sh` now runs one boot per
382
+ journey, and tightening session discovery to the preferred workspace fixed `prompt`'s `identity mismatch`).
383
+
384
+ ### 2026-10-28 — two product defects closed, and acceptance narrowed to one coupling
385
+
386
+ - **#131 — artifacts were unreachable.** Arrival-time deferral was applied to `chapters_artifact`'s own output, so
387
+ asking to read a stored blob returned *another* pointer to another blob. Found in the leg's durable log (20 tool
388
+ calls, 17 erroring/looping) after three of my own wrong diagnoses (trigger margin, aux turn, haystack size).
389
+ Exempting artifact answers fixed two legs at once: `arrival` 8 entries and `fanout` 41 captured green, each
390
+ replaying green alone. Filed with repro; credit matters — both looked like model flakiness for a day.
391
+ - **#113 — the Autorun button refused its own click.** The dock dispatched local state and then `refresh()` re-read
392
+ the server and flipped the label back; `off` two lines below sent its command correctly, which is how the
393
+ asymmetry showed. Fixed, guarded by `prompt-dock-autorun-write.test.ts` (red first; the property form survived
394
+ my `[^}]*` mistake). **Displacement is now observed in Chromium**: with a goal armed the host offers `Pause
395
+ goal`; clicking Autorun leaves `Autorun off` in place, the host flips to `Resume goal`, `Pause goal` disappears.
396
+ Recorded under the real provider, replayed model-free twice at 5 passed. That closes item (3)'s last sub-claim
397
+ and gives item (4) a browser-level half — goal-off restoring a suggestion is still unit-only and still unclaimed.
398
+ - **#129's remaining acceptance gap is one coupling, named.** `#arrive` runs only at the head of the relief entry
399
+ points, so `auto: false` disables deferral with relief, and leaving it on makes deferral depend on when a
400
+ threshold crosses on that machine's header bytes. Every remaining CI divergence has the same fingerprint: a
401
+ checkpoint notice where the other machine has a plain message, or a history one message longer. `heavy` and
402
+ `fanout` are that, not separate mysteries. The clean fix conflicts with "no second automatic engine timing of our
403
+ own", so #132 carries four options with costs and a recommendation; the decision is the maintainer's.
404
+ - **Numbers on this branch right now:** plane 1,114/1,114 with 0 skipped; `typecheck` and `typecheck:client` 0;
405
+ `typecheck:e2e` at its 68 baseline; full one-boot-per-journey chain green ten-for-ten twice (`AR=0`, `A2K=0`);
406
+ fresh `coverage:e2e` 78.31% (`CVA=0`), stamped `lib=081a726aca738d02`-era corpus. CI: deterministic job green,
407
+ acceptance red on `heavy`/`fanout` after `arrival` and `prompt` were fixed — four legs to two, both locally and on
408
+ the runner. #127 unmerged behind that gate; `0.2.2-dev.1` unpublished.
409
+ - **Corrections I made to myself in the open** (each with its evidence in git): the `noAuxModel` "inert key" claim
410
+ (it is a rig alias for `auto`/`elicitedPlot`, which the host does read), the fold that broke a green leg, the
411
+ pin attribution that the pre-change logs disproved, and the `limit 5000` prompt that made a leg depend on a
412
+ rejected call — the last one was a real bug and its fix is what took `arrival` off CI's failing list.
413
+
414
+ ### 2026-10-28 — the acceptance pipeline went green, and the branch is on staging
415
+
416
+ **Run 40676609079**: deterministic ✅ · pinned-host preset-rows probe ✅ · **acceptance ✅ — ten legs `ok`, each on its own boot**: suite, heavy, arrival, enrich, fanout, rules, fork, plans, prompt, prompt-off. PR #127 squash-merged to `staging` as `45dd4ac`; #56 closes with it.
417
+
418
+ What it took, in the order the layers came apart — each fixed by measurement, never by masking:
419
+
420
+ 1. **The proxy join** (`/v1/v1` → 404 → no assistant message) that had nine legs failing on provider wiring.
421
+ 2. **The runner assembled 7 tools where a dev host assembled 34** — 28 preset rows naming packages that are not this
422
+ repo's dependencies, pruned in silence. `linkPinnedToolPackages()` before spawn, plus the `MOUNT FAULT` abort that
423
+ replaced masking. Refuted along the way, with evidence: bubblewrap provisioning, AppArmor userns, credentials,
424
+ installed bytes, profile rows, config keys.
425
+ 3. **One boot served ten projects** — `globalSetup` boots from the setup process's environment while project `env`
426
+ reaches workers only. `npm run test:e2e:replay` is now one journey per boot, which is also how tapes are recorded.
427
+ 4. **#131, the artifact cycle** — `chapters_artifact` answers were themselves arrival-stubbed, so a stored blob
428
+ answered with a pointer to another blob and the store was unreachable at exactly the sizes it exists for. Two
429
+ legs' week-long "flakiness" was this one defect.
430
+ 5. **Turn count, not timing** — the last misses were legs whose journey length was the model's choice. Bounding them
431
+ (`fanout`: one decisive oversized read per child; `arrival`: one read plus ≤2 artifact queries; `heavy`: three named
432
+ 600-line pages) is what made them portable, and bounding `heavy` correctly required learning that **the read tool
433
+ caps a call at 600 lines** — measured on both machines — which is what made the old fixture's marker pigeonhole work
434
+ and my first "three reads of 2000" bound unsatisfiable.
435
+
436
+ Five claims I published and then retracted the same day, each caught by a test or by a byte rather than by
437
+ reflection: the "nearest-prefix serving" matcher theory (`findReplay` requires equal length), the 38× title-call
438
+ signal (a cumulative journal read as one run), the duplicate `<DSH-CHECKOUT>` blind (raw dumps diffed before
439
+ normalizing), `noAuxModel` as an inert key (it is a rig alias for `auto`/`elicitedPlot`, which the host really
440
+ reads), and the folding of injected instructions out of matching (it collapses positional prefixes and mis-serves
441
+ turns — the row system refused it, and the honest fix was to stop injecting a development doc into acceptance).
442
+
443
+ **Still open, unsoftened:** #126 (a dock cannot write the composer on 0.2.0-rc.2 — click-to-draft shows a refusal and
444
+ Run submits), #128 (harness devDependencies lag the pinned runtime; 4 sites pass a retired `source.kind`), #130 (a
445
+ boot hang when plot elicitation is off while relief declines — user-reachable from config), and the goal-off
446
+ restores-a-normal-suggestion half of the interplay, which is unit-covered and **not** claimed from a browser.
447
+
448
+ ### 2026-10-28 (later) — the goal-off browser leg withdrawn after four failed captures; the claim returns to unit-only
449
+
450
+ PR #136 is closed **unmerged** and the tree is byte-identical to the state CI proved green (spec back to the five
451
+ merged tests, `prompt` tape back to 24 files, stamp `lib=b67e373defcad83a`, `corpus:check` agreeing; isolated replay
452
+ `5 passed`, plane 1,115/1,115, `typecheck:e2e` 68 baseline).
453
+
454
+ Four attempts at the goal-off leg, four different failure classes — recorded because each one is a general trap:
455
+
456
+ 1. `Clear goal` **button** after a turn → CI diverged at `msg32`: a `<goal_round>` where the capture had the human turn.
457
+ 2. `/goal clear` immediately, no turn between → CI diverged at `msg12`: runner `Round: 3/256`, capture `Round: 4/256`.
458
+ 3. Poll until a round appears, then act → still diverged. The structural reason I had missed: **a goal round is itself
459
+ a turn, and every turn ends**, so rounds self-sustain — the resulting tape held `Round: 12/256`. Click timing
460
+ cannot race a loop that schedules itself, and there is no rig knob (the human `/goal` takes no round argument;
461
+ `goal-round-driver` has no config block).
462
+ 4. Bound it with the product's own rule — instruct the model to call `create_goal(max_goal_rounds: 1)` and wait for
463
+ the quiesced `Round: 1/1` → capture failed at `the host goal bar appears once a goal exists`: the model answered in
464
+ prose instead of invoking the tool.
465
+
466
+ Attempt 4 is the one that settles it. A browser leg whose *setup* requires a small model to cooperate is encoding luck
467
+ into the tape, which is exactly what #132 and #135 keep charging this corpus to stop doing — so the leg does not ship
468
+ until its setup is deterministic without asking the model. What survives the exercise is a rig rule worth more than the
469
+ test (#135's entry in the rig list): **a tape may carry a background mechanism's output only when that mechanism has a
470
+ state it cannot leave.**
471
+
472
+ Site §28 and the interface lock are unchanged, because neither ever claimed the goal-off pixel; AGENTS.md now states
473
+ the half that is unit-covered and is not browser-claimed. `heavy`'s 600-line page fix, the prefix-symmetry fix and the
474
+ rest stay as merged — they are green on the runner.
475
+
476
+ ### 2026-10-28 (evening) — the goal claims are browser-verified, and the corpus no longer records latency
477
+
478
+ **What changed in the claim.** Both halves of the goal/suggestion interplay are now observed in Chromium: arming the
479
+ bar's Autorun takes a session's next turn away from an active goal (`Pause goal` → `Resume goal`, Pause disappears), and
480
+ after `/goal clear` the bar still produces a real suggestion on the next turn (#135's second half, which had been
481
+ unit-only). **The class of that evidence is the finding, so it is stated with the claim:** both run in
482
+ `tests/e2e/prompt-goal-live.spec.ts` against the real provider under a 420 s wall-clock ceiling (**2 passed**,
483
+ `var/goallive-2.log`), and the model-free acceptance job deliberately does not cover them — `chain-replay.sh` omits the
484
+ project and the spec skips under `E2E_MODEL === 'replay'` with the reason in the message.
485
+
486
+ **Why they cannot be tape legs.** A goal round is a turn and every turn ends, so an armed goal drives itself; replay
487
+ answers instantly, so the round count tracks machine speed. Two docs-only pushes proved the merged leg was agreeing by
488
+ luck (runs 40697174778, 40706037817 — nine legs `ok`, `prompt` FAILED, `storedCandidates: []`, runner at
489
+ `Round: 1/256`…`Round: 4/256`). I then built the bound the source offered — `ctx.goals.create(agent, { objective,
490
+ maxGoalRounds: 1 })`, plugin-callable, as upstream's own `seed-goal.ts` fixture uses — and it *worked* (17-entry tape,
491
+ `Round: 1/`, no second round) while still being useless: spending a budget calls `ctx.goals.block(…, 'round-limit')`
492
+ and `GoalBar.tsx:85-86` renders no strip for a blocked goal. **An armed goal has no rest state at any budget** — 256
493
+ floods, 1 ends it. Recorded in `docs/contract.md` with the line numbers; #138 restated as that gap.
494
+
495
+ **Numbers after the change.** `prompt` re-anchored to **14 entries, zero round markers**; replayed `4 passed` twice;
496
+ one full `npm run test:e2e:replay` **ten-for-ten (`CT=0`)**; fresh `coverage:e2e` **77.85%** with the CI plane at
497
+ **93.41 / 85.25 / 90.69** against the 85/85/85 gate; plane 1,118/1,118, `typecheck` 0, `typecheck:client` 0.
498
+
499
+ **Two of my own bugs, both caught by measurement rather than reflection.** (a) The new spec landed inside `suite`'s
500
+ boot — `suite` is the one project defined by `testIgnore`, so any new file joins it; the suite tape's second request is
501
+ the session-title call over those human messages, and it stopped matching (`MISS tape=suite messages=2 divergeAt=msg1`,
502
+ staging `4 passed` vs mine failing, docs and pins ruled out by reverting them). Fixed by ignoring the file, with the
503
+ selector audit in the comment. (b) My skip guard compared `E2E_TAPE` — the *project name* — to `'replay'`, so it never
504
+ fired; the rig's signal is `E2E_MODEL === 'replay'` (`globalSetup.ts:52`). (c) The `e2e-typecheck-ratchet` then refused
505
+ my +1 error, and instead of raising the ceiling I fixed the cause: one documented cast at the projects boundary replaced
506
+ eleven identical `TS2769`s and the baseline **fell 68 → 59**, which is the direction the ratchet asks for.
507
+
508
+ ### 2026-10-28 (late) — a dependency alignment found a live product failure: 32K hosts had no relief at all (#140, #128)
509
+
510
+ Aligning this repo's `@deepseek-ai/*` compile deps to the host the rig actually boots (`0.2.0-rc.2`) made seven
511
+ `engine-lifecycle` rows throw:
512
+
513
+ ```
514
+ compaction-basic: local/qwen-test reserves 0 completion tokens and 65536 headroom tokens
515
+ of its 32000-token context window … → TargetPressureConfigError
516
+ ```
517
+
518
+ That is not a test artifact. `dsh-compaction-basic@0.2.0-rc.2` validates
519
+ `contextWindow − reservedCompletionTokens − headroomTokens` per routed target and **throws** when it is ≤ 0, its default
520
+ `headroomTokens` is **65,536**, and that reservation exists to bound a routed summarize call — which this engine does
521
+ not make, because `summarize()` is overridden and deterministic (`src/engine.ts:664`). So on any model under 65,536
522
+ tokens — including 32K, which is this project's own stated target hardware — the plugin's central feature raised an
523
+ exception instead of compacting, and had done so silently for two host minors because the compiler was reading older
524
+ types. The e2e legs cannot see it: the token-plan model reports a window well above the default.
525
+
526
+ Two changes, deliberately different in kind. The realm's engine row now bounds `headroomTokens: 8192` (inert at 128K —
527
+ `min(window × 0.9, window − 8192)` keeps the ratio as the trigger — and positive at 32K), and the engine refuses to let
528
+ a *configuration* problem escape as a crash: `isPressureConfigRejection()` identifies the class structurally (the
529
+ error type is not re-exported in the bundle's types), logs the cause, and abstains. Provider failures still propagate
530
+ after finalization, and a row pins that asymmetry — r19's distinction between "the user can fix this" and "the
531
+ endpoint failed".
532
+
533
+ Then the temptation, and why it was refused: after the first cut, the pre-existing `#78` row ("a declined relief while
534
+ over the trigger is reported with its numbers") failed. Editing its expectation would have been the easy green. It was
535
+ right, and my branch had dropped a fact — a config-impossible realm still DECLINED relief while over the trigger — so
536
+ the branch now emits the cause *and* calls `#reportDecline()`. Two silences traded for one is not a fix.
537
+
538
+ Red-first rows that keep the failure from returning: `host-dep-pinning.test.ts` (compile deps equal the lock's exact pin,
539
+ and the installed copy matches — a caret here is how 32K hosts lost relief twice), `aux-message-kind.test.ts` (no shipped
540
+ code carries the retired bare `source.kind: 'plugin'`; four one-off `llm.stream` sites now say `kind: 'user'`, which is
541
+ what they are), and the drift row in `preset-declaration.test.ts` (realm carries the bound *and* `Config` declares it, so
542
+ the next host bump cannot quietly drop the key).
543
+
544
+ Measured on this branch: plane **1,287/1,287, 0 fail, 0 skipped**; `typecheck` 0; `typecheck:client` 0; e2e typecheck
545
+ **59/59** (the ratchet fell when one boundary cast replaced eleven identical `TS2769`s); corpus fully re-anchored because
546
+ the lib hash moved — every leg captured `exit=0`, one strict `npm run test:e2e:replay` **ten-for-ten (`CD=0`)**,
547
+ `corpus:check` agreeing. A fresh `coverage:e2e` on this corpus is recorded in the PR body. One accuracy note: my previous
548
+ commit claimed two stray `src/*.bak` files were removed; they were deleted in the tree but still tracked, and THIS commit
549
+ is what removes them — the claim was right in intent and wrong about state, which is the failure this file exists to
550
+ catch.
551
+
552
+ ### 2026-10-28 (night) — the release, a dead tag, and `heavy` moving to the live class (#140, #128, #141, #142)
553
+
554
+ **Release state, exactly.** PR #139 (`0.2.2-dev.1`) was CI-green on all three jobs and merged to `main` as `f9943f9` on the
555
+ maintainer's explicit authorization. The tag `0.2.2-dev.1` then **failed the publish blocker** for a reason that was mine:
556
+ the bump commit edited `package.json` only, and `tests/unit/loudness.test.ts:123` asserts
557
+ `PLUGIN_VERSION === package.json.version`, so `src/version.ts` (still `0.2.1`) tripped the gate — Release run
558
+ 40771258161, `tests 1282 / pass 1271 / fail 1`. A pushed tag is immutable, so **`0.2.2-dev.1` is a dead release** and stays
559
+ in place with this note; `0.2.2-dev.2` bumps all three version-bearing files at once (`package.json`, `src/version.ts`,
560
+ lock root). I also checked the old base engine directly — `@deepseek-ai/dsh-compaction-basic@0.1.5-rc.2`'s tarball has
561
+ **zero** occurrences of `headroomTokens` — so #140's realm key and #128's dependency alignment are one delivery, not two:
562
+ a realm setting a key the compiled-against base rejects would simply fail `validateKeys`.
563
+
564
+ **`heavy` is a live-class leg now, chosen by the maintainer, on six captures' worth of evidence.** Four designs on one
565
+ commit produced 5, 7, 12, 23 and 24 tape entries (three mandated reads; one read of a ~68K-token page; one read of a
566
+ ~17K-token page tuned to this realm's real 14,400 trigger; one read plus a tool-free report), and CI's own widened miss
567
+ diff — which is why `tapeDiffPayload` was worth building — showed the mechanism: once relief auto-continues the session,
568
+ the child's history is `[system, checkpoint-notice, …]` and at message 12 it was running
569
+ `bash … head -30 tests/e2e/artifact-arrival.spec.ts && grep -rl 'E2E-D3-0731|E2E-PD-0731|…'`, marker-exploration work the
570
+ spec never asked for. The request count belongs to the model, so no tape of that journey is portable. The leg skips under
571
+ `E2E_MODEL === 'replay'` with the reason in the skip message, is absent from `scripts/chain-replay.sh`'s nine-leg list, and
572
+ runs against the real provider under its 110-minute ceiling. **What makes this honest rather than a dodge:** every
573
+ assertion still executes (relief passes shrink, nothing lost from the durable log, the read markers survive, the session
574
+ takes its next turn), and relief timing is covered without a browser or a model by `tests/unit/engine-lifecycle.test.ts`,
575
+ which is where #140's rows live.
576
+
577
+ **A bug of mine that had to be caught before it could be trusted: I inverted the live-leg guard.** The goal leg passed
578
+ **2/2** for real (`var/goallive-2.log` reads `prompt-goal-live mode=record provider=harness`), and the guard as it shipped
579
+ said `test.skip(process.env.E2E_MODEL !== 'replay', …)` — i.e. it ran only in replay and skipped in live, the opposite of
580
+ its comment and of the intent. My "fix" for the earlier `E2E_TAPE` confusion had flipped the predicate. Proved the way it
581
+ should be proved: after correcting it to `=== 'replay'`, a replay invocation returns `2 skipped` with the reason and exit
582
+ 0. Two guards in the tree now share one spelling, and the copy of the predicate is why the fix went to both files at once.
583
+
584
+ **Correction to the paragraph above, same day, and it is the more important fact.** `heavy`'s live run did **not** pass: `1 failed` on
585
+ the leg's own bound — `expect(summaries.length).toBeLessThanOrEqual(30)` — run `LEG=heavy MODE=record E2E_PROVIDER=harness`, exit 1,
586
+ `var/heavy-live.log`. So the browser-level claim "relief converges in bounded passes on the rig's pinned 32K window" is **not
587
+ currently demonstrated**, and this file does not claim it. What *is* demonstrated: the plugin does not crash and does not throw on a
588
+ 32K window (#140's rows, 1,287/1,287 deterministic), and the model-free acceptance set (nine legs) is green on CI. The many-pass
589
+ behaviour is filed as its own bug with per-pass numbers as the first acceptance criterion, and the bound is not being raised.
590
+
591
+ ### 2026-10-28 (late night) — a release shipped, an anchor gate became real, and a tally stopped being a claim (#139–#158)
592
+
593
+ **The release.** `@treeseed/dsh-chapters@0.2.2-dev.2` is on npm — registry says `versions: [… 0.2.1, 0.2.2-dev.2]`,
594
+ `dist-tags: {latest: 0.2.1, dev.2: 0.2.2-dev.2}`, so the prerelease rides its own tag and `latest` stays stable. Verified
595
+ against `registry.npmjs.org` directly, because a local `npm view` claimed the version was missing: the CLI was serving
596
+ stale data and the registry is the source of record. It carries #140 (32K hosts had *no* relief — the base engine's
597
+ `contextWindow − reserved − headroom` validation against a 65,536 default, with our realm bounding it at 8,192 and a
598
+ fixable configuration now abstaining with a named note instead of throwing) and #128 (compile deps equal the host the rig
599
+ boots, with guards on both the manifest and the installed copy).
600
+
601
+ **`0.2.2-dev.1` is a dead tag and stays one.** Its bump commit moved `package.json` only, and `loudness.test.ts:123`
602
+ pins `PLUGIN_VERSION === pkg.version`, so Release run 40771258161 failed the publish blocker (`tests 1282 / pass 1271 /
603
+ fail 1`). Pushed tags are immutable: superseded, never moved. Getting `dev.2` mergeable also required **merging `main`
604
+ back into `staging` with a real merge commit** (#146) — the previous squash had left the branches divergent and made the
605
+ RC `CONFLICTING / DIRTY`. A version bump now moves three carriers together: `package.json`, `src/version.ts`, and the
606
+ lockfile's root plus `packages[""]`.
607
+
608
+ **The anchor gate measures the right thing (#156, merged as #157).** The stamp hashed the built bundle, so a
609
+ diagnostics-only change (#152/#153) demanded a full re-record while CI's nine-leg acceptance was legitimately green — and
610
+ `corpus:check` appeared in `ci.yml` only inside a comment, so nothing enforced it. `scripts/prompt-anchor.mjs` now
611
+ hashes **what a model reads** (tool/command descriptions, the dock label, the persona, a whitelist of realm keys),
612
+ `verdictFor()` splits refuse-vs-advise, and `corpus:check` runs in the **blocking deterministic job** — verified from the
613
+ Actions job's step list, not from a green tick, and successful on GitHub's runner. A manifest file that yields zero
614
+ tokens fails its own row, so a dead extraction rule can't masquerade as protection.
615
+
616
+ **A tally stopped being a claim (#143, #154, #155).** The heavy leg asserted `passes ≤ 30` and live runs produced **38,
617
+ 9, 7, 22** on the same realm — the count belongs to the model's turn, not the mechanism. After the maintainer's
618
+ decision it asserts progress (≥1 node shadowed per pass), monotonicity (no node shadowed twice), and the post-condition
619
+ (surface left under the realm's trigger, read from the engine's own note), with `PASS_CEILING = 60` commented as a
620
+ runaway guard. Two attributable live passes followed (`1 passed` at 7, then at 22). The rule is written in
621
+ `docs/verify.md` and site §24 as *"bound a mechanism by its invariants, never by a tally."* `heavy` itself is a
622
+ live-provider leg now (#141), so the model-free acceptance set is **nine**, and #149 corrected the CI job's own title,
623
+ which had been advertising a leg it no longer runs.
624
+
625
+ **What stayed open, and what was refused.** `coverage:e2e` cannot currently complete reliably: two consecutive attempts
626
+ failed on **different** legs under `NODE_V8_COVERAGE=1` (120 s door-visible wait; 300 s click timeout) while eight legs
627
+ passed each time and an uninstrumented isolation of the failed leg returned `4 passed, rc 0` minutes later. Filed as
628
+ **#158** with the table; the ceilings were **not** raised, because widening a wait to satisfy an instrumentation mode is
629
+ the failure this project keeps being bitten by. The `rc.4` host bump (#150) is pre-flighted rather than assumed: in a
630
+ worktree with its own `dev/dsh-host-lock` repinned and installed, the *compiled* bundle the browser will load shows
631
+ `mirrorFn` gone and `cancelCommandRestore`/`lastPublishedDraft`/`draftSnapshotCache` present — the mechanism #126 blamed,
632
+ rewritten in the direction that would fix it — while the click-to-draft claim still waits for one browser observation.
633
+
634
+ **Retractions in this file's own voice, kept because they are the useful part.** Four successive theories about `heavy`
635
+ died to measurements (tape variance → fixture sizing → the pinned window → pass thrashing), each of which I had asserted
636
+ with confidence; a live-leg guard I "fixed" had shipped inverted (`!== 'replay'` runs only against a tape); a hollow
637
+ field (`window=?`) and a hollow row (assertions in a branch the harness never reaches) both passed before being caught;
638
+ an issue was closed before its evidence comment existed because a heredoc targeted `var/`, which a worktree has not;
639
+ a long job launched with a shell `&` died with its tool shell and looked like it was running; and a commit message
640
+ carried a **fabricated CI run id** (`40810272330`), amended to the read value (`40803763620`) with the invention left
641
+ visible in the correction. Every one was caught by a gate, a re-read, or an exit code that someone bothered to check —
642
+ which is the entire argument for this repository's design.
package/docs/verify.md CHANGED
@@ -52,6 +52,31 @@ near-zero on the first and high on the second.
52
52
 
53
53
  Steps 4, 7, 8 of the `AGENTS.md` list are G1–G3. They are the whole point of the design.
54
54
 
55
+ ### Bound a mechanism by its invariants, never by a tally (#143)
56
+
57
+ A live leg that waits on a model-driven turn must assert what the mechanism **promises**, not what one run happened to
58
+ count. Measured proof, 2026-10-28, one commit and one realm (`heavy`, 32K window, `thresholdRatio: 0.45`, nothing
59
+ arrival-deferred): two live runs produced **8** and **38** `compaction/summary` events. The assertion was `passes ≤ 30`,
60
+ so the leg could go red with nothing broken — a red test that carries no information is worse than no test, because it
61
+ teaches the next reader to ignore it.
62
+
63
+ **Assert instead:**
64
+
65
+ 1. **Progress per step** — every pass shadows at least one node. A zero-removal pass is the infinite loop any ceiling
66
+ exists to catch, and it is the actual bug class.
67
+ 2. **Monotonicity** — no node is shadowed twice; the shadowed set strictly grows. This is what rules out relief
68
+ circling instead of converging.
69
+ 3. **Post-condition** — relief leaves the surface under the realm's trigger. Read it from the engine's own decision
70
+ note (`surface=… tok`, `window=…`, `ratio=…`, `shadowed=`, `shadowedTok=`, `nodes=`), which is durable bytes written
71
+ **during** the run, not a parser's guess afterwards.
72
+
73
+ A count may stay as **runaway protection**, commented as such (`PASS_CEILING = 60`, ≈2× the worst observed) and never
74
+ cited as the claim. Two related traps this surfaced: (a) a row whose assertion lives in a branch the harness never
75
+ reaches passes while asserting nothing — the unit plane cannot produce a real commit, because the base engine returns a
76
+ result only for a live `Session`, so pin such claims in the leg or on a pure function that is genuinely called; and
77
+ (b) a field printed from a config key the realm does not carry reads `?` forever — measure the shape you *read*
78
+ (#153's `window=?`).
79
+
55
80
  ### Correctness Checks
56
81
 
57
82
  | # | Check | Procedure | Passes when |
@@ -452,6 +477,18 @@ Run on a scratch clone of a real project (not this repo), at the pinned host and
452
477
  could never pass, and an unbounded `scrollIntoViewIfNeeded` that hung a leg for 17 minutes. Each
453
478
  looked like a product failure. **An unexercised assertion is a rumor of an assertion.**
454
479
 
480
+ ## Refusal output is grouped by class, with the remainder counted (#101)
481
+
482
+ `/chapters-repair` prints **one line per refusal class per session** via `renderRefusalGroups`
483
+ (`src/repair-run.ts`) — the count, up to three named examples, and `N more of the same class` when items
484
+ were withheld. Un-grouped, the command printed 21 identical `test-litter` refusals across 23 sessions:
485
+ 483 repeated lines that made 372 actionable findings unreadable in the maintainer's run, while the offline
486
+ runner had already been aggregating. Aggregation is presentation only — every item survives in
487
+ `groupRefusals`'s output, and a class with a single refusal prints plainly, with no `×1` ceremony.
488
+
489
+ If you add a refusal class, its line must carry the class name before the first `': '`: that is the grouping
490
+ key, and a class that does not follow it will not aggregate (it will not be hidden, just alone).
491
+
455
492
  ## One unreadable session must not stop a repair (#101)
456
493
 
457
494
  The kernel refuses to open a session log it considers invalid — measured 2026-10-24 when
package/lib/arrival.js CHANGED
@@ -19,6 +19,28 @@ export const ARRIVAL_MARKER = '[dsh:artifact';
19
19
  const kb = (n) => n < 1024 ? `${n} B` : `${(n / 1024).toFixed(1)} KB`;
20
20
  export async function applyArrivalStubs(session, opts) {
21
21
  let stubbed = 0;
22
+ // #131: resolve each result's tool name once, so an artifact ANSWER can be exempted below.
23
+ //
24
+ // Arrival-time deferral was applied to `chapters_artifact`'s own output: asking to read a stored blob returned
25
+ // ANOTHER stub pointing at ANOTHER blob, so the store became unreachable at exactly the sizes it exists for, and
26
+ // the `arrival` leg's model called the tool 20 times before the run gave up. A query answer is the payload the
27
+ // caller reached for — economizing it is a cycle, not context relief. The tool already bounds its own output per
28
+ // action (`limit`, `maxTokens`), so nothing needs a second layer here.
29
+ const nameByCall = new Map();
30
+ for (const seq of [...session.surface.nodes]) {
31
+ const ev = session.eventAt(seq);
32
+ if (ev?.type !== 'tool/call')
33
+ continue;
34
+ const d = ev.data;
35
+ if (typeof d?.callId === 'string' && typeof d?.name === 'string')
36
+ nameByCall.set(d.callId, d.name);
37
+ }
38
+ const isArtifactAnswer = (message) => {
39
+ const src = message.source;
40
+ const wrappers = Array.isArray(message.content) ? message.content : [];
41
+ const ids = [src?.callId, message.toolCallId, ...wrappers.map((w) => w?.toolCallId)];
42
+ return ids.some((id) => typeof id === 'string' && nameByCall.get(id) === 'chapters_artifact');
43
+ };
22
44
  for (const seq of [...session.surface.nodes]) {
23
45
  const event = session.eventAt(seq);
24
46
  if (event?.type !== 'tool/result')
@@ -52,6 +74,8 @@ export async function applyArrivalStubs(session, opts) {
52
74
  const text = carriers.map(textOf).join('');
53
75
  if (text.length === 0 || text.includes(ARRIVAL_MARKER))
54
76
  continue;
77
+ if (isArtifactAnswer(data.message))
78
+ continue; // #131 — a pointer to a pointer is not relief
55
79
  const tokens = opts.estimate(data.message);
56
80
  if (tokens < opts.floorTokens)
57
81
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"arrival.js","sourceRoot":"","sources":["../src/arrival.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"arrival.js","sourceRoot":"","sources":["../src/arrival.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The one user-role message of an auxiliary, out-of-band model call.
3
+ *
4
+ * Several features ask a model a question without entering a session: the post-relief plot elicitation in
5
+ * `engine.ts`, the bar's suggestion generators in `index.ts`. Their payload is a single user message streamed through
6
+ * `ctx.llm.stream(...)` — it is never admitted to a session log, so it makes no producer claim and needs no
7
+ * `plugin:*` kind.
8
+ *
9
+ * That distinction is the point of this file. Session format v4 retired the catch-all `source.kind: 'plugin'`
10
+ * (`@deepseek-ai/dsh-llm`'s `MessageSourceMap`: *"there is no shared catch-all `plugin` kind"*), and a bare `plugin`
11
+ * is refused at row admission on 0.2.x (#43). Four aux call sites still carried the retired spelling and passed every
12
+ * gate for two host minors, because the repo type-checked against 0.1.5-rc.2 while the rig boots 0.2.0-rc.2
13
+ * (`tests/unit/host-dep-pinning.test.ts` now forbids that drift). One helper, one honest kind.
14
+ */
15
+ import { createUserMessage } from '@deepseek-ai/dsh-llm';
16
+ /** @param text - the auxiliary prompt, verbatim. @returns a user-role message for a one-off `llm.stream` call. */
17
+ export declare function auxPromptMessage(text: string): ReturnType<typeof createUserMessage>;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The one user-role message of an auxiliary, out-of-band model call.
3
+ *
4
+ * Several features ask a model a question without entering a session: the post-relief plot elicitation in
5
+ * `engine.ts`, the bar's suggestion generators in `index.ts`. Their payload is a single user message streamed through
6
+ * `ctx.llm.stream(...)` — it is never admitted to a session log, so it makes no producer claim and needs no
7
+ * `plugin:*` kind.
8
+ *
9
+ * That distinction is the point of this file. Session format v4 retired the catch-all `source.kind: 'plugin'`
10
+ * (`@deepseek-ai/dsh-llm`'s `MessageSourceMap`: *"there is no shared catch-all `plugin` kind"*), and a bare `plugin`
11
+ * is refused at row admission on 0.2.x (#43). Four aux call sites still carried the retired spelling and passed every
12
+ * gate for two host minors, because the repo type-checked against 0.1.5-rc.2 while the rig boots 0.2.0-rc.2
13
+ * (`tests/unit/host-dep-pinning.test.ts` now forbids that drift). One helper, one honest kind.
14
+ */
15
+ import { createUserMessage } from '@deepseek-ai/dsh-llm';
16
+ /** @param text - the auxiliary prompt, verbatim. @returns a user-role message for a one-off `llm.stream` call. */
17
+ export function auxPromptMessage(text) {
18
+ return createUserMessage({ content: [{ type: 'text', text }], source: { kind: 'user' } });
19
+ }
20
+ //# sourceMappingURL=aux-message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aux-message.js","sourceRoot":"","sources":["../src/aux-message.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAExD,kHAAkH;AAClH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,iBAAiB,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,CAAA;AAC3F,CAAC"}