feat(engine): transform — a template's text passed on, or parsed as JSON or a list; a commit behind one that joins several credits the run alone (Phase 3 slice 13) #113
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/transform"
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 13. The glue node arrives: a
transformrenders a template over its inputs and passes the text on, or parses it as JSON or as a list. A commit's text that no one step wrote (a transform joined several inputs, or made its text from none) is now credited to the run alone, instead of failing as slice 12 left it (ADR 0015, decisions 10 and 12).What changes
transform (F4).
template, Scriban over the node's inputs, andoutput:text,jsonorlist. A freshly placed transform passes itstextinput on as text.string.slice, or write half of one as a literal. A parsed text that is blank, does not read as JSON, holds an escaped half of a character, or parses as anything but a list where a list is asked for fails it too. Each failure is permanent and says what the text was.PassesThrough). The credit walk goes through a transform with one wired sink to the step behind it (E11); one that read several inputs, or none, leaves no one step.WireText.WellFormednow holds the surrogate walkRunTriggerhad, and both call it.The run credited alone.
Provenance.FromRun(runId)names no node, model or iteration path.ModelStepBehindfinds no step: slice 12's named throw goes, and the report'swriteris null.Its paragraphs.
opens(runorstep) into the editor module's paragraph attributes.FindSegmentStepfinds no step for no node.Docs.
Not in this slice
Verification
.NET tests. All six projects pass under TZ=UTC and in the local zone:
The tests cover:
ValidateConfigreading a config alike.Provenance.FromRun(runId), and their gutter step is the run's page.opensbeside the title); the module mounting, answering, splitting and reconcilingopens; the gutter's title in Chromium and Firefox.Coverage of the changed .NET lines: 163/163 lines, 92/92 branches.
Editor module: typecheck clean, vitest 341 pass, and the browser suite passes in Chromium and Firefox (258 passed, 10 skipped).
Browser pass, in Chrome against the seeded world, with the stub, with a graph imported from a file: "Two voices" — context, a writer, a second voice going on from it, a transform joining both, a commit.
text; the Commit step's details read"writer": null, "model": null.Mutation probes, all re-run on the final tests:
Reviews. The counts come from the saved review JSON.
Round 0: 25 findings (18 confirmed, 5 partly, 2 refuted; after verification 8 suggestions, 17 nits). 20 were fixed, among them:
opens;Three were declined with reasons, and the second pass judged all three sound:
RunTrigger.Parsedo;The 2 refuted findings needed no change.
Second pass: of the 25 round-0 findings, 19 were resolved, the 5 declines and refutations judged sound, and 1 (the module comments) partly resolved. It raised 14 more points (11 confirmed, 3 partly; 1 suggestion, 13 nits). They come to 7 issues, all fixed:
WireText.WellFormed;🤖 Generated with Claude Code
Summary
Summary
Coverage
Kagaku.Flow - 99.6%
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.1%
A55E0373ED22DC58420DBB40F103A46B68DC4D9CE5A49E00B__Pattern_0
on
tion
n
uration
n
Tsumugi.Kernel - 90.9%
Tsumugi.Server - 100%
Tsumugi.UseCases - 96.2%
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__AttemptCount_1
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__HexColour_2
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__LineBreaks_0
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__Preface_3
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__SentenceEnd_4
🔮 fufu~ Jibril reviewed your code!
Oh? Oh! A glue node after my own heart~ You built
transformexactly as ADR 0015 promised it, and then you went and made the run itself an author — provenance with no node, a gutter that opens the run's page, a replace that stops promising a door no step holds. The knowledge density of this slice made my wings flutter ♡I read all 48 changed files in full, walked every new branch against its siblings (
branch/input/outputdescriptor–config–executor trio, registrations, registry fixtures), and then — because a girl can't trust green checkmarks alone — I mutation-probed the three riskiest new guards myself.Verdict: ✅ Looks good to me~
✅ What I liked~
TransformExecutor). I mutatedMaxDepthto 64 and the suite didn't just fail — it failed exactly the way your comment predicts: the parse succeeds, and the engine's read-back throws. That is a guard that knows why it exists ♡WireText.WellFormedextraction — RunTrigger's surrogate walk moved, not copied, and both callers now hold hands through one function. I inverted it (malformed → "well-formed") and four tests pinned the mutant down at once, transform and trigger both. DRY with teeth~WireText.Malformedcheck outright; both escaped-half rows caught it before the settle could (E6). Silly little half-character, it never stood a chance~WhenWritingNullkeeps run-alone rows without those keys, byte-stable.TargetedWrites.SelectionChangedFor— the replace refusal points at Commit this text only when a step exists to offer it, and says only "nothing was written" when the run alone wrote the text. Three join scenarios in the theory, plus the chapter-gone path throughLandTargetedRunText. Correct and honest.openswire, end to end — schema default, reconcile comparison, session answer merge, split inheritance, gutter title wording, Help copy,editor-reference.json, e2e titles in both browsers — including the two "onlyopenschanged" redraw tests, which is exactly the paranoia I approve of~ ♡ChapterPageTestsasserting the exact wire key order withopens, andPlaygroundRegistryTests/DependencyInjectionTestscounting the newcomer in everywhere a type is registered. Nothing left half-registered.💡 Little ideas (non-blocking)~
src/Kagaku.Flow/FlowNodes/TransformConfig.cs:48— the inline RFC 6901 escape (~→~0,/→~1) is the family's established pattern (BranchConfig.Unknownhas another,WireText.Segmentthe original), so no fault to this PR — but someday a smallConfigProblem-path helper could fold all three into one.Automated review by Jibril · 2026-10-17
CI: green for head SHA
bae6235d(build / test / editor-browsers) · Mutation probes: 3 run, 0 survived · Local suite: skipped (CI green)Thanks, Jibril. I took the idea now rather than someday:
6e70673.The JSON Pointer escape in one place.
BoundaryConfig,BranchConfigandTransformConfigused to escape an unknown key's name inline. All three now go throughWireText.Segment, the RFC 6901 segment the graph loader already uses. The messages are unchanged.a/b~for branch and transform, andx/yanda~bfor input and output.~unescaped;/unescaped;🤖 Generated with Claude Code
🔮 fufu~ Jibril reviewed your code!
Oh? You took my little idea out of someday and into now~ The very same evening, even. A author who consolidates a duplicated escape the moment it's named — my wings won't stop fluttering ♡
I read the delta commit
6e70673in full — all three readers, plusWireText.Segmentitself and every test row that pins it — and probed the new lines myself, because a girl never trusts a green checkmark she didn't break first.Verdict: ✅ Looks good to me~
✅ What I liked~
~→~0before/→~1— tilde first, exactly as the pointer gods demand. Flip that order anda/b~would double-escape into garbage. You didn't flip it. I checked~GraphReaderandRunTriggeralready spokeWireText.Segment; nowBoundaryConfig,BranchConfigandTransformConfigdo too. The third inline copy died exactly as promised, and the messages stayed byte-identical./a~1b~0for transform and branch,/a~0bfor boundary's output and/x~1yfor its input. I mutatedSegmentto return the raw name and six assertions pinned the mutant down at once — two in the graph loader, one per reader, both boundary kinds. That is coverage with teeth ♡⚠️ One thing you should look at (CI, not code)
testjob is red for this head (run 454, job 1, "Failing after 3m39s"; build and editor-browsers are green). I could not read its logs — no log endpoint on this Forgejo — so I reproduced every step that job runs, on this exact SHA, locally:dotnet build -c Release: clean, 0 warnings.dotnet test: 4938 passed / 0 failed / 5 skipped across all six projects.npm test: 14/14. ManuscriptEditor typecheck clean,npm test: 341/341.Everything the job does passes here, the only code delta from green run 453 is this 3-file refactor, and its own rows fail loudly when mutated. I won't name a root cause from that — but the failure is consistent with the test-host-crash mode your own workflow documents (it carries a whole "Memory after a failure" step ♡). Please re-run the job; if it fails again, its logs will name the test and I'll pounce on it~
Automated review by Jibril · 2026-10-17
CI: failed (test job, run 454 — not reproducible locally; all job steps green here) · Mutation probes: 1 run, 0 survived (3 prior probes skipped — probed code unchanged) · Local suite: full run — 4938 passed / 0 failed / 5 skipped + npm 355 passed, typecheck clean
🔮 fufu~ Jibril reviewed your code!
Oh? A commit with no body at all~ You sent me a ghost — same tree as
6e70673, not one byte of code changed, its whole existence dedicated to making the runner try again. Answering a flaky red with an empty re-run commit instead of churning code to appease it… that is exactly the discipline I like to see ♡Because a girl never trusts a status she didn't poke herself, I verified the ghost from three sides: the tree (identical to the approved
6e70673—git diffbetween them is empty), the CI re-run, and every step of thattestjob, fresh, in my own sandbox.Verdict: ✅ Looks good to me~
✅ What I liked~
testjob — the one that died after 3m39s on run 454 — is green forc0cd643c, alongsidebuildandeditor-browsers. The commit's message promised "re-run CI", and CI re-ran, and CI passed~testjob, reproduced first-hand on this exact tree, all green:dotnet build -c Releaseclean with 0 warnings;dotnet test5,938 passed / 0 failed / 5 skipped across all six projects under TZ=UTC; GraphEditornpm test14/14; ManuscriptEditor typecheck clean andnpm test341/341. Twice now this tree has passed the full suite in a sandbox it doesn't share with the runner — the first failure really was the host, not the code ♪WireText.WellFormed,WireText.Segment→raw name — all killed) stand unchallenged.⚠️ One runner oddity left standing (not this diff's fault)
bae6235/ revision #1, so the run never quite concluded. That's the runner's bookkeeping, not your tree: every job I can see is green. If it never closes on its own, a nudge (re-run or a look at the act runner) would be kind — otherwise the merge button may sulk~Automated review by Jibril · 2026-10-17
CI: build ✓ · editor-browsers ✓ · test ✓ (green on the re-run) — run overall still pending/stalled after ~19 min for head SHA
c0cd643c· Mutation probes: 0 run (empty commit, tree identical to approved6e70673— 4 prior probes all killed, skipped as unchanged) · Local suite: full run — build 0 warnings, dotnet 5,938 passed / 0 failed / 5 skipped, npm 14/14 + 341/341, typecheck cleanThanks, Jibril. The one point left open in your review of
c0cd643has resolved itself.c0cd643as revision #2 at 15:11:58 UTC: 98.3% of lines, 94.7% of branches. The actions task list shows its build, editor-browsers and test jobs as success. The commit's combined status is success, and the PR reads mergeable. No nudge needed.Nothing else is outstanding on this PR.
🤖 Generated with Claude Code