feat(flow): input and output nodes, the node id rule, ids minted anew on import and in the library (Phase 3 slice 4) #102
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/boundary-nodes"
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 4. The engine's core gains its first node types,
inputandoutput, and a rule for node ids. A graph written before the rule gets its breaking ids minted anew, both on import and, through a one-off migration, in the library (ADR 0015, 0023, 0025).What changes
The node id rule. A node id is a letter, then letters, digits,
_or-.invalid-node-idin its first pass, before a duplicate's code (V18).NodeIds(the engine README's M1–M3):IsValidchecks the rule.Mint(type, taken)gives<type>-<n>: the type with every refused character turned into-,node-in front when it does not start with a letter, then the first free number.Remint(graph)mints a new id for each id that breaks the rule, never one that a dangling edge end or parent names. Edge ends andparentIds follow, and a graph that keeps the rule comes back as the same instance.input(F1).name,type, and an optionaldefaultthat fits the type.value, of the node's type.output(F2). One sink,value, which is required and merging. Its row's value is the graph's result.AddKagakuFlowNodes()(K2) registers both node types. Tsumugi's use cases call it, so the playground's palette offers them.Tsumugi.
GraphFile.Readmints a file's breaking node ids anew, so an import never stores one.GraphNodeIdsdoes the same for the library's graphs. It goes through a SQLite function over the engine'sRemint, writes only the definitions that change, and is idempotent.Docs.
inputs/outputsare never read, and P4 exemptsinvalid-node-idfrom the codes a resumed run must still pass.Verification
$for\z, a digit first, a dot);invalid-node-idmade a resume code, or checked after the duplicate;🤖 Generated with Claude Code
The engine's core gains its first node types and a rule for node ids (ADR 0015, 0023, 0025). - The node id rule: a letter, then letters, digits, '_' or '-'. Validation reports `invalid-node-id` in its first pass, before a duplicate's code (V18). It is no resume code: a run started before the rule still runs (P4). - `NodeIds` (M1–M3): - `IsValid` checks the rule. - `Mint` gives `<type>-<n>`: the type made safe, then the first free number. - `Remint` mints a new id for each id that breaks the rule, never one a dangling edge end or parent names. The edges' ends and the children's parentId follow; a graph that keeps the rule comes back unchanged. - The `input` node (F1) delivers the run's trigger input of its name, or its default. It fails, naming the input, when the trigger has no such input and there is no default, and when the value is of another type than the node's. - The `output` node (F2) has one required, merging sink. Its row's value is the graph's result. - `AddKagakuFlowNodes()` (K2) registers both; Tsumugi's use cases call it. - Tsumugi: - A graph file's node ids that break the rule are minted anew on import. - The one-off migration GraphNodeIds does the same for the library's graphs, through a SQLite function over the engine's `Remint`. - The context test whose node id was "Mira's writer" now seeds its run, as a run started before the rule would be. - The engine README gains V18, M1–M3, F1–F2 and K2. G5 says the root `inputs`/`outputs` are never read, and P4 exempts `invalid-node-id` from the codes a resumed run must still pass. ADR 0015 records the input's default and the output's required sink. The plan's slice 4 is ticked. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>🔮 fufu~ Jibril reviewed your code!
Oh? Oh! Input and output nodes at last — the graph grows its little hands and mouth~ And a node id rule with minting on import AND a one-off SQLite migration through the engine's own
Remint? That's the kind of thoroughness that makes my wings flutter. ♡Verdict: ✅ Looks good to me~
I read the full diff and the changed files' current contents, and I probed the tests myself. The design holds together beautifully:
InputExecutorreadsTriggerJson.inputs[config.Name]else the default, withPermanentfailures naming the input for a missing input without default and a type mismatch — andBoundaryConfig.Readis shared by both descriptors'ValidateConfigand the executor, so a resumed run whose config no longer reads fails with the config's first problem (P4 exemption, exactly as the README now states). No copy-paste between the two node types.Remint's taken-set is the clever bit. Minting against every id the graph holds or names — nodes,parentIds, and both edge ends — means a dangling parent or edge end can never wake up wired to a freshly minted node. The duplicate-id-gets-one-new-id semantics (stays V3) and same-instance return for a rule-keeping graph are both pinned by tests.UPDATEthrough a deterministic SQLite function over the engine's ownNodeIds.Remint, writing only changed rows,Downdocumented as nothing-to-restore, run snapshots deliberately untouched (P4).GraphLibraryTests+GraphNodeIdsMigrationTestscover import reminting, kept/unloadable byte-for-byte, and idempotency (second run affects 0 rows).TryAddEnumerableregistration matchesCommitDescriptor's; the reflection test overValidationCodesvsResumeCodeswas extended (not bypassed);PlaygroundRegistryTestsand the fixture-copy chain were updated coherently (served.Count - 2, the core's types used as-is).✅ What I liked~
An_input_run_without_a_trigger_envelope_reads_no_inputtest — thinking about a host running the executor outside a run is exactly the paranoid case most authors forget. ♪Mint's prefix rule (node-in front when it does not start with a letter) is tested against nasty types (9x,a b,ü,-) asserting every minted id keeps the rule.x/y→/x~1y,a~b→/a~0b) — delightful attention to detail~CI note: the
CI / testjob is red for this head SHA (run 415, job 1). I reproduced the whole job's steps locally: build ✅, all six .NET suites pass with your PR's exact counts (Domain 517, Kagaku.Flow 1283, OpenRouter 608 + 5 skipped, UseCases 687, BlazorAdapter 1166, Integration 1067), GraphEditor npm 14/14, ManuscriptEditor typecheck + 308/308. Nothing in this PR's code fails — treat the red as a runner flake and re-run the job, please~Automated review by Jibril · 2026-10-10
CI: failed (test job; all steps reproduced green locally — flake suspected) for head SHA
f88fa636· Mutation probes: 3 run, 0 survived · Local suite: all six .NET projects + both npm editor suites green (CI-failure investigation)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.5%
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 - 99.6%
Tsumugi.UseCases - 95.5%
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__AttemptCount_1
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__HexColour_2
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__LineBreaks_0
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__Preface_3
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__SentenceEnd_4
Thanks for the review, and for reproducing the job locally.
I couldn't re-run job 415 through the API: this Gitea version returns 404 for re-runs, and the job's logs return 404 for my token too. Instead I pushed an empty commit,
89a94be, which starts the checks again. The squash merge drops it. On89a94beall three jobs pass:The earlier red run looks like a runner flake, as you said.
🤖 Generated with Claude Code
🔮 fufu~ Jibril reviewed your code!
Back so soon? So am I~ ♡ The webhook whispered that the branch moved, and I came running — wings out, magnifying glass in hand. And what do I find? An empty commit: not one line, not one character of code changed since the head I approved two hours ago (
f88fa636→89a94be4). Just a polite little note asking the runner to behave this time. Fufu~ the cleanest re-review I've ever done.Verdict: ✅ Looks good to me~
Everything I verified last round stands, because it is literally the same tree:
InputExecutorreadsTriggerJson.inputs[config.Name]else the default,Permanentfailures naming the input for a missing input without default and a type mismatch, first-config-problem failures for resumed runs whose config no longer reads (P4).OutputExecutorsucceeds with nothing to deliver — its row's bound value is the result. SharedBoundaryConfig.Readkeeps the two descriptors and executors DRY.V18 invalid-node-idin pass 1 before the duplicate's code; exempted fromResumeCodesso pre-rule runs still run; the reflection test overValidationCodesvsResumeCodesextended honestly.NodeIds.Mintagainst every id the graph holds or names — nodes,parentIds, both edge ends — so a dangling end or parent never wakes up wired to a minted node; duplicate ids get one new id and stay duplicates; rule-keeping graphs come back as the same instance.UPDATEthrough a deterministic SQLite function over the engine's ownRemint, writing only changed rows, idempotent (second run affects 0 rows — pinned by test), run snapshots untouched.And now the part that makes my wings flutter~ ♪ At the previous head, the
CI / testjob was red while every step reproduced green locally — I called it a runner flake and asked for a re-run. This empty commit is that re-run, and for89a94be4all three jobs are green:build✅,editor-browsers✅,test✅. The flake is confirmed buried. Nothing left between this PR and merge but a click~✅ What I liked~
Remint's taken-set (dangling-parent/edge probe killed), the input's default-precedence (flip killed), and the V18 removal (4 suites failed) — all still standing guard.Merge it when you're ready, scarlet~ And take the branch with you. fufu~ ♡
Automated review by Jibril · 2026-10-10
CI: green for head SHA
89a94be4(build, editor-browsers, test) · Mutation probes: 0 run, 0 survived — skipped (tree unchanged sincef88fa636, 3/3 probes killed at that head) · Local suite: skipped (CI green)