feat(graphs): the selection templates — Expand, Rewrite and Continue from here (Phase 3 slice 9) #109
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/selection-templates"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Phase 3's slice 9. The library now ships its three selection templates — Expand, Rewrite and Continue from here — so a right-click on a selection offers them on a fresh install (ADR 0023, 0030). This is the selection half of Phase 3's ships-when, and it ticks M5b.
What changes
The templates.
BundledGraphsgains Expand, Rewrite and Continue from here. They have fixed ids in the templates' reserved range and are re-seeded on every start beside Continue. All three have one shape:selectionandinstructioninputs;contextnode focused on the selection;llmon Continue's model, with the settings' effort;commitwhose target is the selection — a replace for Expand and Rewrite, an insertAfter for Continue from here.What the model is told.
run.selection, it also says when the selection begins or ends inside a paragraph. A selection that ends at the start of a later paragraph ends in the one before, as the commit has it, so nothing is said of it.The sample world. Two settled selection runs land on the first chapter, between the two runs of Continue:
Each has its run snapshot. Their rows were checked against real runs of the engine and the OpenRouter gateway over a scripted HTTP handler, and diffed. Only the seed's deliberate stand-ins differ: the served model, the provider, the generation ids and the service tier.
ContextBuilder.Buildis split out ofBuildAsync, so the seed assembles the focused context as the node does, and the seed renders the user message with Scriban as the node does.Docs.
Verification
.NET tests. All six projects pass under TZ=UTC and in the local zone:
The tests cover:
Coverage of the changed .NET lines: 144/144 lines. No branches are left on them.
Browser pass of the ships-when. It ran against the seeded world and the OpenRouter stub in Chrome. Two paragraphs were selected and Expand… was right-clicked with an instruction. The working state held both paragraphs while the run worked, and the stub's two paragraphs replaced them. The seeded runs read on the Runs list, the run page and History.
Mutation probes: 58 of 58 killed — 42 on the slice, 9 on the round-0 fixes and 7 on the second-pass fixes. One of the slice's survived its first run: it moved the writer row's finish past the commit's start. The seed test now checks each row's timing, and the mutant is killed.
Reviews. The counts come from the saved review JSON.
Round 0: 15 findings (10 confirmed, 5 partly; 8 suggestions, 7 nits). All 15 were fixed. The two the reviewers had called blockers were downgraded by the verifiers to suggestions. Both said Continue from here's prompt was unclear about where its text lands after a selection ending inside a paragraph. The main fixes:
Second pass: 14 of the 15 fixes held, and one partly. It raised 8 more points (5 confirmed, 3 partly; 4 suggestions, 4 nits). 8 of the 9 open points were fixed, the partly-held fix included. The main ones:
One was declined: see below.
Left open
A selection that ends at offset 0 of a paragraph after a scene break (A,
***, B) still reaches the model as a passage ending in***. The commit snaps it to A alone. So Expand may return the***and leave two scene breaks in a row, and Continue from here may open a new scene that lands before the break.Should it get a small follow-up (snapping the context as the commit does), or wait for the run page work?
🤖 Generated with Claude Code
Summary
Summary
Coverage
Kagaku.Flow - 99.5%
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__ColorToken_3
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__NodeId_2
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__Socket_1
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__TypeId_0
Kagaku.Flow.OpenRouter - 100%
Kagaku.Flow.Testing - 100%
Tsumugi.BlazorAdapter - 97.8%
Tsumugi.Domain - 96.6%
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__DigitsAndSeparators_2
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__LineBreak_0
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__NumberToken_1
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__Plain_4
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__ThousandsGroup_3
Tsumugi.Infrastructure - 99%
A55E0373ED22DC58420DBB40F103A46B68DC4D9CE5A49E00B__Pattern_0
on
tion
n
uration
n
Tsumugi.Kernel - 90.9%
Tsumugi.Server - 100%
Tsumugi.UseCases - 96%
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__AttemptCount_1
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__HexColour_2
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__LineBreaks_0
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__Preface_3
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__SentenceEnd_4
🔮 fufu~ Jibril reviewed your code!
Oh? Oh! Three templates, one
Selectionfactory, and a seed that threads a caret through the very sameReadSelectionthe menu uses~ ♪ This slice is tidy. Expand and Rewrite share a shape and differ only where they must, Continue from here earns its own insertAfter prose, and theRequest/Sentsplit actually removed duplication fromSeedRunswhile adding all this. That's the kind of diff I want to keep forever~ ♡Verdict: ✅ Looks good to me~
I read the full diff, every changed file in full, and the machinery underneath (
SelectionInput.Read's caret widening,SelectionTemplateModel'srun.selection.end.offset,LandTargetedRunText,ContextConfig's null margin) — and I didn't just trust the tests, I attacked them:BundledGraphs.EndsInside's offset guard — flippedend.offset > 0to>= 0. The "Continue from here, to the next paragraph's start" theory case caught it instantly (1/7 failed). The snap case is genuinely guarded, not decoratively~BeginsInside's{{ if }}guard — made it unconditional. Both whole-paragraph Expand cases failed (2/7). Killed~SeedRuns.Selected's context report — zeroedFollowingSegments.Seeds_an_Expand_run…failed on the pinned report constants. The seed really is diffed against the engine's shape, not just self-consistent~Three probes, three corpses, zero survivors. Fufu~ ♡
✅ What I liked~
BeginsInside/EndsInsideclauses encode a genuinely subtle rule — "an end at offset 0 of a later paragraph ends in the one before" — and every branch of it is pinned by an engine-running theory case with the exact rendered user message, with and without an instruction.ReadSelection→LandTargetedRunText→TakeRunSnapshot, the same path the host takes, so the sample world can't drift from reality. The caret at(second, 10)widening to the whole paragraph throughSelectionInput.Readis a lovely touch — it exercises the caret rule a real writer hits.ContextBuilder.Buildsplit out ofBuildAsyncwith the behavior identical, purely so the seed assembles context exactly as the node does — the right kind of refactor for this.The scene-break-adjacent focus (a selection ending at offset 0 after
***) left open in the description predates the slice and is correctly fenced off behind an ADR 0017 amendment — I agree it doesn't belong here.Automated review by Jibril · 2026-10-16
CI: green for head SHA
497e8996· Mutation probes: 3 run, 0 survived · Local suite: skipped (CI green)