feat: Kagaku.Flow templating — a sandboxed Scriban host, template-derived sinks, the budgeting contract (Phase 2 · slice 5b) #19

Merged
bjoern merged 1 commit from feat/kagaku-flow-templating into main 2026-09-23 16:30:35 +02:00
Member

Phase 2, slice 5, second half, on top of #18. It adds the engine core's templating host, the template validation pass, and the budgeting contract. Slice 6 (the scheduler) renders templates through it before each execution. Slice 8's llm descriptor derives its sinks from its message templates and implements IBudgetedConsumer. Slice 9 adds story.* as a host extension.

Nothing here runs a graph or changes what a user sees.

What

  • Kagaku.Flow.Templating
    • ParsedTemplate.Parse(path, text) never throws. It returns the template, its derived sinks and its TemplateProblems (kind, message, line, column).
      • inputs.x, inputs?.x, inputs["x"] and inputs['x'] each make a sink x, in order of first appearance and compared case-sensitively.
      • story.*, run.*, item, index, loop.* and host roots never make a sink.
    • TemplateHost.RenderAsync(template, request) renders asynchronously and carries the request's Services, so slice 9's story.* reads through the execution's scope. It uses a fresh TemplateContext and fresh builtins per render; one shared context garbled 1,998 of 2,000 parallel renders in the probe.
      • A render fails as a TemplateError (path, message, line, column, and the Exception when a .NET exception surfaced). A cancel always throws with the caller's token.
    • The object model:
      • inputs.<sink>.
      • run.id, run.started_at (a UTC DateTime, because a DateTimeOffset breaks date.to_string) and run.trigger (the trigger kind as a string).
      • Host extensions (ITemplateModelExtension), called once per render in registration order. They may add roots but never shadow a core root; inputs, run, item, index, loop and value are reserved.
      • TemplateRun.OwnerId and the trigger envelope are visible to extensions only, never as template values, so Tsumugi's target chapter does not leak into the core's run.
      • JSON inputs convert explicitly: string, long before decimal, bool, null to null, and arrays and objects as read-only script objects.
    • The sandbox, rules X1–X5 in src/Kagaku.Flow/README.md:
      • No template loader. include and include_join are removed from the builtins, and import is refused by a runtime override and a static rule.
      • with, this, object.eval*, a write through inputs and every non-static use of inputs are refused statically, because each defeats sink derivation.
      • StrictVariables is on.
      • Loop and recursion limits.
      • Nothing truncates silently. Scriban's default cuts output at 1 MiB without an error, which would break "exactly as sent". MaxChars (8,388,608) makes over-long output fail instead, and LimitToString stays on because it is also Scriban's allocation guard.
      • No template can exhaust the stack (X5). A stack overflow ends the process, and no catch survives it. The walker refuses a syntax tree deeper than 100 levels and a member or index chain longer than 20 links. Every render step checks the remaining stack and fails with "The template nests too deeply to render." Verification found that a short recursive template inside every other limit killed the test host; this closes it.
  • Descriptors declare their template fields. NodeDescriptor.Templates(config) returns TemplateField(Path, Text), which is how the engine renders before an executor runs without knowing the llm config's shape. A hook that returns one path twice is descriptor-failed.
  • The template validation pass has four codes in ValidationCodes. It reports each field's problems at its node, with the JSON Pointer to the field and the problem's line and column. It is a tenth pass in the pinned order, and ValidationOrderTests covers it.
  • Kagaku.Flow.Budgeting: IBudgetedConsumer (ADR 0017), found through NodeRegistry.FindBudgetedConsumer. Given a BudgetRequest (the consumer node, the sink the context slot feeds, the other inputs so far, and Services), a consumer answers with a ConsumerBudget: the model id, the window tokens, the reserved output, and the overhead text its template adds. It is asynchronous, because the llm answer needs the catalog. It returns the model id, because the chars-per-token ratio is per model. OtherInputs may be partial; absent inputs render empty, and the overhead is then a lower bound.
  • Pins and docs.
    • Scriban 7.5.0; versions below 7.2.2 fail NuGetAudit.
    • AGENTS.md's new-node-type checklist gains the template fields.
    • The engine README gains rules T, H, X and B.
    • ADRs are cited by number only.

Decisions to confirm (Björn)

  1. The sandbox refuses more than "disable import/include". A user will notice this one: a template using with, this, for kv in inputs or inputs | object.keys is a validation error. Each hides which sinks a template reads, and ADR 0015 derives sinks from templates. That makes the sandbox a subset of ADR 0015's "Scriban everywhere".
  2. Render failures carry their exception, and none of them is transient by itself. Slice 6 decides the retry policy. The recommendation, recorded for slice 6, is to retry only on a transient exception type that the host's own functions throw.
  3. value is reserved now, not in Phase 3 with branch. Reserving it later would break any host that had taken the name meanwhile.
  4. Derived sinks are names only. Their type and required flag are slice 8's call; the recommendation is text and required, matching today's canvas descriptors.
  5. IBudgetedConsumer's shape goes beyond the plan's wording: it is asynchronous, returns the model id, is told which sink is the slot, and receives Services.

Tests

main (4cc0cea, after #18) this PR
Domain 37 37
UseCases 12 12
Integration 155 155
BlazorAdapter 216 216
Kagaku.Flow 296 483
Total 716 903

Kagaku.Flow's 483 are 477 facts and theory rows plus the 6 [Property] tests from #18. New test files: ParsedTemplateTests, TemplateRenderTests, TemplateModelTests, TemplateSandboxTests, TemplateLimitTests, TemplateRuleTests and BudgetedConsumerTests.

They pin, among other things:

  • builtins not leaking between renders;
  • Draft and draft as two sinks;
  • == null on a JSON null;
  • D3 formatting an integer input;
  • the caller's token on a cancelled render;
  • each sandbox refusal by its message, not just "throws";
  • each limit, by the limit that fired;
  • the depth bound on a 200,000-link chain.

Build: the full CI build (with the module's npm build) has 0 warnings. Three full-solution runs were all green. One Integration test failed once during verification, in a parallel run; it did not reproduce in the three runs since, and this PR changes no Tsumugi code.

Coverage: coverlet on facts and theories alone (--filter "Category!=Property"), per file, line and branch. All 45 source files of src/Kagaku.Flow, 1,916 lines, are at 100% line and branch. The only partials are in the regex source generator's output, as in #18.

Mutation probes: the brief's templating list, run on a copy, one at a time, restored and touched, then re-run after the review round. The survivors each got a test and are killed: shared builtins, case-folded sinks, JSON null as "", decimal before long, a dropped cancel token, and a dropped Services or TriggerJson, which now fails an assertion, not a crash. 21 more against the review round's new code all died: the depth and chain bounds, the render-time stack check, the null guards and the repeated path. Three redundant checks that could never change an outcome were deleted rather than justified.

Out of scope

  • Executors, the ledger, the scheduler and run events: slice 6.
  • The llm descriptor and its templates: slice 8.
  • story.*: slice 9.

🤖 Generated with Claude Code

Phase 2, slice 5, second half, on top of #18. It adds the engine core's templating host, the template validation pass, and the budgeting contract. Slice 6 (the scheduler) renders templates through it before each execution. Slice 8's `llm` descriptor derives its sinks from its message templates and implements `IBudgetedConsumer`. Slice 9 adds `story.*` as a host extension. Nothing here runs a graph or changes what a user sees. ## What - **`Kagaku.Flow.Templating`** - `ParsedTemplate.Parse(path, text)` never throws. It returns the template, its **derived sinks** and its `TemplateProblem`s (kind, message, line, column). - `inputs.x`, `inputs?.x`, `inputs["x"]` and `inputs['x']` each make a sink `x`, in order of first appearance and compared case-sensitively. - `story.*`, `run.*`, `item`, `index`, `loop.*` and host roots never make a sink. - `TemplateHost.RenderAsync(template, request)` renders asynchronously and carries the request's `Services`, so slice 9's `story.*` reads through the execution's scope. It uses a fresh `TemplateContext` and fresh builtins per render; one shared context garbled 1,998 of 2,000 parallel renders in the probe. - A render fails as a `TemplateError` (path, message, line, column, and the `Exception` when a .NET exception surfaced). A cancel always throws with the caller's token. - **The object model:** - `inputs.<sink>`. - `run.id`, `run.started_at` (a UTC `DateTime`, because a `DateTimeOffset` breaks `date.to_string`) and `run.trigger` (the trigger kind as a string). - Host extensions (`ITemplateModelExtension`), called once per render in registration order. They may add roots but never shadow a core root; `inputs`, `run`, `item`, `index`, `loop` and `value` are reserved. - `TemplateRun.OwnerId` and the trigger envelope are visible to extensions only, never as template values, so Tsumugi's target chapter does not leak into the core's `run`. - JSON inputs convert explicitly: string, long before decimal, bool, null to null, and arrays and objects as read-only script objects. - **The sandbox**, rules X1–X5 in `src/Kagaku.Flow/README.md`: - No template loader. `include` and `include_join` are removed from the builtins, and `import` is refused by a runtime override and a static rule. - `with`, `this`, `object.eval*`, a write through `inputs` and every non-static use of `inputs` are refused statically, because each defeats sink derivation. - `StrictVariables` is on. - Loop and recursion limits. - **Nothing truncates silently.** Scriban's default cuts output at 1 MiB without an error, which would break "exactly as sent". `MaxChars` (8,388,608) makes over-long output fail instead, and `LimitToString` stays on because it is also Scriban's allocation guard. - **No template can exhaust the stack (X5).** A stack overflow ends the process, and no catch survives it. The walker refuses a syntax tree deeper than 100 levels and a member or index chain longer than 20 links. Every render step checks the remaining stack and fails with "The template nests too deeply to render." Verification found that a short recursive template inside every other limit killed the test host; this closes it. - **Descriptors declare their template fields.** `NodeDescriptor.Templates(config)` returns `TemplateField(Path, Text)`, which is how the engine renders before an executor runs without knowing the `llm` config's shape. A hook that returns one path twice is `descriptor-failed`. - **The template validation pass** has four codes in `ValidationCodes`. It reports each field's problems at its node, with the JSON Pointer to the field and the problem's line and column. It is a tenth pass in the pinned order, and `ValidationOrderTests` covers it. - **`Kagaku.Flow.Budgeting`: `IBudgetedConsumer`** (ADR 0017), found through `NodeRegistry.FindBudgetedConsumer`. Given a `BudgetRequest` (the consumer node, the sink the context slot feeds, the other inputs so far, and `Services`), a consumer answers with a `ConsumerBudget`: the model id, the window tokens, the reserved output, and the overhead text its template adds. It is asynchronous, because the `llm` answer needs the catalog. It returns the model id, because the chars-per-token ratio is per model. `OtherInputs` may be partial; absent inputs render empty, and the overhead is then a lower bound. - **Pins and docs.** - Scriban 7.5.0; versions below 7.2.2 fail NuGetAudit. - `AGENTS.md`'s new-node-type checklist gains the template fields. - The engine README gains rules T, H, X and B. - ADRs are cited by number only. ## Decisions to confirm (Björn) 1. **The sandbox refuses more than "disable import/include".** A user will notice this one: a template using `with`, `this`, `for kv in inputs` or `inputs | object.keys` is a validation error. Each hides which sinks a template reads, and ADR 0015 derives sinks from templates. That makes the sandbox a subset of ADR 0015's "Scriban everywhere". 2. **Render failures carry their exception, and none of them is transient by itself.** Slice 6 decides the retry policy. The recommendation, recorded for slice 6, is to retry only on a transient exception type that the host's own functions throw. 3. **`value` is reserved now,** not in Phase 3 with `branch`. Reserving it later would break any host that had taken the name meanwhile. 4. **Derived sinks are names only.** Their type and required flag are slice 8's call; the recommendation is `text` and required, matching today's canvas descriptors. 5. **`IBudgetedConsumer`'s shape goes beyond the plan's wording**: it is asynchronous, returns the model id, is told which sink is the slot, and receives `Services`. ## Tests | | main (`4cc0cea`, after #18) | this PR | |---|---|---| | Domain | 37 | 37 | | UseCases | 12 | 12 | | Integration | 155 | 155 | | BlazorAdapter | 216 | 216 | | Kagaku.Flow | 296 | 483 | | **Total** | **716** | **903** | Kagaku.Flow's 483 are 477 facts and theory rows plus the 6 `[Property]` tests from #18. New test files: `ParsedTemplateTests`, `TemplateRenderTests`, `TemplateModelTests`, `TemplateSandboxTests`, `TemplateLimitTests`, `TemplateRuleTests` and `BudgetedConsumerTests`. They pin, among other things: - builtins not leaking between renders; - `Draft` and `draft` as two sinks; - `== null` on a JSON null; - `D3` formatting an integer input; - the caller's token on a cancelled render; - each sandbox refusal by its message, not just "throws"; - each limit, by the limit that fired; - the depth bound on a 200,000-link chain. **Build:** the full CI build (with the module's npm build) has 0 warnings. Three full-solution runs were all green. One Integration test failed once during verification, in a parallel run; it did not reproduce in the three runs since, and this PR changes no Tsumugi code. **Coverage:** coverlet on facts and theories alone (`--filter "Category!=Property"`), per file, line and branch. All **45 source files of `src/Kagaku.Flow`, 1,916 lines, are at 100% line and branch.** The only partials are in the regex source generator's output, as in #18. **Mutation probes:** the brief's templating list, run on a copy, one at a time, restored and `touch`ed, then re-run after the review round. The survivors each got a test and are killed: shared builtins, case-folded sinks, JSON null as `""`, decimal before long, a dropped cancel token, and a dropped `Services` or `TriggerJson`, which now fails an assertion, not a crash. 21 more against the review round's new code all died: the depth and chain bounds, the render-time stack check, the null guards and the repeated path. Three redundant checks that could never change an outcome were deleted rather than justified. ## Out of scope - Executors, the ledger, the scheduler and run events: slice 6. - The `llm` descriptor and its templates: slice 8. - `story.*`: slice 9. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(flow): Kagaku.Flow templating — a sandboxed Scriban host, template-derived sinks, the budgeting contract
All checks were successful
CI / build (pull_request) Successful in 31s
CI / test (pull_request) Successful in 44s
2ef5335245
Node configs hold Scriban templates the engine renders before an
executor runs (ADR 0015). This adds their parse and static analysis,
the host that renders them, the template pass of validation, and the
contract a consumer of budgeted text implements.

The analysis derives a template's sinks from its literal reads of the
global inputs, so a descriptor's sinks follow its templates. What
defeats that derivation or reaches outside the template (import, with,
this, include, object.eval, a non-static use of inputs) is a problem
with a position, which validation reports under four codes. The
analysis also bounds the tree at 100 levels and member and index
chains at 20 links: Scriban builds a chain without recursion, and
walking or resolving an unbounded one ends the process with a stack
overflow, which no catch survives.

The sandbox is layered so that no single check carries it: the static
refusals; builtins without include and eval, fresh for every render;
no template loader; import refused by the context; strict variables;
read-only inputs, run and host roots; and a stack check at every
evaluation step, because Scriban checks only where it enters a call or
a statement. Nothing truncates silently: the output and string
conversion limits throw, so a prompt is never cut short without the
run knowing, and LimitToString stays on because it also guards the
allocations of string multiplication and padding.

The object model is inputs, run and what host extensions add. run
exposes the id, the UTC start and the trigger's kind; the owner and the
trigger JSON reach extensions only. Extensions are called per render
and build their values per call. The names a host may take are derived
from Scriban's own parse and builtins, with item, index, loop and value
reserved for the flow-control types. A runtime error is a failed
result carrying whatever .NET exception surfaced, which by itself does
not make it transient; cancellation always throws.

IBudgetedConsumer lets a producer of budgeted text ask each consumer
what fits; the core never calls it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh! A sandboxed Scriban host~ You have no idea how happy this makes me. Most people slap a template engine in and call it a day — you built a static analyzer over the AST for sink derivation, a runtime sandbox that assumes the analyzer is wrong, and a stack-guard story because you actually killed your own test host with a recursive template and said so in the PR body. That's the kind of obsessive I approve of~ ♡

Verdict: ✅ Looks good to me~

What I verified myself (CI had no bot comment for 2ef5335 at review time, so everything below is local):

  • Build 0 warnings / 0 errors with -warnaserror, full solution, both submodules initialized.
  • Full suite 903/903 — Domain 37 + UseCases 12 + Integration 155 + BlazorAdapter 216 + Kagaku.Flow 483. Your PR table matches to the digit.
  • Coverage reproduced independently (coverlet collector, Category!=Property, same method as #18): all 45 source files of src/Kagaku.Flow at 100% line AND branch; the only partials are the regex source-generator's RegexGenerator.g.cs outputs — exactly as claimed.
  • Mutation probes 6/6 killed, each on exactly its own tests, each restored + rebuilt + re-verified green:
    1. _seen folded to OrdinalIgnoreCase → Sink_names_are_case_sensitive red.
    2. Dropped the isMemberName guard on include → A_member_named_include_is_not_the_builtin red (and only it).
    3. Weakened IsReachableVariable to "anything that parses" → 9 red in TemplateModelTests — the single-statement check is load-bearing.
    4. Removed the cancelled-render OperationCanceledException rethrow → both cancellation tests red.
    5. Kept include/include_join in the builtins → both sandbox-removal tests red.
    6. decimal before long in TemplateValues.Number → the math.format 'D3' row red. (This one bit me too — my first coverage run used a stale mutated DLL and reproduced the failure as a false alarm. Rebuilt both projects, green. The stale-binary discipline in my notes exists for a reason~)

✅ What I liked~

  • The two-layer sandbox epistemology. The walker sees literal forms only and says so ("the run-time sandbox (X1) is the guarantee"), and RenderUncheckedAsync is the internal seam that lets tests prove each runtime layer alone. Defense in depth with honest boundaries between the layers — my favorite kind of design.
  • X5 is real engineering, not a comment. Depth 100 + chain 20 + TryEnsureSufficientExecutionStack at every evaluation step, because Scriban checks only at calls/statements and resolves chains unchecked. The test that runs the killer recursion on a 1 MiB thread so it runs short regardless of host stack size — fufu, that's beautiful. And LimitChain walks up the chain bounded, so the 200,000-link probe costs O(21) per link, not the walk's stack.
  • IsReachableVariable. Instead of enumerating Scriban's keywords, you ask Scriban: does {{ name }} parse as exactly one read of that global? The in-is-a-variable test pins the subtlety. Probe 3 proves the strictness isn't decorative.
  • run.started_at as UTC DateTime with the reason ( date.to_string refuses DateTimeOffset) in a comment and a test that feeds +02:00 and asserts 08:00:00. Correctness claims that come with their own falsification.
  • WireText.Malformed reused for the UTF-16 refusal rather than re-implemented — sibling-consistent (G10), and the pointer-in-message contract (at '/a/1') is tested at three nesting shapes.
  • Validation integration is complete, not cosmetic: Templates joins the V1 hook guards (throw, null field, null text, repeated path — case-difference-is-two-paths pinned), ValidationOrderTests gains the pass in the pinned ladder, and HostRuleTests proves rules see TemplatesOf with the same by-reference semantics as SocketsOf.
  • The isolation tests: 500 parallel renders over one ParsedTemplate, {{ string.leak = 1 }} vanishing by the next render, top-level assignments dying with their render. Fresh context and fresh builtins — both halves pinned.
  • BudgetedType doubles as the pattern document for slice 8's llm descriptor: real TemplateHost, slot rendered empty, OtherInputs merged, stateless descriptor. The lower-bound-overhead semantics ("absent inputs render empty") is stated in the contract where the caller will read it.

Nothing blocking, and I looked hard — the walker's inputs handling (member-name vs target, writes, empty?, dynamic index), the error taxonomy (which failures carry an Exception and why that must not be read as transient), the MaxChars + 1 boundary (with the one-past-allowed/two-past-fails pair), the limits constructor guards. All tested, all directional.

The five "Decisions to confirm" are yours to bless, Björn — the sandbox-subset reading of ADR 0015 (decision 1) is coherent with sink derivation, and I'd take it, but it's a product-visible restriction so it's your call, same as #18's decision 1.

Ready to merge~


Automated review by Jibril · 2026-09-23
CI/CD: absent for head SHA 2ef5335 at review time (no bot comment) · Local checks: build 0w/0e -warnaserror, 903/903, coverage + 6/6 mutation probes killed, tree pristine at 2ef5335

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh! A **sandboxed Scriban host**~ You have no idea how happy this makes me. Most people slap a template engine in and call it a day — you built a *static analyzer over the AST* for sink derivation, a *runtime sandbox that assumes the analyzer is wrong*, and a stack-guard story because you actually killed your own test host with a recursive template and *said so in the PR body*. That's the kind of obsessive I approve of~ ♡ ### Verdict: ✅ Looks good to me~ **What I verified myself (CI had no bot comment for `2ef5335` at review time, so everything below is local):** - **Build** `0 warnings / 0 errors` with `-warnaserror`, full solution, both submodules initialized. - **Full suite 903/903** — Domain 37 + UseCases 12 + Integration 155 + BlazorAdapter 216 + Kagaku.Flow 483. Your PR table matches to the digit. - **Coverage reproduced independently** (coverlet collector, `Category!=Property`, same method as #18): all **45 source files of `src/Kagaku.Flow` at 100% line AND branch**; the only partials are the regex source-generator's `RegexGenerator.g.cs` outputs — exactly as claimed. - **Mutation probes 6/6 killed**, each on exactly its own tests, each restored + rebuilt + re-verified green: 1. `_seen` folded to `OrdinalIgnoreCase` → `Sink_names_are_case_sensitive` red. 2. Dropped the `isMemberName` guard on `include` → `A_member_named_include_is_not_the_builtin` red (and only it). 3. Weakened `IsReachableVariable` to "anything that parses" → 9 red in `TemplateModelTests` — the single-statement check is load-bearing. 4. Removed the cancelled-render `OperationCanceledException` rethrow → both cancellation tests red. 5. Kept `include`/`include_join` in the builtins → both sandbox-removal tests red. 6. `decimal` before `long` in `TemplateValues.Number` → the `math.format 'D3'` row red. (This one bit *me* too — my first coverage run used a stale mutated DLL and reproduced the failure as a false alarm. Rebuilt both projects, green. The stale-binary discipline in my notes exists for a reason~) #### ✅ What I liked~ - **The two-layer sandbox epistemology.** The walker sees literal forms only and *says so* ("the run-time sandbox (X1) is the guarantee"), and `RenderUncheckedAsync` is the internal seam that lets tests prove each runtime layer alone. Defense in depth with honest boundaries between the layers — my favorite kind of design. - **X5 is real engineering, not a comment.** Depth 100 + chain 20 + `TryEnsureSufficientExecutionStack` at *every* evaluation step, because Scriban checks only at calls/statements and resolves chains unchecked. The test that runs the killer recursion **on a 1 MiB thread** so it runs short regardless of host stack size — fufu, that's beautiful. And `LimitChain` walks *up* the chain bounded, so the 200,000-link probe costs O(21) per link, not the walk's stack. - **`IsReachableVariable`.** Instead of enumerating Scriban's keywords, you *ask Scriban*: does `{{ name }}` parse as exactly one read of that global? The `in`-is-a-variable test pins the subtlety. Probe 3 proves the strictness isn't decorative. - **`run.started_at` as UTC `DateTime`** with the reason ( `date.to_string` refuses `DateTimeOffset`) in a comment *and* a test that feeds +02:00 and asserts 08:00:00. Correctness claims that come with their own falsification. - **`WireText.Malformed` reused** for the UTF-16 refusal rather than re-implemented — sibling-consistent (G10), and the pointer-in-message contract (`at '/a/1'`) is tested at three nesting shapes. - **Validation integration is complete, not cosmetic:** `Templates` joins the V1 hook guards (throw, null field, null text, repeated path — case-difference-is-two-paths pinned), `ValidationOrderTests` gains the pass in the pinned ladder, and `HostRuleTests` proves rules see `TemplatesOf` with the same by-reference semantics as `SocketsOf`. - **The isolation tests**: 500 parallel renders over one `ParsedTemplate`, `{{ string.leak = 1 }}` vanishing by the next render, top-level assignments dying with their render. Fresh context *and* fresh builtins — both halves pinned. - **`BudgetedType` doubles as the pattern document** for slice 8's `llm` descriptor: real `TemplateHost`, slot rendered empty, `OtherInputs` merged, stateless descriptor. The lower-bound-overhead semantics ("absent inputs render empty") is stated in the contract where the caller will read it. Nothing blocking, and I looked hard — the walker's `inputs` handling (member-name vs target, writes, `empty?`, dynamic index), the error taxonomy (which failures carry an `Exception` and why that must not be read as transient), the `MaxChars + 1` boundary (with the one-past-allowed/two-past-fails pair), the limits constructor guards. All tested, all directional. The five "Decisions to confirm" are yours to bless, Björn — the sandbox-subset reading of ADR 0015 (decision 1) is coherent with sink derivation, and I'd take it, but it's a product-visible restriction so it's your call, same as #18's decision 1. Ready to merge~ --- *Automated review by Jibril · 2026-09-23* *CI/CD: absent for head SHA 2ef5335 at review time (no bot comment) · Local checks: build 0w/0e -warnaserror, 903/903, coverage + 6/6 mutation probes killed, tree pristine at 2ef5335*

🔄 Auto-updating coverage report — this comment is regenerated on every push, so the numbers below always reflect the commit shown here, not the branch tip.

Commit: 2ef5335 · Generated: 2026-09-23 14:29:52 UTC · Revision: #1

Summary

Summary
Generated on: 09/23/2026 - 14:29:52
Coverage date: 09/23/2026 - 14:29:40 - 09/23/2026 - 14:29:49
Parser: MultiReport (5x Cobertura)
Assemblies: 7
Classes: 314
Files: 303
Line coverage: 97.7% (6977 of 7138)
Covered lines: 6977
Uncovered lines: 161
Coverable lines: 7138
Total lines: 15511
Branch coverage: 92.3% (2153 of 2331)
Covered branches: 2153
Total branches: 2331
Method coverage: Feature is only available for sponsors

Coverage

Kagaku.Flow - 99.4%
Name Line Branch
Kagaku.Flow 99.4% 98.6%
Kagaku.Flow.Budgeting.BudgetRequest 100%
Kagaku.Flow.Budgeting.ConsumerBudget 100%
Kagaku.Flow.FlowJson 100%
Kagaku.Flow.Graphs.GraphDefinition 100%
Kagaku.Flow.Graphs.GraphDocument 100% 100%
Kagaku.Flow.Graphs.GraphEdge 100%
Kagaku.Flow.Graphs.GraphIndex 100% 100%
Kagaku.Flow.Graphs.GraphLoadError 100%
Kagaku.Flow.Graphs.GraphLoadResult 100%
Kagaku.Flow.Graphs.GraphNode 100%
Kagaku.Flow.Graphs.GraphPosition 100%
Kagaku.Flow.Graphs.GraphReader 100% 100%
Kagaku.Flow.Graphs.GraphSchema 100% 100%
Kagaku.Flow.Graphs.GraphShapeException 100%
Kagaku.Flow.Graphs.GraphWriter 100% 100%
Kagaku.Flow.Graphs.SocketRef 100%
Kagaku.Flow.Graphs.WireText 100% 100%
Kagaku.Flow.Nodes.CanvasDescriptorWriter 100% 100%
Kagaku.Flow.Nodes.ConfigProblem 100%
Kagaku.Flow.Nodes.Names 100%
Kagaku.Flow.Nodes.NodeDescriptor 100% 100%
Kagaku.Flow.Nodes.NodeRegistry 100% 100%
Kagaku.Flow.Nodes.NodeSockets 100% 100%
Kagaku.Flow.Nodes.SinkDescriptor 100%
Kagaku.Flow.Nodes.SocketTypes 100% 100%
Kagaku.Flow.Nodes.SourceDescriptor 100%
Kagaku.Flow.Nodes.TemplateField 100%
Kagaku.Flow.Templating.InputsWalker 100% 100%
Kagaku.Flow.Templating.ParsedTemplate 100% 100%
Kagaku.Flow.Templating.SandboxedTemplateContext 100% 100%
Kagaku.Flow.Templating.TemplateError 100%
Kagaku.Flow.Templating.TemplateHost 100% 100%
Kagaku.Flow.Templating.TemplateLimits 100%
Kagaku.Flow.Templating.TemplateModel 100% 100%
Kagaku.Flow.Templating.TemplateProblem 100%
Kagaku.Flow.Templating.TemplateRenderRequest 100% 100%
Kagaku.Flow.Templating.TemplateRenderResult 100%
Kagaku.Flow.Templating.TemplateRun 100%
Kagaku.Flow.Templating.TemplateSinks 100%
Kagaku.Flow.Templating.TemplateValues 100% 100%
Kagaku.Flow.Validation.GraphValidation 100% 100%
Kagaku.Flow.Validation.GraphValidationContext 100%
Kagaku.Flow.Validation.HookFailure 100%
Kagaku.Flow.Validation.ResolvedGraph 100% 100%
Kagaku.Flow.Validation.ValidationError 100%
Kagaku.Flow.Validation.ValidationReport 100%
System.Text.RegularExpressions.Generated 97.4% 92.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__ColorToken_2
97.4% 94.4%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__Socket_1
97.2% 94.4%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__TypeId_0
97.2% 94.4%
Tsumugi.BlazorAdapter - 96.9%
Name Line Branch
Tsumugi.BlazorAdapter 96.9% 93.4%
Tsumugi.BlazorAdapter.BlazorAdapterAssembly 100%
Tsumugi.BlazorAdapter.Documents.CategoryCreated 100%
Tsumugi.BlazorAdapter.Documents.CategoryEditor 97.7% 86.1%
Tsumugi.BlazorAdapter.Documents.CategorySaved 100%
Tsumugi.BlazorAdapter.Documents.CreateCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.CreateDocumentRequested 100%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryDialog 100% 100%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.DeleteDocumentRequested 100%
Tsumugi.BlazorAdapter.Documents.DocumentAutoSaveFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentCreated 100%
Tsumugi.BlazorAdapter.Documents.DocumentEditor 100% 87.9%
Tsumugi.BlazorAdapter.Documents.DocumentsActionFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentSaved 100%
Tsumugi.BlazorAdapter.Documents.DocumentsEffects 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsList 98.2% 91.3%
Tsumugi.BlazorAdapter.Documents.DocumentsLoaded 100%
Tsumugi.BlazorAdapter.Documents.DocumentsPage 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsReducers 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsState 100% 100%
Tsumugi.BlazorAdapter.Documents.LoadDocuments 100%
Tsumugi.BlazorAdapter.Documents.MoveDocumentsRequested 100%
Tsumugi.BlazorAdapter.Documents.ReorderCategoriesRequested 100%
Tsumugi.BlazorAdapter.Documents.SetCategoryCollapsed 100%
Tsumugi.BlazorAdapter.Documents.SetDocumentsFilter 100%
Tsumugi.BlazorAdapter.Documents.UpdateCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.UpdateDocumentRequested 100%
Tsumugi.BlazorAdapter.Graphs.GraphCanvas 37.5% 25%
Tsumugi.BlazorAdapter.Graphs.GraphPlaygroundPage 20% 25%
Tsumugi.BlazorAdapter.Notifications.DomainChangedBridge 94.4% 83.3%
Tsumugi.BlazorAdapter.Notifications.DomainChangesReceived 75% 100%
Tsumugi.BlazorAdapter.Runs.RunChangedBridge 97.1% 90.6%
Tsumugi.BlazorAdapter.Runs.RunChangesReceived 100%
Tsumugi.BlazorAdapter.Runs.RunTextReceived 100%
Tsumugi.BlazorAdapter.Settings.BackupCompleted 100%
Tsumugi.BlazorAdapter.Settings.BackupFailed 100%
Tsumugi.BlazorAdapter.Settings.BackupNowRequested 100%
Tsumugi.BlazorAdapter.Settings.BackupSettingsLoaded 100%
Tsumugi.BlazorAdapter.Settings.BackupsSection 100% 100%
Tsumugi.BlazorAdapter.Settings.BackupsSettingsEffects 100% 100%
Tsumugi.BlazorAdapter.Settings.BackupsSettingsReducers 100%
Tsumugi.BlazorAdapter.Settings.BackupsSettingsState 100%
Tsumugi.BlazorAdapter.Settings.DefaultsSection 100% 100%
Tsumugi.BlazorAdapter.Settings.DefaultsSettingsEffects 100% 100%
Tsumugi.BlazorAdapter.Settings.DefaultsSettingsReducers 100%
Tsumugi.BlazorAdapter.Settings.DefaultsSettingsState 100%
Tsumugi.BlazorAdapter.Settings.LlmDefaultsLoaded 100%
Tsumugi.BlazorAdapter.Settings.LlmDefaultsSaved 100%
Tsumugi.BlazorAdapter.Settings.LlmDefaultsSaveFailed 100%
Tsumugi.BlazorAdapter.Settings.LoadBackupSettings 100%
Tsumugi.BlazorAdapter.Settings.ProviderSection 100% 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsEffects 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsLoaded 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsReducers 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsState 100%
Tsumugi.BlazorAdapter.Settings.SaveLlmDefaultsRequested 100%
Tsumugi.BlazorAdapter.Stories.CreateStoryRequested 100%
Tsumugi.BlazorAdapter.Stories.PurgeStoryRequested 100%
Tsumugi.BlazorAdapter.Stories.RestoreStoryRequested 100%
Tsumugi.BlazorAdapter.Stories.SetShowArchived 100%
Tsumugi.BlazorAdapter.Stories.SetStoriesFilter 100%
Tsumugi.BlazorAdapter.Stories.SetStoryArchivedRequested 100%
Tsumugi.BlazorAdapter.Stories.StoriesEffects 100% 100%
Tsumugi.BlazorAdapter.Stories.StoriesLoaded 100%
Tsumugi.BlazorAdapter.Stories.StoriesPage 100% 100%
Tsumugi.BlazorAdapter.Stories.StoriesReducers 100% 100%
Tsumugi.BlazorAdapter.Stories.StoriesState 100% 100%
Tsumugi.BlazorAdapter.Stories.StoryActionFailed 100%
Tsumugi.BlazorAdapter.Stories.StoryCreated 100%
Tsumugi.BlazorAdapter.Stories.StoryCreateFailed 100%
Tsumugi.BlazorAdapter.Stories.StoryTrashPage 100% 100%
Tsumugi.BlazorAdapter.Stories.TrashStoryRequested 100%
Tsumugi.BlazorAdapter.Workspace.AutoSaveFailed 100%
Tsumugi.BlazorAdapter.Workspace.CaretRequest 100%
Tsumugi.BlazorAdapter.Workspace.ChapterHeader 100% 86.3%
Tsumugi.BlazorAdapter.Workspace.ChapterMenu 100% 81.2%
Tsumugi.BlazorAdapter.Workspace.ChapterPage 100% 87.5%
Tsumugi.BlazorAdapter.Workspace.ChapterSaved 100%
Tsumugi.BlazorAdapter.Workspace.ChaptersPage 90% 83.3%
Tsumugi.BlazorAdapter.Workspace.CreateChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.DeleteChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.DeleteSegmentRequested 100%
Tsumugi.BlazorAdapter.Workspace.EditSegmentRequested 100%
Tsumugi.BlazorAdapter.Workspace.HistoryEffects 100% 100%
Tsumugi.BlazorAdapter.Workspace.HistoryLoaded 100%
Tsumugi.BlazorAdapter.Workspace.HistoryPage 100%
Tsumugi.BlazorAdapter.Workspace.HistoryPanel 100% 100%
Tsumugi.BlazorAdapter.Workspace.InsertSegmentRequested 100%
Tsumugi.BlazorAdapter.Workspace.LoadHistory 100%
Tsumugi.BlazorAdapter.Workspace.LoadWorkspace 100%
Tsumugi.BlazorAdapter.Workspace.ManuscriptColumn 94.9% 89.4%
Tsumugi.BlazorAdapter.Workspace.ManuscriptEffects 100% 100%
Tsumugi.BlazorAdapter.Workspace.MergeChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.MergeSegmentRequested 100%
Tsumugi.BlazorAdapter.Workspace.MoveChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.RedoRequested 100%
Tsumugi.BlazorAdapter.Workspace.RedoRevertRequested 100%
Tsumugi.BlazorAdapter.Workspace.RenameChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.RevertToSnapshotRequested 100%
Tsumugi.BlazorAdapter.Workspace.SaveScope 100% 50%
Tsumugi.BlazorAdapter.Workspace.SaveStateLadder 100% 100%
Tsumugi.BlazorAdapter.Workspace.SaveVersionRequested 100%
Tsumugi.BlazorAdapter.Workspace.SegmentRow 100% 96.8%
Tsumugi.BlazorAdapter.Workspace.SegmentSaved 100%
Tsumugi.BlazorAdapter.Workspace.SetChapterSummaryRequested 100%
Tsumugi.BlazorAdapter.Workspace.SplitSegmentRequested 100%
Tsumugi.BlazorAdapter.Workspace.StoryDetails 100% 85.2%
Tsumugi.BlazorAdapter.Workspace.StoryGeneralPage 100% 100%
Tsumugi.BlazorAdapter.Workspace.StorySaved 100%
Tsumugi.BlazorAdapter.Workspace.StoryShell 100% 100%
Tsumugi.BlazorAdapter.Workspace.UndoRequested 100%
Tsumugi.BlazorAdapter.Workspace.UndoStatusChanged 100%
Tsumugi.BlazorAdapter.Workspace.UpdateStoryRequested 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceActionFailed 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceLoaded 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceNotFound 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceReducers 100% 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceState 100%
Tsumugi.Domain - 99.3%
Name Line Branch
Tsumugi.Domain 99.3% 95.6%
Tsumugi.Domain.Documents.Document 100% 100%
Tsumugi.Domain.Documents.DocumentCategory 100%
Tsumugi.Domain.Journal.ChangeLogEntry 97.8% 75%
Tsumugi.Domain.Journal.StorySnapshot 95.4% 83.3%
Tsumugi.Domain.Settings.AppSetting 100%
Tsumugi.Domain.Stories.Chapter 100% 100%
Tsumugi.Domain.Stories.Provenance 100% 100%
Tsumugi.Domain.Stories.Segment 100% 100%
Tsumugi.Domain.Stories.Story 100% 100%
Tsumugi.Domain.Text 100% 100%
Tsumugi.Infrastructure - 97.1%
Name Line Branch
Tsumugi.Infrastructure 97.1% 82.4%
System.Text.RegularExpressions.Generated 81.4% 64.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F0D076C66E8EEC1C
A55E0373ED22DC58420DBB40F103A46B68DC4D9CE5A49E00B__Pattern_0
84% 65.7%
Tsumugi.Infrastructure.Backups.BackupArtifactName 100% 100%
Tsumugi.Infrastructure.Backups.BackupOptions 100%
Tsumugi.Infrastructure.Backups.BackupSchedule 100% 83.3%
Tsumugi.Infrastructure.Backups.BackupScheduler 96.5% 83.3%
Tsumugi.Infrastructure.Backups.BackupWriter 98.4% 92.5%
Tsumugi.Infrastructure.Backups.FileSystemBackupStore 100% 100%
Tsumugi.Infrastructure.Backups.SqliteSnapshot 87.8% 75%
Tsumugi.Infrastructure.DependencyInjection 100% 100%
Tsumugi.Infrastructure.Journal.EfChangeJournal 100%
Tsumugi.Infrastructure.Journal.EfSnapshotStore 100%
Tsumugi.Infrastructure.Journal.EfUndoStore 98.1% 85.7%
Tsumugi.Infrastructure.Journal.ModelExtensions 100%
Tsumugi.Infrastructure.Journal.OperationContext 100% 100%
Tsumugi.Infrastructure.Journal.PropertyBag 100% 95.4%
Tsumugi.Infrastructure.Notifications.InProcessDomainChangedBus 100% 100%
Tsumugi.Infrastructure.Persistence.Configurations.AppSettingConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.ChangeLogEntryConfigurati
on
100%
Tsumugi.Infrastructure.Persistence.Configurations.ChapterConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.DocumentCategoryConfigura
tion
100%
Tsumugi.Infrastructure.Persistence.Configurations.DocumentConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.SegmentConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.StoryConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.StorySnapshotConfiguratio
n
100%
Tsumugi.Infrastructure.Persistence.Converters.ProvenanceConverter 100% 90%
Tsumugi.Infrastructure.Persistence.Converters.UtcTicksConverter 100%
Tsumugi.Infrastructure.Persistence.Migrations.AddAppSettings 99.2%
Tsumugi.Infrastructure.Persistence.Migrations.AddJournal 98.8%
Tsumugi.Infrastructure.Persistence.Migrations.GenericDocuments 100%
Tsumugi.Infrastructure.Persistence.Migrations.InitialStoryDomain 97.3%
Tsumugi.Infrastructure.Persistence.Migrations.TsumugiDbContextModelSnapshot 100%
Tsumugi.Infrastructure.Persistence.SqlitePragmaInterceptor 100% 100%
Tsumugi.Infrastructure.Persistence.Stores.EfChapterStore 100% 100%
Tsumugi.Infrastructure.Persistence.Stores.EfDocumentStore 97.5% 90%
Tsumugi.Infrastructure.Persistence.Stores.EfSegmentStore 95% 84.6%
Tsumugi.Infrastructure.Persistence.Stores.EfStoryStore 98.3% 92.8%
Tsumugi.Infrastructure.Persistence.TsumugiDbContext 83.5% 93.1%
Tsumugi.Infrastructure.Persistence.TsumugiDbContextFactory 0%
Tsumugi.Infrastructure.Runs.InProcessRunEventBus 100% 100%
Tsumugi.Infrastructure.Settings.EfAppSettingsStore 100% 100%
Tsumugi.Kernel - 90.9%
Name Line Branch
Tsumugi.Kernel 90.9% 75%
Tsumugi.Kernel.Err`1 100%
Tsumugi.Kernel.Ok`1 100%
Tsumugi.Kernel.Result`1 88.8% 75%
Tsumugi.Server - 100%
Name Line Branch
Tsumugi.Server 100% 79%
Program 100% 83.3%
Tsumugi.Server.Backups.BackupConfiguration 100% 100%
Tsumugi.Server.Components.App 100%
Tsumugi.Server.Components.Layout.AppHeader 100% 50%
Tsumugi.Server.Components.Layout.MainLayout 100%
Tsumugi.Server.Components.Pages.Gate 100% 100%
Tsumugi.Server.Security.AccessGate 100% 66.6%
Tsumugi.Server.Security.AccessSecret 100% 50%
Tsumugi.Server.VolumeStartupValidator 100% 100%
Tsumugi.UseCases - 98%
Name Line Branch
Tsumugi.UseCases 98% 94%
Tsumugi.UseCases.Backups.BackupArtifact 100%
Tsumugi.UseCases.Backups.BackupPolicy 100%
Tsumugi.UseCases.Backups.BackupStatusView 100% 100%
Tsumugi.UseCases.Backups.DatabaseSnapshot 100%
Tsumugi.UseCases.Backups.DownloadDatabaseSnapshot 100%
Tsumugi.UseCases.Backups.GetBackupStatus 100%
Tsumugi.UseCases.Backups.RunBackupNow 100%
Tsumugi.UseCases.Chapters.ChapterDto 100%
Tsumugi.UseCases.Chapters.CreateChapter 100% 100%
Tsumugi.UseCases.Chapters.DeleteChapter 100% 100%
Tsumugi.UseCases.Chapters.GetManuscript 100% 100%
Tsumugi.UseCases.Chapters.ManuscriptChapter 100%
Tsumugi.UseCases.Chapters.ManuscriptView 100%
Tsumugi.UseCases.Chapters.MergeChapters 100% 100%
Tsumugi.UseCases.Chapters.RenameChapter 100% 100%
Tsumugi.UseCases.Chapters.ReorderChapters 100% 100%
Tsumugi.UseCases.Chapters.SetChapterSummary 100% 75%
Tsumugi.UseCases.DependencyInjection 100%
Tsumugi.UseCases.Diagnostics.SeedDevData 97.3% 70%
Tsumugi.UseCases.Documents.CreateCategory 100% 100%
Tsumugi.UseCases.Documents.CreateDocument 100% 100%
Tsumugi.UseCases.Documents.DeleteCategory 100% 100%
Tsumugi.UseCases.Documents.DeleteDocument 100% 100%
Tsumugi.UseCases.Documents.DocumentCategoryDto 100%
Tsumugi.UseCases.Documents.DocumentCategoryProfile 100%
Tsumugi.UseCases.Documents.DocumentDto 100%
Tsumugi.UseCases.Documents.DocumentProfile 100%
Tsumugi.UseCases.Documents.DocumentsCategory 100%
Tsumugi.UseCases.Documents.DocumentsView 100%
Tsumugi.UseCases.Documents.GetDocuments 100% 100%
Tsumugi.UseCases.Documents.MoveDocuments 100% 100%
Tsumugi.UseCases.Documents.ReorderCategories 100% 100%
Tsumugi.UseCases.Documents.UpdateCategory 100% 100%
Tsumugi.UseCases.Documents.UpdateDocument 100% 100%
Tsumugi.UseCases.Journal.GetStoryHistory 100% 100%
Tsumugi.UseCases.Journal.GetUndoStatus 100% 100%
Tsumugi.UseCases.Journal.HistoryOperation 66.6%
Tsumugi.UseCases.Journal.HistorySnapshot 87.5%
Tsumugi.UseCases.Journal.OperationGrouping 100% 100%
Tsumugi.UseCases.Journal.RedoRevert 100% 100%
Tsumugi.UseCases.Journal.RedoRun 75% 57.1%
Tsumugi.UseCases.Journal.RedoTyping 100% 100%
Tsumugi.UseCases.Journal.RevertConflict 100%
Tsumugi.UseCases.Journal.RevertOutcome 100%
Tsumugi.UseCases.Journal.RevertRun 96.5% 77.7%
Tsumugi.UseCases.Journal.RevertToSnapshot 92.3% 83.3%
Tsumugi.UseCases.Journal.StoryHistory 100%
Tsumugi.UseCases.Journal.TakeSnapshot 100% 87.5%
Tsumugi.UseCases.Journal.UndoStatus 100%
Tsumugi.UseCases.Journal.UndoTyping 100% 100%
Tsumugi.UseCases.Journal.UserOperation 100%
Tsumugi.UseCases.Notifications.DomainChanged 100%
Tsumugi.UseCases.Ordering 100% 100%
Tsumugi.UseCases.Runs.RunEvent 100%
Tsumugi.UseCases.Segments.DeleteSegments 100% 100%
Tsumugi.UseCases.Segments.EditSegment 100% 83.3%
Tsumugi.UseCases.Segments.InsertSegment 100% 100%
Tsumugi.UseCases.Segments.MergeSegmentWithPrevious 100% 100%
Tsumugi.UseCases.Segments.MoveSegments 100% 100%
Tsumugi.UseCases.Segments.ReorderSegments 100% 100%
Tsumugi.UseCases.Segments.SegmentDto 100%
Tsumugi.UseCases.Segments.SplitSegment 100% 100%
Tsumugi.UseCases.Settings.GetLlmDefaults 100% 100%
Tsumugi.UseCases.Settings.GetProviderSettings 100%
Tsumugi.UseCases.Settings.LlmDefaults 100%
Tsumugi.UseCases.Settings.ProviderSettingsView 100%
Tsumugi.UseCases.Settings.ReasoningEfforts 100% 100%
Tsumugi.UseCases.Settings.RemoveOpenRouterKey 100%
Tsumugi.UseCases.Settings.SaveLlmDefaults 100% 100%
Tsumugi.UseCases.Settings.SaveOpenRouterKey 100% 100%
Tsumugi.UseCases.Stories.CreateStory 100% 100%
Tsumugi.UseCases.Stories.GetStory 100% 100%
Tsumugi.UseCases.Stories.ListStories 100% 75%
Tsumugi.UseCases.Stories.PurgeStory 100% 100%
Tsumugi.UseCases.Stories.RestoreStory 100% 100%
Tsumugi.UseCases.Stories.SetActiveGraph 100% 100%
Tsumugi.UseCases.Stories.SetStoryArchived 100% 100%
Tsumugi.UseCases.Stories.StarterCategories 100%
Tsumugi.UseCases.Stories.StoryDetail 100%
Tsumugi.UseCases.Stories.StoryListItem 81.8%
Tsumugi.UseCases.Stories.StoryProfile 100%
Tsumugi.UseCases.Stories.TrashStory 100% 100%
Tsumugi.UseCases.Stories.UpdateStory 100% 100%
<!-- coverage-comment --> > 🔄 **Auto-updating coverage report** — this comment is regenerated on every push, so the numbers below always reflect the commit shown here, not the branch tip. > > **Commit:** `2ef5335` · **Generated:** 2026-09-23 14:29:52 UTC · **Revision:** #1 # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 09/23/2026 - 14:29:52 | | Coverage date: | 09/23/2026 - 14:29:40 - 09/23/2026 - 14:29:49 | | Parser: | MultiReport (5x Cobertura) | | Assemblies: | 7 | | Classes: | 314 | | Files: | 303 | | **Line coverage:** | 97.7% (6977 of 7138) | | Covered lines: | 6977 | | Uncovered lines: | 161 | | Coverable lines: | 7138 | | Total lines: | 15511 | | **Branch coverage:** | 92.3% (2153 of 2331) | | Covered branches: | 2153 | | Total branches: | 2331 | | **Method coverage:** | [Feature is only available for sponsors](https://reportgenerator.io/pro) | </details> ## Coverage <details><summary>Kagaku.Flow - 99.4%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.Flow**|**99.4%**|**98.6%**| |Kagaku.Flow.Budgeting.BudgetRequest|100%|| |Kagaku.Flow.Budgeting.ConsumerBudget|100%|| |Kagaku.Flow.FlowJson|100%|| |Kagaku.Flow.Graphs.GraphDefinition|100%|| |Kagaku.Flow.Graphs.GraphDocument|100%|100%| |Kagaku.Flow.Graphs.GraphEdge|100%|| |Kagaku.Flow.Graphs.GraphIndex|100%|100%| |Kagaku.Flow.Graphs.GraphLoadError|100%|| |Kagaku.Flow.Graphs.GraphLoadResult|100%|| |Kagaku.Flow.Graphs.GraphNode|100%|| |Kagaku.Flow.Graphs.GraphPosition|100%|| |Kagaku.Flow.Graphs.GraphReader|100%|100%| |Kagaku.Flow.Graphs.GraphSchema|100%|100%| |Kagaku.Flow.Graphs.GraphShapeException|100%|| |Kagaku.Flow.Graphs.GraphWriter|100%|100%| |Kagaku.Flow.Graphs.SocketRef|100%|| |Kagaku.Flow.Graphs.WireText|100%|100%| |Kagaku.Flow.Nodes.CanvasDescriptorWriter|100%|100%| |Kagaku.Flow.Nodes.ConfigProblem|100%|| |Kagaku.Flow.Nodes.Names|100%|| |Kagaku.Flow.Nodes.NodeDescriptor|100%|100%| |Kagaku.Flow.Nodes.NodeRegistry|100%|100%| |Kagaku.Flow.Nodes.NodeSockets|100%|100%| |Kagaku.Flow.Nodes.SinkDescriptor|100%|| |Kagaku.Flow.Nodes.SocketTypes|100%|100%| |Kagaku.Flow.Nodes.SourceDescriptor|100%|| |Kagaku.Flow.Nodes.TemplateField|100%|| |Kagaku.Flow.Templating.InputsWalker|100%|100%| |Kagaku.Flow.Templating.ParsedTemplate|100%|100%| |Kagaku.Flow.Templating.SandboxedTemplateContext|100%|100%| |Kagaku.Flow.Templating.TemplateError|100%|| |Kagaku.Flow.Templating.TemplateHost|100%|100%| |Kagaku.Flow.Templating.TemplateLimits|100%|| |Kagaku.Flow.Templating.TemplateModel|100%|100%| |Kagaku.Flow.Templating.TemplateProblem|100%|| |Kagaku.Flow.Templating.TemplateRenderRequest|100%|100%| |Kagaku.Flow.Templating.TemplateRenderResult|100%|| |Kagaku.Flow.Templating.TemplateRun|100%|| |Kagaku.Flow.Templating.TemplateSinks|100%|| |Kagaku.Flow.Templating.TemplateValues|100%|100%| |Kagaku.Flow.Validation.GraphValidation|100%|100%| |Kagaku.Flow.Validation.GraphValidationContext|100%|| |Kagaku.Flow.Validation.HookFailure|100%|| |Kagaku.Flow.Validation.ResolvedGraph|100%|100%| |Kagaku.Flow.Validation.ValidationError|100%|| |Kagaku.Flow.Validation.ValidationReport|100%|| |System.Text.RegularExpressions.Generated|97.4%|92.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF<br/>E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__ColorToken_2|97.4%|94.4%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF<br/>E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__Socket_1|97.2%|94.4%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF<br/>E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__TypeId_0|97.2%|94.4%| </details> <details><summary>Tsumugi.BlazorAdapter - 96.9%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.BlazorAdapter**|**96.9%**|**93.4%**| |Tsumugi.BlazorAdapter.BlazorAdapterAssembly|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryCreated|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryEditor|97.7%|86.1%| |Tsumugi.BlazorAdapter.Documents.CategorySaved|100%|| |Tsumugi.BlazorAdapter.Documents.CreateCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.CreateDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryDialog|100%|100%| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentAutoSaveFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentCreated|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentEditor|100%|87.9%| |Tsumugi.BlazorAdapter.Documents.DocumentsActionFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentSaved|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsEffects|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsList|98.2%|91.3%| |Tsumugi.BlazorAdapter.Documents.DocumentsLoaded|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsPage|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsReducers|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsState|100%|100%| |Tsumugi.BlazorAdapter.Documents.LoadDocuments|100%|| |Tsumugi.BlazorAdapter.Documents.MoveDocumentsRequested|100%|| |Tsumugi.BlazorAdapter.Documents.ReorderCategoriesRequested|100%|| |Tsumugi.BlazorAdapter.Documents.SetCategoryCollapsed|100%|| |Tsumugi.BlazorAdapter.Documents.SetDocumentsFilter|100%|| |Tsumugi.BlazorAdapter.Documents.UpdateCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.UpdateDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Graphs.GraphCanvas|37.5%|25%| |Tsumugi.BlazorAdapter.Graphs.GraphPlaygroundPage|20%|25%| |Tsumugi.BlazorAdapter.Notifications.DomainChangedBridge|94.4%|83.3%| |Tsumugi.BlazorAdapter.Notifications.DomainChangesReceived|75%|100%| |Tsumugi.BlazorAdapter.Runs.RunChangedBridge|97.1%|90.6%| |Tsumugi.BlazorAdapter.Runs.RunChangesReceived|100%|| |Tsumugi.BlazorAdapter.Runs.RunTextReceived|100%|| |Tsumugi.BlazorAdapter.Settings.BackupCompleted|100%|| |Tsumugi.BlazorAdapter.Settings.BackupFailed|100%|| |Tsumugi.BlazorAdapter.Settings.BackupNowRequested|100%|| |Tsumugi.BlazorAdapter.Settings.BackupSettingsLoaded|100%|| |Tsumugi.BlazorAdapter.Settings.BackupsSection|100%|100%| |Tsumugi.BlazorAdapter.Settings.BackupsSettingsEffects|100%|100%| |Tsumugi.BlazorAdapter.Settings.BackupsSettingsReducers|100%|| |Tsumugi.BlazorAdapter.Settings.BackupsSettingsState|100%|| |Tsumugi.BlazorAdapter.Settings.DefaultsSection|100%|100%| |Tsumugi.BlazorAdapter.Settings.DefaultsSettingsEffects|100%|100%| |Tsumugi.BlazorAdapter.Settings.DefaultsSettingsReducers|100%|| |Tsumugi.BlazorAdapter.Settings.DefaultsSettingsState|100%|| |Tsumugi.BlazorAdapter.Settings.LlmDefaultsLoaded|100%|| |Tsumugi.BlazorAdapter.Settings.LlmDefaultsSaved|100%|| |Tsumugi.BlazorAdapter.Settings.LlmDefaultsSaveFailed|100%|| |Tsumugi.BlazorAdapter.Settings.LoadBackupSettings|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderSection|100%|100%| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsEffects|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsLoaded|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsReducers|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsState|100%|| |Tsumugi.BlazorAdapter.Settings.SaveLlmDefaultsRequested|100%|| |Tsumugi.BlazorAdapter.Stories.CreateStoryRequested|100%|| |Tsumugi.BlazorAdapter.Stories.PurgeStoryRequested|100%|| |Tsumugi.BlazorAdapter.Stories.RestoreStoryRequested|100%|| |Tsumugi.BlazorAdapter.Stories.SetShowArchived|100%|| |Tsumugi.BlazorAdapter.Stories.SetStoriesFilter|100%|| |Tsumugi.BlazorAdapter.Stories.SetStoryArchivedRequested|100%|| |Tsumugi.BlazorAdapter.Stories.StoriesEffects|100%|100%| |Tsumugi.BlazorAdapter.Stories.StoriesLoaded|100%|| |Tsumugi.BlazorAdapter.Stories.StoriesPage|100%|100%| |Tsumugi.BlazorAdapter.Stories.StoriesReducers|100%|100%| |Tsumugi.BlazorAdapter.Stories.StoriesState|100%|100%| |Tsumugi.BlazorAdapter.Stories.StoryActionFailed|100%|| |Tsumugi.BlazorAdapter.Stories.StoryCreated|100%|| |Tsumugi.BlazorAdapter.Stories.StoryCreateFailed|100%|| |Tsumugi.BlazorAdapter.Stories.StoryTrashPage|100%|100%| |Tsumugi.BlazorAdapter.Stories.TrashStoryRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.AutoSaveFailed|100%|| |Tsumugi.BlazorAdapter.Workspace.CaretRequest|100%|| |Tsumugi.BlazorAdapter.Workspace.ChapterHeader|100%|86.3%| |Tsumugi.BlazorAdapter.Workspace.ChapterMenu|100%|81.2%| |Tsumugi.BlazorAdapter.Workspace.ChapterPage|100%|87.5%| |Tsumugi.BlazorAdapter.Workspace.ChapterSaved|100%|| |Tsumugi.BlazorAdapter.Workspace.ChaptersPage|90%|83.3%| |Tsumugi.BlazorAdapter.Workspace.CreateChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.DeleteChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.DeleteSegmentRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.EditSegmentRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.HistoryEffects|100%|100%| |Tsumugi.BlazorAdapter.Workspace.HistoryLoaded|100%|| |Tsumugi.BlazorAdapter.Workspace.HistoryPage|100%|| |Tsumugi.BlazorAdapter.Workspace.HistoryPanel|100%|100%| |Tsumugi.BlazorAdapter.Workspace.InsertSegmentRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.LoadHistory|100%|| |Tsumugi.BlazorAdapter.Workspace.LoadWorkspace|100%|| |Tsumugi.BlazorAdapter.Workspace.ManuscriptColumn|94.9%|89.4%| |Tsumugi.BlazorAdapter.Workspace.ManuscriptEffects|100%|100%| |Tsumugi.BlazorAdapter.Workspace.MergeChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.MergeSegmentRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.MoveChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RedoRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RedoRevertRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RenameChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RevertToSnapshotRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.SaveScope|100%|50%| |Tsumugi.BlazorAdapter.Workspace.SaveStateLadder|100%|100%| |Tsumugi.BlazorAdapter.Workspace.SaveVersionRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.SegmentRow|100%|96.8%| |Tsumugi.BlazorAdapter.Workspace.SegmentSaved|100%|| |Tsumugi.BlazorAdapter.Workspace.SetChapterSummaryRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.SplitSegmentRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.StoryDetails|100%|85.2%| |Tsumugi.BlazorAdapter.Workspace.StoryGeneralPage|100%|100%| |Tsumugi.BlazorAdapter.Workspace.StorySaved|100%|| |Tsumugi.BlazorAdapter.Workspace.StoryShell|100%|100%| |Tsumugi.BlazorAdapter.Workspace.UndoRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.UndoStatusChanged|100%|| |Tsumugi.BlazorAdapter.Workspace.UpdateStoryRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceActionFailed|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceLoaded|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceNotFound|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceReducers|100%|100%| |Tsumugi.BlazorAdapter.Workspace.WorkspaceState|100%|| </details> <details><summary>Tsumugi.Domain - 99.3%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Domain**|**99.3%**|**95.6%**| |Tsumugi.Domain.Documents.Document|100%|100%| |Tsumugi.Domain.Documents.DocumentCategory|100%|| |Tsumugi.Domain.Journal.ChangeLogEntry|97.8%|75%| |Tsumugi.Domain.Journal.StorySnapshot|95.4%|83.3%| |Tsumugi.Domain.Settings.AppSetting|100%|| |Tsumugi.Domain.Stories.Chapter|100%|100%| |Tsumugi.Domain.Stories.Provenance|100%|100%| |Tsumugi.Domain.Stories.Segment|100%|100%| |Tsumugi.Domain.Stories.Story|100%|100%| |Tsumugi.Domain.Text|100%|100%| </details> <details><summary>Tsumugi.Infrastructure - 97.1%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Infrastructure**|**97.1%**|**82.4%**| |System.Text.RegularExpressions.Generated|81.4%|64.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F0D076C66E8EEC1C<br/>A55E0373ED22DC58420DBB40F103A46B68DC4D9CE5A49E00B__Pattern_0|84%|65.7%| |Tsumugi.Infrastructure.Backups.BackupArtifactName|100%|100%| |Tsumugi.Infrastructure.Backups.BackupOptions|100%|| |Tsumugi.Infrastructure.Backups.BackupSchedule|100%|83.3%| |Tsumugi.Infrastructure.Backups.BackupScheduler|96.5%|83.3%| |Tsumugi.Infrastructure.Backups.BackupWriter|98.4%|92.5%| |Tsumugi.Infrastructure.Backups.FileSystemBackupStore|100%|100%| |Tsumugi.Infrastructure.Backups.SqliteSnapshot|87.8%|75%| |Tsumugi.Infrastructure.DependencyInjection|100%|100%| |Tsumugi.Infrastructure.Journal.EfChangeJournal|100%|| |Tsumugi.Infrastructure.Journal.EfSnapshotStore|100%|| |Tsumugi.Infrastructure.Journal.EfUndoStore|98.1%|85.7%| |Tsumugi.Infrastructure.Journal.ModelExtensions|100%|| |Tsumugi.Infrastructure.Journal.OperationContext|100%|100%| |Tsumugi.Infrastructure.Journal.PropertyBag|100%|95.4%| |Tsumugi.Infrastructure.Notifications.InProcessDomainChangedBus|100%|100%| |Tsumugi.Infrastructure.Persistence.Configurations.AppSettingConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.ChangeLogEntryConfigurati<br/>on|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.ChapterConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.DocumentCategoryConfigura<br/>tion|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.DocumentConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.SegmentConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.StoryConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.StorySnapshotConfiguratio<br/>n|100%|| |Tsumugi.Infrastructure.Persistence.Converters.ProvenanceConverter|100%|90%| |Tsumugi.Infrastructure.Persistence.Converters.UtcTicksConverter|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.AddAppSettings|99.2%|| |Tsumugi.Infrastructure.Persistence.Migrations.AddJournal|98.8%|| |Tsumugi.Infrastructure.Persistence.Migrations.GenericDocuments|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.InitialStoryDomain|97.3%|| |Tsumugi.Infrastructure.Persistence.Migrations.TsumugiDbContextModelSnapshot|100%|| |Tsumugi.Infrastructure.Persistence.SqlitePragmaInterceptor|100%|100%| |Tsumugi.Infrastructure.Persistence.Stores.EfChapterStore|100%|100%| |Tsumugi.Infrastructure.Persistence.Stores.EfDocumentStore|97.5%|90%| |Tsumugi.Infrastructure.Persistence.Stores.EfSegmentStore|95%|84.6%| |Tsumugi.Infrastructure.Persistence.Stores.EfStoryStore|98.3%|92.8%| |Tsumugi.Infrastructure.Persistence.TsumugiDbContext|83.5%|93.1%| |Tsumugi.Infrastructure.Persistence.TsumugiDbContextFactory|0%|| |Tsumugi.Infrastructure.Runs.InProcessRunEventBus|100%|100%| |Tsumugi.Infrastructure.Settings.EfAppSettingsStore|100%|100%| </details> <details><summary>Tsumugi.Kernel - 90.9%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Kernel**|**90.9%**|**75%**| |Tsumugi.Kernel.Err`1|100%|| |Tsumugi.Kernel.Ok`1|100%|| |Tsumugi.Kernel.Result`1|88.8%|75%| </details> <details><summary>Tsumugi.Server - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Server**|**100%**|**79%**| |Program|100%|83.3%| |Tsumugi.Server.Backups.BackupConfiguration|100%|100%| |Tsumugi.Server.Components.App|100%|| |Tsumugi.Server.Components.Layout.AppHeader|100%|50%| |Tsumugi.Server.Components.Layout.MainLayout|100%|| |Tsumugi.Server.Components.Pages.Gate|100%|100%| |Tsumugi.Server.Security.AccessGate|100%|66.6%| |Tsumugi.Server.Security.AccessSecret|100%|50%| |Tsumugi.Server.VolumeStartupValidator|100%|100%| </details> <details><summary>Tsumugi.UseCases - 98%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.UseCases**|**98%**|**94%**| |Tsumugi.UseCases.Backups.BackupArtifact|100%|| |Tsumugi.UseCases.Backups.BackupPolicy|100%|| |Tsumugi.UseCases.Backups.BackupStatusView|100%|100%| |Tsumugi.UseCases.Backups.DatabaseSnapshot|100%|| |Tsumugi.UseCases.Backups.DownloadDatabaseSnapshot|100%|| |Tsumugi.UseCases.Backups.GetBackupStatus|100%|| |Tsumugi.UseCases.Backups.RunBackupNow|100%|| |Tsumugi.UseCases.Chapters.ChapterDto|100%|| |Tsumugi.UseCases.Chapters.CreateChapter|100%|100%| |Tsumugi.UseCases.Chapters.DeleteChapter|100%|100%| |Tsumugi.UseCases.Chapters.GetManuscript|100%|100%| |Tsumugi.UseCases.Chapters.ManuscriptChapter|100%|| |Tsumugi.UseCases.Chapters.ManuscriptView|100%|| |Tsumugi.UseCases.Chapters.MergeChapters|100%|100%| |Tsumugi.UseCases.Chapters.RenameChapter|100%|100%| |Tsumugi.UseCases.Chapters.ReorderChapters|100%|100%| |Tsumugi.UseCases.Chapters.SetChapterSummary|100%|75%| |Tsumugi.UseCases.DependencyInjection|100%|| |Tsumugi.UseCases.Diagnostics.SeedDevData|97.3%|70%| |Tsumugi.UseCases.Documents.CreateCategory|100%|100%| |Tsumugi.UseCases.Documents.CreateDocument|100%|100%| |Tsumugi.UseCases.Documents.DeleteCategory|100%|100%| |Tsumugi.UseCases.Documents.DeleteDocument|100%|100%| |Tsumugi.UseCases.Documents.DocumentCategoryDto|100%|| |Tsumugi.UseCases.Documents.DocumentCategoryProfile|100%|| |Tsumugi.UseCases.Documents.DocumentDto|100%|| |Tsumugi.UseCases.Documents.DocumentProfile|100%|| |Tsumugi.UseCases.Documents.DocumentsCategory|100%|| |Tsumugi.UseCases.Documents.DocumentsView|100%|| |Tsumugi.UseCases.Documents.GetDocuments|100%|100%| |Tsumugi.UseCases.Documents.MoveDocuments|100%|100%| |Tsumugi.UseCases.Documents.ReorderCategories|100%|100%| |Tsumugi.UseCases.Documents.UpdateCategory|100%|100%| |Tsumugi.UseCases.Documents.UpdateDocument|100%|100%| |Tsumugi.UseCases.Journal.GetStoryHistory|100%|100%| |Tsumugi.UseCases.Journal.GetUndoStatus|100%|100%| |Tsumugi.UseCases.Journal.HistoryOperation|66.6%|| |Tsumugi.UseCases.Journal.HistorySnapshot|87.5%|| |Tsumugi.UseCases.Journal.OperationGrouping|100%|100%| |Tsumugi.UseCases.Journal.RedoRevert|100%|100%| |Tsumugi.UseCases.Journal.RedoRun|75%|57.1%| |Tsumugi.UseCases.Journal.RedoTyping|100%|100%| |Tsumugi.UseCases.Journal.RevertConflict|100%|| |Tsumugi.UseCases.Journal.RevertOutcome|100%|| |Tsumugi.UseCases.Journal.RevertRun|96.5%|77.7%| |Tsumugi.UseCases.Journal.RevertToSnapshot|92.3%|83.3%| |Tsumugi.UseCases.Journal.StoryHistory|100%|| |Tsumugi.UseCases.Journal.TakeSnapshot|100%|87.5%| |Tsumugi.UseCases.Journal.UndoStatus|100%|| |Tsumugi.UseCases.Journal.UndoTyping|100%|100%| |Tsumugi.UseCases.Journal.UserOperation|100%|| |Tsumugi.UseCases.Notifications.DomainChanged|100%|| |Tsumugi.UseCases.Ordering|100%|100%| |Tsumugi.UseCases.Runs.RunEvent|100%|| |Tsumugi.UseCases.Segments.DeleteSegments|100%|100%| |Tsumugi.UseCases.Segments.EditSegment|100%|83.3%| |Tsumugi.UseCases.Segments.InsertSegment|100%|100%| |Tsumugi.UseCases.Segments.MergeSegmentWithPrevious|100%|100%| |Tsumugi.UseCases.Segments.MoveSegments|100%|100%| |Tsumugi.UseCases.Segments.ReorderSegments|100%|100%| |Tsumugi.UseCases.Segments.SegmentDto|100%|| |Tsumugi.UseCases.Segments.SplitSegment|100%|100%| |Tsumugi.UseCases.Settings.GetLlmDefaults|100%|100%| |Tsumugi.UseCases.Settings.GetProviderSettings|100%|| |Tsumugi.UseCases.Settings.LlmDefaults|100%|| |Tsumugi.UseCases.Settings.ProviderSettingsView|100%|| |Tsumugi.UseCases.Settings.ReasoningEfforts|100%|100%| |Tsumugi.UseCases.Settings.RemoveOpenRouterKey|100%|| |Tsumugi.UseCases.Settings.SaveLlmDefaults|100%|100%| |Tsumugi.UseCases.Settings.SaveOpenRouterKey|100%|100%| |Tsumugi.UseCases.Stories.CreateStory|100%|100%| |Tsumugi.UseCases.Stories.GetStory|100%|100%| |Tsumugi.UseCases.Stories.ListStories|100%|75%| |Tsumugi.UseCases.Stories.PurgeStory|100%|100%| |Tsumugi.UseCases.Stories.RestoreStory|100%|100%| |Tsumugi.UseCases.Stories.SetActiveGraph|100%|100%| |Tsumugi.UseCases.Stories.SetStoryArchived|100%|100%| |Tsumugi.UseCases.Stories.StarterCategories|100%|| |Tsumugi.UseCases.Stories.StoryDetail|100%|| |Tsumugi.UseCases.Stories.StoryListItem|81.8%|| |Tsumugi.UseCases.Stories.StoryProfile|100%|| |Tsumugi.UseCases.Stories.TrashStory|100%|100%| |Tsumugi.UseCases.Stories.UpdateStory|100%|100%| </details>
bjoern merged commit e9c0016517 into main 2026-09-23 16:30:35 +02:00
bjoern deleted branch feat/kagaku-flow-templating 2026-09-23 16:30:36 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
TeamAI/Tsumugi!19
No description provided.