feat: the context node — the story text for what its consumers say fits; documents as agent grants and pins (Phase 2 · slice 9b) #60

Merged
bjoern merged 8 commits from feat/context-node into main 2026-09-26 20:50:04 +02:00
Member

Slice 9b of Phase 2, the second of three PRs for "the story half" (9a #50: story.* and the document rendering; 9b: the context node; 9c: the commit node and the registry in the playground). The context node assembles the run's story text for what the nodes it feeds say fits. Documents reach a model another way: an agent's granted categories and a template's pins, which this PR writes into the ADRs.

The redirect. The first draft built ADR 0017's document selection: fixed, dynamic and index manners, keyword triggers with aliases, a scan window and near-end placement. On reviewing it you corrected the model: documents are an agent's skills, not a lorebook. The commits from the rework on implement and document that; the earlier ones stay as history.

Commits:

  • 5938b83, ad2d7da, c50b362, a657a41: the first draft (the document selection), its review round 0, its second pass, and this PR's number in the docs. History now.
  • ee30806 is the rework: story text only, and the docs for grants and pins.
  • 1bc6f3e holds the fixes from the rework's review.
  • 88301c7 holds that review's second pass.
  • d1c5967 is Jibril's round 1: the section names are public constants.

What

Tsumugi.UseCases/Context:

  • ContextConfig has two settings, both optional, so {} (the playground's literal) is a config:

    • sections: summaries and recent, in output order;
    • safetyMargin: a fraction from 0 to below 1, 0.05 by default.

    Every problem is found at its JSON pointer. A document selection in an old config is refused as an unknown setting.

  • ContextDescriptor is the playground's canvas entry: group Story, --success, no sinks (the focus sink is Phase 3), one text source, context. It has three attempts, since a consumer's budget may need a catalog that failed to load, and no slot of the LLM limit. Its config schema agrees with ValidateConfig, except for a number past a decimal's 28 digits.

  • ContextExecutor asks each node its context feeds what fits, through the registry's IBudgetedConsumer, and budgets for the smallest answer at each model's ratio. The budget is (window − reserved output) × (1 − margin) × ratio, less the overhead as sent. The row's report holds:

    • every consumer's figures, and the one that set the budget;
    • each section's size;
    • how much of the chapter the recent text holds.
  • ContextAssembly, ContextBuilder build the text:

    • the earlier chapters' summaries, never cut;
    • the target chapter's recent text, walked back by whole segments and never opening with a scene break;
    • each section under a fixed heading (# Earlier chapters, # Story so far), an empty section left out.
  • ContextConsumerRule refuses two graphs (ADR 0017, 0021):

    • tsumugi.context-needs-consumer: a context node that feeds no node answering budget questions;
    • tsumugi.context-one-per-consumer: a consumer that takes a context on more than one sink, since each context would budget for its whole window.
  • CharsPerToken folds a model's completed requests into its ratio. IPromptSamples is the port that reads them; until 11a persists the ledger, NoPromptSamples knows none, and every model reads at 4.0.

  • StoryText holds what story.* and the node read alike. story.documents.index now keeps each entry on one line: a description written over several lines is joined into one.

  • Everything is registered as enumerable singletons in AddUseCases.

How documents reach a model, recorded in ADR 0013, 0017, 0018, 0019, 0021 and 0028 and built in later phases:

  • Granted categories:
    • A per-agent setting on the llm node, shown as a checkbox dropdown in the property panel (Phase 3).
    • Every granted document is listed in the agent's system prompt as Title — Description.
    • The agent holds load_document over the granted categories and runs an agent loop (Phase 4).
  • Pins:
    • In the prompt editor, @ opens a dropdown of the story's documents, filtered as you type (Phase 3).
    • A pin is stored as story.pin(id, category, title) and shown by the document's name. At render it becomes the document's current content.
  • Template reads: story.* reads, as 9a built them.
  • No keyword activation. The trigger scanner is gone from ADR 0017 and 0030, and from AGENTS.md's read-path rule.

Why

  • Your direction on this PR (2026-09-26): documents as agent skills; a checkbox dropdown per agent; pins picked with @ (not #, which Markdown reads as a heading), stored by id and shown by name.
  • ADR 0017: the budgeted story text, and budgeting through the consumers with the ratio from the ledger.
  • ADR 0021: a context node with no consumer is a validation error.

Decisions to confirm

Decision ADR
A pin keeps its category and title beside its id. A graph serves every story, but an id belongs to one. In another story a pin resolves to the first document of that category and title, matched as story.document matches. The dropdown lists the documents of the story the editor was opened from; opened from the Graphs page, it offers none. 0017, 0021, graph-library story
A grant brings load_document, and so an agent loop. Granted means listed and loadable, so the tool is not a separate checkbox: the panel shows it held and locked while categories are granted. Bundled writers are granted Characters and Lore from Phase 4. 0013, 0018, 0019, 0023
An agent loop's budget holds back room for its rounds (tool definitions, loaded documents). Phase 4 decides how much; until then, a later round refused for length fails the row, naming the round. 0017, 0018
One context per consumer. A consumer fed a context on two sinks, from one node or two, is refused rather than having its budget split. 0017, 0021
The summaries are never cut. When they alone exceed the budget, the row fails permanently and names their size. 0017
The ratio comes through a Tsumugi port, not a new IRunLedger query (D-5). The engine stays untouched; 11a's EF ledger answers the port. 0017, 0025, plan
The ratio's fold. It reads the model's last 50 completed rows, oldest first. The first row replaces the seed of 4.0, and each later one moves the ratio by 0.3 of the difference. 0017
Three attempts, no slot. A consumer's own refusal is permanent; a transient one retries. 0016, 0017
The template field becomes an editor that renders pins, a new Kagaku.UI component in Phase 3. 0009, 0021

Reviews

Each round was a review workflow, a skeptic for each finding, and then a second pass over the fixes:

  • The first draft: 31 findings, all taken in ad2d7da, and a second pass with 12 more, 11 taken in c50b362. The draft they reviewed is retracted, but a few of its fixes carry over:
    • one context per consumer;
    • index entries kept on one line;
    • the report on each failure;
    • the margin clamped below 1;
    • numbers read as decimals.
  • The rework: 14 findings (10 confirmed, 4 partly), all taken in 1bc6f3e. They covered:
    • a grant brings load_document;
    • a pin is a story.pin read, and where its dropdown's documents come from;
    • phase wording;
    • the remaining "selection" wording;
    • four test gaps: a summaries-only node reports no recent text, a busy store is retried, node ids are kept as written, a setting spelt in another case is refused.
  • Its second pass: 9 findings (6 confirmed, 3 partly), all taken in 88301c7. They covered the agent-loop budget reserve, the pin fallback's tie-break, the locked load_document, the pin-rendering template field, and the editor's entry points.

Out of scope

  • The commit node and the registry in the playground (9c).
  • Granted categories, load_document and agent mode (Phase 4); the @ picker, story.pin and the category dropdown (Phase 3). This PR writes their design into the ADRs.
  • The ledger's EF adapter and its answer to IPromptSamples (11a).
  • The context preview (10b), which will run the same builder and read the same report.
  • The focus sink and the selection's sections (Phase 3).

Tests

Every project, one at a time, after a full build (script modules included), on main e19247c; UseCases and the context tests again after round 1:

Project main branch
Tsumugi.Domain.Tests 486 486
Kagaku.Flow.Tests 1103 1103
Kagaku.Flow.OpenRouter.Tests 596 (4 live, skipped) 596
Tsumugi.BlazorAdapter.Tests 462 462
Tsumugi.UseCases.Tests 243 321 (+78: config 14, descriptor and schema 16, ratio and budget 11, assembly 22, rule 10, index lines 4, registration 1)
Tsumugi.Integration.Tests 556 578 (+22: ContextNodeTests, the node run by the engine over the real stores)

All pass.

Coverage

Coverlet with branch coverage, on the use-case and integration tests: 100% of lines and branches on every new or changed source file.

File Lines Branches
Context/CharsPerToken.cs 17/17 6/6
Context/ContextAssembly.cs 35/35 24/24
Context/ContextBuilder.cs 8/8 —
Context/ContextConfig.cs 65/65 38/38
Context/ContextConsumerRule.cs 18/18 18/18
Context/ContextDescriptor.cs 24/24 —
Context/ContextExecutor.cs 83/83 14/14
Context/StoryText.cs 10/10 6/6
Context/StoryTemplateModel.cs (now using StoryText) 154/154 68/68
DependencyInjection.cs 67/67 —

Mutation probes

Each probe is a single edit, built and tested on its own, one at a time.

  • The rework: 17 probes on the reworked config, assembly, builder and executor, all killed. The one that first survived (summaries left out still counted against the budget) got its own test.
  • The rework's review: 4 more, all killed, one per test gap it found.
  • The first draft: 66 probes, all killed. Most covered the lorebook code, which is gone. Those on the ratio fold and the consumer rules still hold, since the rework left that code unchanged.

Browser pass

9b has no visible change: the node is not on the canvas until 9c, and nothing runs a graph until slice 11.

🤖 Generated with Claude Code

Slice 9b of Phase 2, the second of three PRs for "the story half" (9a #50: `story.*` and the document rendering; 9b: the `context` node; 9c: the `commit` node and the registry in the playground). The `context` node assembles the run's **story text** for what the nodes it feeds say fits. Documents reach a model another way: an agent's granted categories and a template's pins, which this PR writes into the ADRs. **The redirect.** The first draft built ADR 0017's document selection: fixed, dynamic and index manners, keyword triggers with aliases, a scan window and near-end placement. On reviewing it you corrected the model: documents are an agent's *skills*, not a lorebook. The commits from the rework on implement and document that; the earlier ones stay as history. **Commits:** - 5938b83, ad2d7da, c50b362, a657a41: the first draft (the document selection), its review round 0, its second pass, and this PR's number in the docs. History now. - ee30806 is the rework: story text only, and the docs for grants and pins. - 1bc6f3e holds the fixes from the rework's review. - 88301c7 holds that review's second pass. - d1c5967 is Jibril's round 1: the section names are public constants. ## What **`Tsumugi.UseCases/Context`:** - **`ContextConfig`** has two settings, both optional, so `{}` (the playground's literal) is a config: - `sections`: `summaries` and `recent`, in output order; - `safetyMargin`: a fraction from 0 to below 1, 0.05 by default. Every problem is found at its JSON pointer. A document selection in an old config is refused as an unknown setting. - **`ContextDescriptor`** is the playground's canvas entry: group Story, `--success`, no sinks (the `focus` sink is Phase 3), one text source, `context`. It has three attempts, since a consumer's budget may need a catalog that failed to load, and no slot of the LLM limit. Its config schema agrees with `ValidateConfig`, except for a number past a decimal's 28 digits. - **`ContextExecutor`** asks each node its `context` feeds what fits, through the registry's `IBudgetedConsumer`, and budgets for the smallest answer at each model's ratio. The budget is (window − reserved output) × (1 − margin) × ratio, less the overhead as sent. The row's report holds: - every consumer's figures, and the one that set the budget; - each section's size; - how much of the chapter the recent text holds. - **`ContextAssembly`, `ContextBuilder`** build the text: - the earlier chapters' summaries, never cut; - the target chapter's recent text, walked back by whole segments and never opening with a scene break; - each section under a fixed heading (`# Earlier chapters`, `# Story so far`), an empty section left out. - **`ContextConsumerRule`** refuses two graphs (ADR 0017, 0021): - `tsumugi.context-needs-consumer`: a context node that feeds no node answering budget questions; - `tsumugi.context-one-per-consumer`: a consumer that takes a context on more than one sink, since each context would budget for its whole window. - **`CharsPerToken`** folds a model's completed requests into its ratio. **`IPromptSamples`** is the port that reads them; until 11a persists the ledger, `NoPromptSamples` knows none, and every model reads at 4.0. - **`StoryText`** holds what `story.*` and the node read alike. `story.documents.index` now keeps each entry on one line: a description written over several lines is joined into one. - Everything is registered as enumerable singletons in `AddUseCases`. **How documents reach a model**, recorded in ADR 0013, 0017, 0018, 0019, 0021 and 0028 and built in later phases: - **Granted categories:** - A per-agent setting on the `llm` node, shown as a checkbox dropdown in the property panel (Phase 3). - Every granted document is listed in the agent's system prompt as `Title — Description`. - The agent holds `load_document` over the granted categories and runs an agent loop (Phase 4). - **Pins:** - In the prompt editor, `@` opens a dropdown of the story's documents, filtered as you type (Phase 3). - A pin is stored as `story.pin(id, category, title)` and shown by the document's name. At render it becomes the document's current content. - **Template reads:** `story.*` reads, as 9a built them. - **No keyword activation.** The trigger scanner is gone from ADR 0017 and 0030, and from AGENTS.md's read-path rule. ## Why - **Your direction on this PR (2026-09-26):** documents as agent skills; a checkbox dropdown per agent; pins picked with `@` (not `#`, which Markdown reads as a heading), stored by id and shown by name. - **ADR 0017:** the budgeted story text, and budgeting through the consumers with the ratio from the ledger. - **ADR 0021:** a context node with no consumer is a validation error. ## Decisions to confirm | Decision | ADR | |---|---| | **A pin keeps its category and title beside its id.** A graph serves every story, but an id belongs to one. In another story a pin resolves to the first document of that category and title, matched as `story.document` matches. The dropdown lists the documents of the story the editor was opened from; opened from the Graphs page, it offers none. | 0017, 0021, graph-library story | | **A grant brings `load_document`, and so an agent loop.** Granted means listed and loadable, so the tool is not a separate checkbox: the panel shows it held and locked while categories are granted. Bundled writers are granted Characters and Lore from Phase 4. | 0013, 0018, 0019, 0023 | | **An agent loop's budget holds back room for its rounds** (tool definitions, loaded documents). Phase 4 decides how much; until then, a later round refused for length fails the row, naming the round. | 0017, 0018 | | **One context per consumer.** A consumer fed a context on two sinks, from one node or two, is refused rather than having its budget split. | 0017, 0021 | | **The summaries are never cut.** When they alone exceed the budget, the row fails permanently and names their size. | 0017 | | **The ratio comes through a Tsumugi port**, not a new `IRunLedger` query (D-5). The engine stays untouched; 11a's EF ledger answers the port. | 0017, 0025, plan | | **The ratio's fold.** It reads the model's last 50 completed rows, oldest first. The first row replaces the seed of 4.0, and each later one moves the ratio by 0.3 of the difference. | 0017 | | **Three attempts, no slot.** A consumer's own refusal is permanent; a transient one retries. | 0016, 0017 | | **The template field becomes an editor that renders pins**, a new Kagaku.UI component in Phase 3. | 0009, 0021 | ## Reviews Each round was a review workflow, a skeptic for each finding, and then a second pass over the fixes: - **The first draft:** 31 findings, all taken in ad2d7da, and a second pass with 12 more, 11 taken in c50b362. The draft they reviewed is retracted, but a few of its fixes carry over: - one context per consumer; - index entries kept on one line; - the report on each failure; - the margin clamped below 1; - numbers read as decimals. - **The rework:** 14 findings (10 confirmed, 4 partly), all taken in 1bc6f3e. They covered: - a grant brings `load_document`; - a pin is a `story.pin` read, and where its dropdown's documents come from; - phase wording; - the remaining "selection" wording; - four test gaps: a summaries-only node reports no recent text, a busy store is retried, node ids are kept as written, a setting spelt in another case is refused. - **Its second pass:** 9 findings (6 confirmed, 3 partly), all taken in 88301c7. They covered the agent-loop budget reserve, the pin fallback's tie-break, the locked `load_document`, the pin-rendering template field, and the editor's entry points. ## Out of scope - The `commit` node and the registry in the playground (9c). - Granted categories, `load_document` and agent mode (Phase 4); the `@` picker, `story.pin` and the category dropdown (Phase 3). This PR writes their design into the ADRs. - The ledger's EF adapter and its answer to `IPromptSamples` (11a). - The context preview (10b), which will run the same builder and read the same report. - The `focus` sink and the selection's sections (Phase 3). ## Tests Every project, one at a time, after a full build (script modules included), on main e19247c; UseCases and the context tests again after round 1: | Project | main | branch | |---|---|---| | Tsumugi.Domain.Tests | 486 | 486 | | Kagaku.Flow.Tests | 1103 | 1103 | | Kagaku.Flow.OpenRouter.Tests | 596 (4 live, skipped) | 596 | | Tsumugi.BlazorAdapter.Tests | 462 | 462 | | Tsumugi.UseCases.Tests | 243 | 321 (+78: config 14, descriptor and schema 16, ratio and budget 11, assembly 22, rule 10, index lines 4, registration 1) | | Tsumugi.Integration.Tests | 556 | 578 (+22: `ContextNodeTests`, the node run by the engine over the real stores) | All pass. ## Coverage Coverlet with branch coverage, on the use-case and integration tests: **100% of lines and branches** on every new or changed source file. | File | Lines | Branches | |---|---|---| | `Context/CharsPerToken.cs` | 17/17 | 6/6 | | `Context/ContextAssembly.cs` | 35/35 | 24/24 | | `Context/ContextBuilder.cs` | 8/8 | — | | `Context/ContextConfig.cs` | 65/65 | 38/38 | | `Context/ContextConsumerRule.cs` | 18/18 | 18/18 | | `Context/ContextDescriptor.cs` | 24/24 | — | | `Context/ContextExecutor.cs` | 83/83 | 14/14 | | `Context/StoryText.cs` | 10/10 | 6/6 | | `Context/StoryTemplateModel.cs` (now using `StoryText`) | 154/154 | 68/68 | | `DependencyInjection.cs` | 67/67 | — | ## Mutation probes Each probe is a single edit, built and tested on its own, one at a time. - **The rework:** 17 probes on the reworked config, assembly, builder and executor, all killed. The one that first survived (summaries left out still counted against the budget) got its own test. - **The rework's review:** 4 more, all killed, one per test gap it found. - **The first draft:** 66 probes, all killed. Most covered the lorebook code, which is gone. Those on the ratio fold and the consumer rules still hold, since the rework left that code unchanged. ## Browser pass 9b has no visible change: the node is not on the canvas until 9c, and nothing runs a graph until slice 11. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The config (ContextConfig, ADR 0017). documents is a list of
{category, manner, placement, trigger}: fixed, dynamic or index; placed in
the header or {"nearEnd": n}; for a dynamic category a trigger of its
documents' titles and aliases per document, "aliases": {"Ansel": ["the
captain"]} (Björn, 2026-09-26). Then sections, documentsShare,
safetyMargin and scanChars. Every setting is optional, so {} is a config.
Every problem is found at its JSON pointer: a category selected twice, a
trigger that can activate nothing, a delivery whose section is not listed.

The node type. ContextDescriptor is the playground's canvas entry: group
Story, --success, no sinks, one text source "context". It has three
attempts, as a consumer's budget may need a catalog that failed to load,
and holds no slot of the LLM limit. Its config schema agrees with
ValidateConfig. ContextConsumerRule refuses a context node that feeds no
node answering budget questions (ADR 0021).

The executor. It asks each node its context feeds what fits and budgets
for the smallest answer: (window - reserved) x (1 - margin) x the model's
ratio, less the overhead as sent. The ratio is CharsPerToken over the
model's last 50 completed rows, read through IPromptSamples, which knows
none until 11a persists the ledger. A consumer's own refusal is
permanent, a transient one retries. Its row's details report every
consumer's figures, what became of each category and document, and each
section's size.

The assembly (ContextBuilder, ContextAssembly, TriggerScanner). A
dynamic document activates when its title or an alias appears as whole
words, ignoring case, in the scan window: the end of the chapter's
visible text, each segment parsed on its own, plus the fixed header
documents as rendered. The documents share caps header and near-end
documents, the lowest priority yielding first from its last document.
The header holds the fixed documents, then the activated ones. The index
and summaries are never cut; when they do not fit, the row fails naming
the sizes. The recent text walks the target chapter back by whole
segments and never opens with a scene break. A near-end document goes
its distance before the end. An empty section is left out with its
heading.

StoryText holds what story.* and the node read alike: kept segments,
paragraphs, index lines, summaries. ADR 0017 records the details as the
9b amendment; the plan names the PR.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A review workflow ran four reviewers (correctness; config, rule and
schema; tests; docs), and a skeptic checked each dimension's findings:
27 confirmed, 4 partly confirmed (A1, B4, D3, D6), none refuted.
All are taken.

The node:
- A1 (partly): a consumer fed a context on two sinks, from one context
  node or two, budgeted each for its whole window and got more than fits.
  ContextConsumerRule now refuses it at the consumer
  (tsumugi.context-one-per-consumer).
- A3: a name selects every category of that name, as story.documents
  does; the report lists all their documents under the one entry.
- A2: an index entry keeps one line, a summary written over several lines
  joined into one (the node and story.documents.index alike).
- A6: in a script written without spaces (Chinese, Japanese, Korean,
  Thai) a keyword fires wherever it appears; "アンセルは" now finds
  アンセル.
- A5, D7: fixed parts that do not fit report what each section would
  take, and a consumer that leaves no room reports the consumers.

The config:
- A4, B1, C2, D1: title false with only empty alias lists can activate
  nothing, and is now a problem ("no alias names").
- B3: numbers are read as decimals, as the schema compares them; a name of
  Unicode blanks is the one listed difference.
- B4, D4: the range messages name their bounds, and the margin is "the
  part of the window, less the reserved output, kept free".
- D5: Read's summary names the order the problems come in.

The tests, each killing a mutant the review found surviving:
- C1: a wider share and margin, a margin in the no-room message, and a
  shorter scan window, each through the engine.
- C3: the over-the-share status; C5: the report on too-large; C10: the
  report's relaxed escaping; C4: the consumer's other inputs, asked on a
  retry once the upstream has settled.
- C6: a blank paragraph in the target chapter; C7: two scene breaks at
  the cut; C8: a window opening at a word's start; C9: near-end documents
  refused without a paragraph; C11: a fixed document naming a dynamic one
  only in its title; C12: the title reported before an alias; C13: an
  overlapping key; C14: a bad section beside documents.

The docs:
- B2, D2: ADR 0016 gives the context node three attempts.
- D6: the 9b amendment gives each setting's values; D3: the plan's 11a
  line takes IPromptSamples over the ledger.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
fix(context): second pass — Korean keywords need a word start, every script range is pinned, a gone story reports the consumers
Some checks failed
CI / test (pull_request) Has been cancelled
CI / editor-browsers (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
2f68081935
A second-pass workflow checked each round-0 fix (29 resolved, 2 partly:
B3, C3), reviewed the fix commit, and a skeptic checked each new finding:
9 confirmed, 2 partly confirmed (M3, F1), 1 refuted (K1). All taken but
the refuted one.

The trigger:
- K2, M1, F4: Korean spaces its words and joins its particles to them,
  so it is no longer matched anywhere: a Korean keyword needs a word
  start and may run on into the syllables after it. 안셀 fires in 안셀은,
  not in 사진; 미라 still fires in 미라클, which only a dictionary could
  tell from 미라는. A window cut inside a Korean word opens after it.
- F2: the kana range starts at the CJK symbols and punctuation, so a name
  right after 時々 or 人々 fires.
- K3: a row pins each range — Chinese, extension A, a compatibility
  ideograph NFC keeps, Thai, halfwidth katakana — and each dropped range
  fails one.

The config:
- M3, F1: a safety margin just below 1 stays below 1, where a double
  would round it to 1.
- K4, B3: Read and the schema test say where decimals stop agreeing with
  the schema: past a decimal's 28 digits.

The report:
- M2, F3: a run whose story is gone reports the consumers and the
  budget, as a consumer that leaves no room does; the summaries and the
  amendment say so.
- C3: two documents of a category sharing a title, one over the share,
  are reported "in" and "over the documents share", which value
  equality would not tell apart.

The docs: ADR 0017's amendment words the scripts and the window as
above; M4: the plan's 11a comes after 9b.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
bjoern referenced this pull request from a commit 2026-09-26 18:40:35 +02:00
docs: slice 9b's PR is #60
All checks were successful
CI / build (pull_request) Successful in 42s
CI / editor-browsers (pull_request) Successful in 56s
CI / test (pull_request) Successful in 1m45s
e953d7825f
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

🔄 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: d1c5967 · Generated: 2026-09-26 18:49:38 UTC · Revision: #3

Summary

Summary
Generated on: 09/26/2026 - 18:49:38
Coverage date: 09/26/2026 - 18:49:07 - 09/26/2026 - 18:49:34
Parser: MultiReport (6x Cobertura)
Assemblies: 9
Classes: 524
Files: 463
Line coverage: 98.1% (16230 of 16543)
Covered lines: 16230
Uncovered lines: 313
Coverable lines: 16543
Total lines: 35419
Branch coverage: 94.2% (6234 of 6612)
Covered branches: 6234
Total branches: 6612
Method coverage: Feature is only available for sponsors

Coverage

Kagaku.Flow - 99.7%
Name Line Branch
Kagaku.Flow 99.7% 99.2%
Kagaku.Flow.Budgeting.BudgetRequest 100%
Kagaku.Flow.Budgeting.ConsumerBudget 100%
Kagaku.Flow.Execution.NodeExecution 100% 100%
Kagaku.Flow.Execution.NodeOutcome 100% 100%
Kagaku.Flow.Execution.TransientFailureException 100%
Kagaku.Flow.Execution.Upstream 100%
Kagaku.Flow.Extensions.ServiceCollectionExtensions 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.Runs.LedgerChange 100% 100%
Kagaku.Flow.Runs.LedgerTransitions 100% 100%
Kagaku.Flow.Runs.NodeAttempt 100%
Kagaku.Flow.Runs.NodeFacts 100%
Kagaku.Flow.Runs.NodeRun 100%
Kagaku.Flow.Runs.Run 100% 100%
Kagaku.Flow.Runs.RunEvent 100%
Kagaku.Flow.Runs.RunStatuses 100% 100%
Kagaku.Flow.Runs.RunTrigger 100% 100%
Kagaku.Flow.Scheduling.Exclusion 100%
Kagaku.Flow.Scheduling.FlowEngine 100% 100%
Kagaku.Flow.Scheduling.FlowEngineOptions 100% 100%
Kagaku.Flow.Scheduling.ReadyRow 100%
Kagaku.Flow.Scheduling.ReadySet 100% 100%
Kagaku.Flow.Scheduling.ReadySetResult 100%
Kagaku.Flow.Scheduling.RunRequest 100% 100%
Kagaku.Flow.Scheduling.RunStartResult 100%
Kagaku.Flow.Scheduling.SocketValues 100% 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%
Kagaku.Flow.OpenRouter - 100%
Name Line Branch
Kagaku.Flow.OpenRouter 100% 100%
Kagaku.Flow.OpenRouter.Catalog.ModelCapabilities 100% 100%
Kagaku.Flow.OpenRouter.Gateway.LlmCompletion 100%
Kagaku.Flow.OpenRouter.Gateway.OpenRouterGateway 100% 100%
Kagaku.Flow.OpenRouter.Gateway.OpenRouterGatewayOptions 100%
Kagaku.Flow.OpenRouter.Gateway.OpenRouterKeyLookup 100% 100%
Kagaku.Flow.OpenRouter.Gateway.SentRequestCapture 100% 100%
Kagaku.Flow.OpenRouter.Gateway.SentRequestCaptureHandler 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmAnswer 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmConfig 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmConfigRead 100%
Kagaku.Flow.OpenRouter.Llm.LlmDescriptor 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmExecutor 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmFacts 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmFailureText 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmMessage 100%
Kagaku.Flow.OpenRouter.Llm.LlmRequestBuilder 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmRequestPlan 100%
Kagaku.Flow.OpenRouter.Llm.LlmRoutingDefaults 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmSampling 100%
Kagaku.Flow.OpenRouter.Llm.LlmSchemaCheck 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmStrictSchemaRule 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmVocabulary 100% 100%
Kagaku.Flow.OpenRouter.LlmNodeServiceCollectionExtensions 100%
Kagaku.Flow.OpenRouter.OpenRouterServiceCollectionExtensions 100% 100%
Kagaku.Flow.Testing - 100%
Name Line Branch
Kagaku.Flow.Testing 100% 100%
Kagaku.Flow.Testing.FlowEngineDriver 100% 100%
Kagaku.Flow.Testing.InMemoryRunLedger 100% 100%
Kagaku.Flow.Testing.RecordingRunEventSink 100%
Kagaku.Flow.Testing.RunLedgerContract 100% 100%
Kagaku.Flow.Testing.RunLedgerContractException 100%
Tsumugi.BlazorAdapter - 95.8%
Name Line Branch
Tsumugi.BlazorAdapter 95.8% 91.1%
Tsumugi.BlazorAdapter.BlazorAdapterAssembly 100%
Tsumugi.BlazorAdapter.Documents.CategoryCreated 100%
Tsumugi.BlazorAdapter.Documents.CategoryEditor 93.2% 88.4%
Tsumugi.BlazorAdapter.Documents.CategorySaved 100%
Tsumugi.BlazorAdapter.Documents.ChangeCategoryFieldsRequested 100%
Tsumugi.BlazorAdapter.Documents.CreateCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.CreateDocumentRequested 100%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryChoice 100%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryDialog 100% 94.1%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.DeleteDocumentRequested 100%
Tsumugi.BlazorAdapter.Documents.DocumentAutoSaveFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentCreated 100%
Tsumugi.BlazorAdapter.Documents.DocumentEditor 95.7% 89.4%
Tsumugi.BlazorAdapter.Documents.DocumentImageRefused 100%
Tsumugi.BlazorAdapter.Documents.DocumentImageSet 100%
Tsumugi.BlazorAdapter.Documents.DocumentsActionFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentSaved 100%
Tsumugi.BlazorAdapter.Documents.DocumentsEffects 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsList 98.5% 95%
Tsumugi.BlazorAdapter.Documents.DocumentsLoaded 100%
Tsumugi.BlazorAdapter.Documents.DocumentsPage 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsReadFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentsReducers 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsRefusal 100%
Tsumugi.BlazorAdapter.Documents.DocumentsState 100% 100%
Tsumugi.BlazorAdapter.Documents.FieldInput 100% 96.6%
Tsumugi.BlazorAdapter.Documents.FieldsChanges 100% 100%
Tsumugi.BlazorAdapter.Documents.FieldShapes 90% 87.5%
Tsumugi.BlazorAdapter.Documents.ImageUpload 100%
Tsumugi.BlazorAdapter.Documents.ImageUploadRefusal 100%
Tsumugi.BlazorAdapter.Documents.ImpactText 100% 94.2%
Tsumugi.BlazorAdapter.Documents.LoadDocuments 100%
Tsumugi.BlazorAdapter.Documents.MoveDocumentChoice 100%
Tsumugi.BlazorAdapter.Documents.MoveDocumentDialog 95.6% 71.4%
Tsumugi.BlazorAdapter.Documents.MoveDocumentsRequested 100%
Tsumugi.BlazorAdapter.Documents.ReorderCategoriesRequested 100%
Tsumugi.BlazorAdapter.Documents.SetCategoryCollapsed 100%
Tsumugi.BlazorAdapter.Documents.SetDocumentImageRequested 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.LoadProviderSettings 100%
Tsumugi.BlazorAdapter.Settings.ModelCatalogLoaded 100%
Tsumugi.BlazorAdapter.Settings.ModelCatalogLoadFailed 100%
Tsumugi.BlazorAdapter.Settings.OpenRouterKeySaved 100%
Tsumugi.BlazorAdapter.Settings.OpenRouterKeySaveFailed 100%
Tsumugi.BlazorAdapter.Settings.ProviderKeyChecked 100%
Tsumugi.BlazorAdapter.Settings.ProviderSection 100% 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsEffects 100% 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsLoaded 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsReducers 100% 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsState 100% 100%
Tsumugi.BlazorAdapter.Settings.SaveLlmDefaultsRequested 100%
Tsumugi.BlazorAdapter.Settings.SaveOpenRouterKeyRequested 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.AckWire 100%
Tsumugi.BlazorAdapter.Workspace.AutoSaveFailed 100%
Tsumugi.BlazorAdapter.Workspace.ChangedWire 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 94.4% 83.3%
Tsumugi.BlazorAdapter.Workspace.ChapterWire 100%
Tsumugi.BlazorAdapter.Workspace.ChapterWritten 100%
Tsumugi.BlazorAdapter.Workspace.CreateChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.CreatedWire 100%
Tsumugi.BlazorAdapter.Workspace.DeleteChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.DeltaWire 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.LoadHistory 100%
Tsumugi.BlazorAdapter.Workspace.LoadWorkspace 100%
Tsumugi.BlazorAdapter.Workspace.ManuscriptEffects 100% 100%
Tsumugi.BlazorAdapter.Workspace.ManuscriptEvents 81.8% 74.1%
Tsumugi.BlazorAdapter.Workspace.ManuscriptSurface 89.8% 87.1%
Tsumugi.BlazorAdapter.Workspace.MergeChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.MergeEvent 100%
Tsumugi.BlazorAdapter.Workspace.MoveChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.RedoRequested 100%
Tsumugi.BlazorAdapter.Workspace.RedoRevertRequested 100%
Tsumugi.BlazorAdapter.Workspace.RenameChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.ReshapeEvent 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.SegmentTextEvent 100%
Tsumugi.BlazorAdapter.Workspace.SegmentWire 100% 81.8%
Tsumugi.BlazorAdapter.Workspace.SelectionEndWire 100%
Tsumugi.BlazorAdapter.Workspace.SelectionGraph 100%
Tsumugi.BlazorAdapter.Workspace.SelectionRangeWire 100%
Tsumugi.BlazorAdapter.Workspace.SelectionRunRequested 100%
Tsumugi.BlazorAdapter.Workspace.SetChapterSummaryRequested 100%
Tsumugi.BlazorAdapter.Workspace.SplitEvent 100%
Tsumugi.BlazorAdapter.Workspace.StampWire 0%
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 - 96.3%
Name Line Branch
Tsumugi.Domain 96.3% 95%
System.Text.RegularExpressions.Generated 91.3% 88.6%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__DigitsAndSeparators_2
97.4% 95.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__LineBreak_0
91% 91.1%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__NumberToken_1
91.8% 83.3%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__Plain_4
91.9% 88.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__ThousandsGroup_3
90.9% 84.3%
Tsumugi.Domain.Documents.CategoryFields 94.5% 93.7%
Tsumugi.Domain.Documents.ChoiceOption 100%
Tsumugi.Domain.Documents.ChoiceValue 100%
Tsumugi.Domain.Documents.DateText 100%
Tsumugi.Domain.Documents.DateValue 100%
Tsumugi.Domain.Documents.Document 100% 100%
Tsumugi.Domain.Documents.DocumentCategory 100% 100%
Tsumugi.Domain.Documents.DocumentValues 100%
Tsumugi.Domain.Documents.FieldCarry 100% 100%
Tsumugi.Domain.Documents.FieldConversion 100% 100%
Tsumugi.Domain.Documents.FieldDefinition 97% 95.3%
Tsumugi.Domain.Documents.FieldMessages 100% 100%
Tsumugi.Domain.Documents.FieldNames 100%
Tsumugi.Domain.Documents.FieldsChange 100%
Tsumugi.Domain.Documents.FieldShape 95.2% 87.5%
Tsumugi.Domain.Documents.FieldsPlan 100%
Tsumugi.Domain.Documents.FieldsPlanner 99.2% 99.2%
Tsumugi.Domain.Documents.FieldValue 100%
Tsumugi.Domain.Documents.FieldValues 95.4% 97.7%
Tsumugi.Domain.Documents.ImageFiles 100% 100%
Tsumugi.Domain.Documents.ImageValue 100%
Tsumugi.Domain.Documents.MovePlan 100%
Tsumugi.Domain.Documents.NumberParse 100%
Tsumugi.Domain.Documents.NumberText 100% 97.6%
Tsumugi.Domain.Documents.NumberValue 100%
Tsumugi.Domain.Documents.StoryImage 100%
Tsumugi.Domain.Documents.TextValue 100% 100%
Tsumugi.Domain.Documents.ValueChange 100%
Tsumugi.Domain.Documents.ValueChangeKey 100%
Tsumugi.Domain.Documents.ValueImpact 100% 100%
Tsumugi.Domain.Journal.ChangeLogEntry 97.9% 83.3%
Tsumugi.Domain.Journal.StorySnapshot 95.4% 83.3%
Tsumugi.Domain.Settings.AppSetting 100%
Tsumugi.Domain.Stories.Chapter 100% 100%
Tsumugi.Domain.Stories.InlineMarkup 100% 100%
Tsumugi.Domain.Stories.MarkupRun 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 - 98.3%
Name Line Branch
Tsumugi.Infrastructure 98.3% 86.8%
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.6% 87.5%
Tsumugi.Infrastructure.Backups.BackupWriter 98.5% 92.8%
Tsumugi.Infrastructure.Backups.DatabaseFingerprint 91.9% 97%
Tsumugi.Infrastructure.Backups.FileSystemBackupStore 100% 100%
Tsumugi.Infrastructure.Backups.OwnerOnlyFile 100% 100%
Tsumugi.Infrastructure.Backups.PreMigrationBackup 90% 100%
Tsumugi.Infrastructure.Backups.SqliteSnapshot 88.2% 75%
Tsumugi.Infrastructure.DependencyInjection 100% 100%
Tsumugi.Infrastructure.Journal.EfChangeJournal 100%
Tsumugi.Infrastructure.Journal.EfSnapshotStore 100%
Tsumugi.Infrastructure.Journal.EfUndoStore 98.5% 88.2%
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.StoryImageConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.StorySnapshotConfiguratio
n
100%
Tsumugi.Infrastructure.Persistence.Converters.CanonicalJsonComparer 100%
Tsumugi.Infrastructure.Persistence.Converters.CategoryFieldsConverter 97.6% 94.4%
Tsumugi.Infrastructure.Persistence.Converters.FieldValuesConverter 96.9% 93.7%
Tsumugi.Infrastructure.Persistence.Converters.ProvenanceConverter 100% 90%
Tsumugi.Infrastructure.Persistence.Converters.UtcTicksConverter 100%
Tsumugi.Infrastructure.Persistence.Converters.WireFormat 85.7% 73.8%
Tsumugi.Infrastructure.Persistence.Migrations.AddAppSettings 99.2%
Tsumugi.Infrastructure.Persistence.Migrations.AddJournal 98.8%
Tsumugi.Infrastructure.Persistence.Migrations.CategoryFields 100% 100%
Tsumugi.Infrastructure.Persistence.Migrations.CategoryFieldsSql 100%
Tsumugi.Infrastructure.Persistence.Migrations.DropDocumentBody 100%
Tsumugi.Infrastructure.Persistence.Migrations.GenericDocuments 100%
Tsumugi.Infrastructure.Persistence.Migrations.InitialStoryDomain 97.3%
Tsumugi.Infrastructure.Persistence.Migrations.JournalUndoState 100%
Tsumugi.Infrastructure.Persistence.Migrations.SegmentTextMarkup 100% 100%
Tsumugi.Infrastructure.Persistence.Migrations.SegmentTextMarkupSql 100%
Tsumugi.Infrastructure.Persistence.Migrations.StoryImages 100%
Tsumugi.Infrastructure.Persistence.Migrations.TsumugiDbContextModelSnapshot 100%
Tsumugi.Infrastructure.Persistence.SqliteFunctions 80% 66.6%
Tsumugi.Infrastructure.Persistence.SqlitePragmaInterceptor 100% 100%
Tsumugi.Infrastructure.Persistence.Stores.EfChapterStore 100% 100%
Tsumugi.Infrastructure.Persistence.Stores.EfDocumentStore 98.3% 75%
Tsumugi.Infrastructure.Persistence.Stores.EfImageStore 100%
Tsumugi.Infrastructure.Persistence.Stores.EfSegmentStore 96.6% 84.6%
Tsumugi.Infrastructure.Persistence.Stores.EfStoryStore 98.7% 90%
Tsumugi.Infrastructure.Persistence.TsumugiDbContext 97.7% 96.6%
Tsumugi.Infrastructure.Persistence.TsumugiDbContextFactory 100%
Tsumugi.Infrastructure.Provider.LlmDefaultsSource 100%
Tsumugi.Infrastructure.Provider.OpenRouterKeySource 100% 100%
Tsumugi.Infrastructure.Provider.OpenRouterModelProvider 100% 100%
Tsumugi.Infrastructure.Provider.OpenRouterOptions 100% 100%
Tsumugi.Infrastructure.Provider.ResolvedKey 100%
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% 92.1%
Program 100% 100%
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.Provider.OpenRouterConfiguration 100% 100%
Tsumugi.Server.Security.AccessGate 100% 87.5%
Tsumugi.Server.Security.AccessSecret 100% 100%
Tsumugi.Server.Security.GateThrottle 100% 100%
Tsumugi.Server.VolumeStartupValidator 100% 100%
Tsumugi.UseCases - 98.5%
Name Line Branch
Tsumugi.UseCases 98.5% 95.8%
System.Text.RegularExpressions.Generated 90.9% 77.2%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6504F1744AA254A
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__LineBreaks_0
95.3% 90.6%
Tsumugi.UseCases.Backups.BackupArtifact 100%
Tsumugi.UseCases.Backups.BackupFailure 100%
Tsumugi.UseCases.Backups.BackupJobState 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.IBackupStore 0%
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.GetChapterSegments 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.Context.AssembledContext 100%
Tsumugi.UseCases.Context.CharsPerToken 100% 100%
Tsumugi.UseCases.Context.ConsumerFigures 100%
Tsumugi.UseCases.Context.ContextAssembly 100% 100%
Tsumugi.UseCases.Context.ContextBuild 100%
Tsumugi.UseCases.Context.ContextBuilder 100%
Tsumugi.UseCases.Context.ContextConfig 100% 100%
Tsumugi.UseCases.Context.ContextConfigRead 100%
Tsumugi.UseCases.Context.ContextConsumerRule 100% 100%
Tsumugi.UseCases.Context.ContextDescriptor 100%
Tsumugi.UseCases.Context.ContextExecutor 100% 100%
Tsumugi.UseCases.Context.ContextParts 100%
Tsumugi.UseCases.Context.ContextReport 100%
Tsumugi.UseCases.Context.DocumentRendering 100% 100%
Tsumugi.UseCases.Context.NoPromptSamples 100%
Tsumugi.UseCases.Context.PromptSample 100%
Tsumugi.UseCases.Context.RecentParagraph 100%
Tsumugi.UseCases.Context.StoryDocumentsRule 100% 100%
Tsumugi.UseCases.Context.StoryReads 100% 100%
Tsumugi.UseCases.Context.StoryScope 100% 100%
Tsumugi.UseCases.Context.StoryTemplateModel 100%
Tsumugi.UseCases.Context.StoryText 100% 100%
Tsumugi.UseCases.DependencyInjection 100%
Tsumugi.UseCases.Diagnostics.SeedDevData 98.3% 68.7%
Tsumugi.UseCases.Diagnostics.SeedPictures 100%
Tsumugi.UseCases.Documents.ChangeCategoryFields 100% 83.3%
Tsumugi.UseCases.Documents.CreateCategory 100% 100%
Tsumugi.UseCases.Documents.CreateDocument 100% 100%
Tsumugi.UseCases.Documents.DefaultFields 100% 100%
Tsumugi.UseCases.Documents.DeleteCategory 100% 94.4%
Tsumugi.UseCases.Documents.DeleteDocument 100% 100%
Tsumugi.UseCases.Documents.DocumentCategoryDto 100%
Tsumugi.UseCases.Documents.DocumentCategoryProfile 100%
Tsumugi.UseCases.Documents.DocumentDto 100%
Tsumugi.UseCases.Documents.DocumentPatch 100%
Tsumugi.UseCases.Documents.DocumentProfile 100%
Tsumugi.UseCases.Documents.DocumentsCategory 100%
Tsumugi.UseCases.Documents.DocumentsView 100%
Tsumugi.UseCases.Documents.DocumentWrites 100% 100%
Tsumugi.UseCases.Documents.FieldsChangeLabel 95.4% 88.2%
Tsumugi.UseCases.Documents.GetDocuments 100% 100%
Tsumugi.UseCases.Documents.GetStoryImage 100% 100%
Tsumugi.UseCases.Documents.ImpactPreview 100% 100%
Tsumugi.UseCases.Documents.LossMessages 92.3% 87.5%
Tsumugi.UseCases.Documents.MoveDocuments 100% 100%
Tsumugi.UseCases.Documents.ReorderCategories 100% 100%
Tsumugi.UseCases.Documents.SetDocumentImage 100% 93.7%
Tsumugi.UseCases.Documents.StoryImageFile 100%
Tsumugi.UseCases.Documents.UpdateCategory 100% 100%
Tsumugi.UseCases.Documents.UpdateDocument 100% 81.2%
Tsumugi.UseCases.Documents.WriteRefusedException 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 90.9% 87.5%
Tsumugi.UseCases.Journal.RedoTyping 100% 100%
Tsumugi.UseCases.Journal.ReplayLanding 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.ChangedText 100%
Tsumugi.UseCases.Segments.ChapterDraft 100%
Tsumugi.UseCases.Segments.ChapterWriting 100%
Tsumugi.UseCases.Segments.DeleteSegments 100% 100%
Tsumugi.UseCases.Segments.EditSegment 100% 100%
Tsumugi.UseCases.Segments.InsertSegment 100% 100%
Tsumugi.UseCases.Segments.ManuscriptAnswer 100%
Tsumugi.UseCases.Segments.ManuscriptWrites 99.1% 97.6%
Tsumugi.UseCases.Segments.MergeSegments 100%
Tsumugi.UseCases.Segments.MergeWrite 100%
Tsumugi.UseCases.Segments.ModelOutput 98.2% 96.6%
Tsumugi.UseCases.Segments.ModelParagraph 100%
Tsumugi.UseCases.Segments.MoveSegments 100% 100%
Tsumugi.UseCases.Segments.NewBlock 100%
Tsumugi.UseCases.Segments.ReadSelection 100%
Tsumugi.UseCases.Segments.ReorderSegments 100% 100%
Tsumugi.UseCases.Segments.ReshapeSegments 100% 100%
Tsumugi.UseCases.Segments.ReshapeWrite 100%
Tsumugi.UseCases.Segments.SegmentDto 100%
Tsumugi.UseCases.Segments.SelectedSegment 100%
Tsumugi.UseCases.Segments.SelectionEnd 100%
Tsumugi.UseCases.Segments.SelectionInput 100% 100%
Tsumugi.UseCases.Segments.SplitSegment 100%
Tsumugi.UseCases.Segments.SplitWrite 100%
Tsumugi.UseCases.Segments.StampedId 100%
Tsumugi.UseCases.Segments.TextWrite 100%
Tsumugi.UseCases.Settings.CatalogModel 100% 100%
Tsumugi.UseCases.Settings.CheckOpenRouterKey 100%
Tsumugi.UseCases.Settings.GetLlmDefaults 100% 100%
Tsumugi.UseCases.Settings.GetModelCatalog 100% 100%
Tsumugi.UseCases.Settings.GetProviderSettings 100%
Tsumugi.UseCases.Settings.LlmDefaults 100%
Tsumugi.UseCases.Settings.ProviderKeyInfo 100%
Tsumugi.UseCases.Settings.ProviderKeyState 100%
Tsumugi.UseCases.Settings.ProviderSettingsView 100% 100%
Tsumugi.UseCases.Settings.ReasoningEfforts 100% 100%
Tsumugi.UseCases.Settings.RemoveOpenRouterKey 100%
Tsumugi.UseCases.Settings.RoutingDefaults 100%
Tsumugi.UseCases.Settings.RoutingSettings 100% 100%
Tsumugi.UseCases.Settings.SaveLlmDefaults 100% 100%
Tsumugi.UseCases.Settings.SaveOpenRouterKey 100% 100%
Tsumugi.UseCases.Stories.ChapterWriteOutcome 50%
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:** `d1c5967` · **Generated:** 2026-09-26 18:49:38 UTC · **Revision:** #3 # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 09/26/2026 - 18:49:38 | | Coverage date: | 09/26/2026 - 18:49:07 - 09/26/2026 - 18:49:34 | | Parser: | MultiReport (6x Cobertura) | | Assemblies: | 9 | | Classes: | 524 | | Files: | 463 | | **Line coverage:** | 98.1% (16230 of 16543) | | Covered lines: | 16230 | | Uncovered lines: | 313 | | Coverable lines: | 16543 | | Total lines: | 35419 | | **Branch coverage:** | 94.2% (6234 of 6612) | | Covered branches: | 6234 | | Total branches: | 6612 | | **Method coverage:** | [Feature is only available for sponsors](https://reportgenerator.io/pro) | </details> ## Coverage <details><summary>Kagaku.Flow - 99.7%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.Flow**|**99.7%**|**99.2%**| |Kagaku.Flow.Budgeting.BudgetRequest|100%|| |Kagaku.Flow.Budgeting.ConsumerBudget|100%|| |Kagaku.Flow.Execution.NodeExecution|100%|100%| |Kagaku.Flow.Execution.NodeOutcome|100%|100%| |Kagaku.Flow.Execution.TransientFailureException|100%|| |Kagaku.Flow.Execution.Upstream|100%|| |Kagaku.Flow.Extensions.ServiceCollectionExtensions|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.Runs.LedgerChange|100%|100%| |Kagaku.Flow.Runs.LedgerTransitions|100%|100%| |Kagaku.Flow.Runs.NodeAttempt|100%|| |Kagaku.Flow.Runs.NodeFacts|100%|| |Kagaku.Flow.Runs.NodeRun|100%|| |Kagaku.Flow.Runs.Run|100%|100%| |Kagaku.Flow.Runs.RunEvent|100%|| |Kagaku.Flow.Runs.RunStatuses|100%|100%| |Kagaku.Flow.Runs.RunTrigger|100%|100%| |Kagaku.Flow.Scheduling.Exclusion|100%|| |Kagaku.Flow.Scheduling.FlowEngine|100%|100%| |Kagaku.Flow.Scheduling.FlowEngineOptions|100%|100%| |Kagaku.Flow.Scheduling.ReadyRow|100%|| |Kagaku.Flow.Scheduling.ReadySet|100%|100%| |Kagaku.Flow.Scheduling.ReadySetResult|100%|| |Kagaku.Flow.Scheduling.RunRequest|100%|100%| |Kagaku.Flow.Scheduling.RunStartResult|100%|| |Kagaku.Flow.Scheduling.SocketValues|100%|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>Kagaku.Flow.OpenRouter - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.Flow.OpenRouter**|**100%**|**100%**| |Kagaku.Flow.OpenRouter.Catalog.ModelCapabilities|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.LlmCompletion|100%|| |Kagaku.Flow.OpenRouter.Gateway.OpenRouterGateway|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.OpenRouterGatewayOptions|100%|| |Kagaku.Flow.OpenRouter.Gateway.OpenRouterKeyLookup|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.SentRequestCapture|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.SentRequestCaptureHandler|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmAnswer|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmConfig|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmConfigRead|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmDescriptor|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmExecutor|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmFacts|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmFailureText|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmMessage|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmRequestBuilder|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmRequestPlan|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmRoutingDefaults|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmSampling|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmSchemaCheck|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmStrictSchemaRule|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmVocabulary|100%|100%| |Kagaku.Flow.OpenRouter.LlmNodeServiceCollectionExtensions|100%|| |Kagaku.Flow.OpenRouter.OpenRouterServiceCollectionExtensions|100%|100%| </details> <details><summary>Kagaku.Flow.Testing - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.Flow.Testing**|**100%**|**100%**| |Kagaku.Flow.Testing.FlowEngineDriver|100%|100%| |Kagaku.Flow.Testing.InMemoryRunLedger|100%|100%| |Kagaku.Flow.Testing.RecordingRunEventSink|100%|| |Kagaku.Flow.Testing.RunLedgerContract|100%|100%| |Kagaku.Flow.Testing.RunLedgerContractException|100%|| </details> <details><summary>Tsumugi.BlazorAdapter - 95.8%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.BlazorAdapter**|**95.8%**|**91.1%**| |Tsumugi.BlazorAdapter.BlazorAdapterAssembly|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryCreated|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryEditor|93.2%|88.4%| |Tsumugi.BlazorAdapter.Documents.CategorySaved|100%|| |Tsumugi.BlazorAdapter.Documents.ChangeCategoryFieldsRequested|100%|| |Tsumugi.BlazorAdapter.Documents.CreateCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.CreateDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryChoice|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryDialog|100%|94.1%| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentAutoSaveFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentCreated|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentEditor|95.7%|89.4%| |Tsumugi.BlazorAdapter.Documents.DocumentImageRefused|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentImageSet|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsActionFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentSaved|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsEffects|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsList|98.5%|95%| |Tsumugi.BlazorAdapter.Documents.DocumentsLoaded|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsPage|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsReadFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsReducers|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsRefusal|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsState|100%|100%| |Tsumugi.BlazorAdapter.Documents.FieldInput|100%|96.6%| |Tsumugi.BlazorAdapter.Documents.FieldsChanges|100%|100%| |Tsumugi.BlazorAdapter.Documents.FieldShapes|90%|87.5%| |Tsumugi.BlazorAdapter.Documents.ImageUpload|100%|| |Tsumugi.BlazorAdapter.Documents.ImageUploadRefusal|100%|| |Tsumugi.BlazorAdapter.Documents.ImpactText|100%|94.2%| |Tsumugi.BlazorAdapter.Documents.LoadDocuments|100%|| |Tsumugi.BlazorAdapter.Documents.MoveDocumentChoice|100%|| |Tsumugi.BlazorAdapter.Documents.MoveDocumentDialog|95.6%|71.4%| |Tsumugi.BlazorAdapter.Documents.MoveDocumentsRequested|100%|| |Tsumugi.BlazorAdapter.Documents.ReorderCategoriesRequested|100%|| |Tsumugi.BlazorAdapter.Documents.SetCategoryCollapsed|100%|| |Tsumugi.BlazorAdapter.Documents.SetDocumentImageRequested|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.LoadProviderSettings|100%|| |Tsumugi.BlazorAdapter.Settings.ModelCatalogLoaded|100%|| |Tsumugi.BlazorAdapter.Settings.ModelCatalogLoadFailed|100%|| |Tsumugi.BlazorAdapter.Settings.OpenRouterKeySaved|100%|| |Tsumugi.BlazorAdapter.Settings.OpenRouterKeySaveFailed|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderKeyChecked|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderSection|100%|100%| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsEffects|100%|100%| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsLoaded|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsReducers|100%|100%| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsState|100%|100%| |Tsumugi.BlazorAdapter.Settings.SaveLlmDefaultsRequested|100%|| |Tsumugi.BlazorAdapter.Settings.SaveOpenRouterKeyRequested|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.AckWire|100%|| |Tsumugi.BlazorAdapter.Workspace.AutoSaveFailed|100%|| |Tsumugi.BlazorAdapter.Workspace.ChangedWire|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|94.4%|83.3%| |Tsumugi.BlazorAdapter.Workspace.ChapterWire|100%|| |Tsumugi.BlazorAdapter.Workspace.ChapterWritten|100%|| |Tsumugi.BlazorAdapter.Workspace.CreateChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.CreatedWire|100%|| |Tsumugi.BlazorAdapter.Workspace.DeleteChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.DeltaWire|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.LoadHistory|100%|| |Tsumugi.BlazorAdapter.Workspace.LoadWorkspace|100%|| |Tsumugi.BlazorAdapter.Workspace.ManuscriptEffects|100%|100%| |Tsumugi.BlazorAdapter.Workspace.ManuscriptEvents|81.8%|74.1%| |Tsumugi.BlazorAdapter.Workspace.ManuscriptSurface|89.8%|87.1%| |Tsumugi.BlazorAdapter.Workspace.MergeChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.MergeEvent|100%|| |Tsumugi.BlazorAdapter.Workspace.MoveChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RedoRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RedoRevertRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RenameChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.ReshapeEvent|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.SegmentTextEvent|100%|| |Tsumugi.BlazorAdapter.Workspace.SegmentWire|100%|81.8%| |Tsumugi.BlazorAdapter.Workspace.SelectionEndWire|100%|| |Tsumugi.BlazorAdapter.Workspace.SelectionGraph|100%|| |Tsumugi.BlazorAdapter.Workspace.SelectionRangeWire|100%|| |Tsumugi.BlazorAdapter.Workspace.SelectionRunRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.SetChapterSummaryRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.SplitEvent|100%|| |Tsumugi.BlazorAdapter.Workspace.StampWire|0%|| |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 - 96.3%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Domain**|**96.3%**|**95%**| |System.Text.RegularExpressions.Generated|91.3%|88.6%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__DigitsAndSeparators_2|97.4%|95.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__LineBreak_0|91%|91.1%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__NumberToken_1|91.8%|83.3%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__Plain_4|91.9%|88.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__ThousandsGroup_3|90.9%|84.3%| |Tsumugi.Domain.Documents.CategoryFields|94.5%|93.7%| |Tsumugi.Domain.Documents.ChoiceOption|100%|| |Tsumugi.Domain.Documents.ChoiceValue|100%|| |Tsumugi.Domain.Documents.DateText|100%|| |Tsumugi.Domain.Documents.DateValue|100%|| |Tsumugi.Domain.Documents.Document|100%|100%| |Tsumugi.Domain.Documents.DocumentCategory|100%|100%| |Tsumugi.Domain.Documents.DocumentValues|100%|| |Tsumugi.Domain.Documents.FieldCarry|100%|100%| |Tsumugi.Domain.Documents.FieldConversion|100%|100%| |Tsumugi.Domain.Documents.FieldDefinition|97%|95.3%| |Tsumugi.Domain.Documents.FieldMessages|100%|100%| |Tsumugi.Domain.Documents.FieldNames|100%|| |Tsumugi.Domain.Documents.FieldsChange|100%|| |Tsumugi.Domain.Documents.FieldShape|95.2%|87.5%| |Tsumugi.Domain.Documents.FieldsPlan|100%|| |Tsumugi.Domain.Documents.FieldsPlanner|99.2%|99.2%| |Tsumugi.Domain.Documents.FieldValue|100%|| |Tsumugi.Domain.Documents.FieldValues|95.4%|97.7%| |Tsumugi.Domain.Documents.ImageFiles|100%|100%| |Tsumugi.Domain.Documents.ImageValue|100%|| |Tsumugi.Domain.Documents.MovePlan|100%|| |Tsumugi.Domain.Documents.NumberParse|100%|| |Tsumugi.Domain.Documents.NumberText|100%|97.6%| |Tsumugi.Domain.Documents.NumberValue|100%|| |Tsumugi.Domain.Documents.StoryImage|100%|| |Tsumugi.Domain.Documents.TextValue|100%|100%| |Tsumugi.Domain.Documents.ValueChange|100%|| |Tsumugi.Domain.Documents.ValueChangeKey|100%|| |Tsumugi.Domain.Documents.ValueImpact|100%|100%| |Tsumugi.Domain.Journal.ChangeLogEntry|97.9%|83.3%| |Tsumugi.Domain.Journal.StorySnapshot|95.4%|83.3%| |Tsumugi.Domain.Settings.AppSetting|100%|| |Tsumugi.Domain.Stories.Chapter|100%|100%| |Tsumugi.Domain.Stories.InlineMarkup|100%|100%| |Tsumugi.Domain.Stories.MarkupRun|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 - 98.3%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Infrastructure**|**98.3%**|**86.8%**| |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.6%|87.5%| |Tsumugi.Infrastructure.Backups.BackupWriter|98.5%|92.8%| |Tsumugi.Infrastructure.Backups.DatabaseFingerprint|91.9%|97%| |Tsumugi.Infrastructure.Backups.FileSystemBackupStore|100%|100%| |Tsumugi.Infrastructure.Backups.OwnerOnlyFile|100%|100%| |Tsumugi.Infrastructure.Backups.PreMigrationBackup|90%|100%| |Tsumugi.Infrastructure.Backups.SqliteSnapshot|88.2%|75%| |Tsumugi.Infrastructure.DependencyInjection|100%|100%| |Tsumugi.Infrastructure.Journal.EfChangeJournal|100%|| |Tsumugi.Infrastructure.Journal.EfSnapshotStore|100%|| |Tsumugi.Infrastructure.Journal.EfUndoStore|98.5%|88.2%| |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.StoryImageConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.StorySnapshotConfiguratio<br/>n|100%|| |Tsumugi.Infrastructure.Persistence.Converters.CanonicalJsonComparer|100%|| |Tsumugi.Infrastructure.Persistence.Converters.CategoryFieldsConverter|97.6%|94.4%| |Tsumugi.Infrastructure.Persistence.Converters.FieldValuesConverter|96.9%|93.7%| |Tsumugi.Infrastructure.Persistence.Converters.ProvenanceConverter|100%|90%| |Tsumugi.Infrastructure.Persistence.Converters.UtcTicksConverter|100%|| |Tsumugi.Infrastructure.Persistence.Converters.WireFormat|85.7%|73.8%| |Tsumugi.Infrastructure.Persistence.Migrations.AddAppSettings|99.2%|| |Tsumugi.Infrastructure.Persistence.Migrations.AddJournal|98.8%|| |Tsumugi.Infrastructure.Persistence.Migrations.CategoryFields|100%|100%| |Tsumugi.Infrastructure.Persistence.Migrations.CategoryFieldsSql|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.DropDocumentBody|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.GenericDocuments|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.InitialStoryDomain|97.3%|| |Tsumugi.Infrastructure.Persistence.Migrations.JournalUndoState|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.SegmentTextMarkup|100%|100%| |Tsumugi.Infrastructure.Persistence.Migrations.SegmentTextMarkupSql|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.StoryImages|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.TsumugiDbContextModelSnapshot|100%|| |Tsumugi.Infrastructure.Persistence.SqliteFunctions|80%|66.6%| |Tsumugi.Infrastructure.Persistence.SqlitePragmaInterceptor|100%|100%| |Tsumugi.Infrastructure.Persistence.Stores.EfChapterStore|100%|100%| |Tsumugi.Infrastructure.Persistence.Stores.EfDocumentStore|98.3%|75%| |Tsumugi.Infrastructure.Persistence.Stores.EfImageStore|100%|| |Tsumugi.Infrastructure.Persistence.Stores.EfSegmentStore|96.6%|84.6%| |Tsumugi.Infrastructure.Persistence.Stores.EfStoryStore|98.7%|90%| |Tsumugi.Infrastructure.Persistence.TsumugiDbContext|97.7%|96.6%| |Tsumugi.Infrastructure.Persistence.TsumugiDbContextFactory|100%|| |Tsumugi.Infrastructure.Provider.LlmDefaultsSource|100%|| |Tsumugi.Infrastructure.Provider.OpenRouterKeySource|100%|100%| |Tsumugi.Infrastructure.Provider.OpenRouterModelProvider|100%|100%| |Tsumugi.Infrastructure.Provider.OpenRouterOptions|100%|100%| |Tsumugi.Infrastructure.Provider.ResolvedKey|100%|| |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%**|**92.1%**| |Program|100%|100%| |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.Provider.OpenRouterConfiguration|100%|100%| |Tsumugi.Server.Security.AccessGate|100%|87.5%| |Tsumugi.Server.Security.AccessSecret|100%|100%| |Tsumugi.Server.Security.GateThrottle|100%|100%| |Tsumugi.Server.VolumeStartupValidator|100%|100%| </details> <details><summary>Tsumugi.UseCases - 98.5%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.UseCases**|**98.5%**|**95.8%**| |System.Text.RegularExpressions.Generated|90.9%|77.2%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6504F1744AA254A<br/>663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__LineBreaks_0|95.3%|90.6%| |Tsumugi.UseCases.Backups.BackupArtifact|100%|| |Tsumugi.UseCases.Backups.BackupFailure|100%|| |Tsumugi.UseCases.Backups.BackupJobState|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.IBackupStore|0%|| |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.GetChapterSegments|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.Context.AssembledContext|100%|| |Tsumugi.UseCases.Context.CharsPerToken|100%|100%| |Tsumugi.UseCases.Context.ConsumerFigures|100%|| |Tsumugi.UseCases.Context.ContextAssembly|100%|100%| |Tsumugi.UseCases.Context.ContextBuild|100%|| |Tsumugi.UseCases.Context.ContextBuilder|100%|| |Tsumugi.UseCases.Context.ContextConfig|100%|100%| |Tsumugi.UseCases.Context.ContextConfigRead|100%|| |Tsumugi.UseCases.Context.ContextConsumerRule|100%|100%| |Tsumugi.UseCases.Context.ContextDescriptor|100%|| |Tsumugi.UseCases.Context.ContextExecutor|100%|100%| |Tsumugi.UseCases.Context.ContextParts|100%|| |Tsumugi.UseCases.Context.ContextReport|100%|| |Tsumugi.UseCases.Context.DocumentRendering|100%|100%| |Tsumugi.UseCases.Context.NoPromptSamples|100%|| |Tsumugi.UseCases.Context.PromptSample|100%|| |Tsumugi.UseCases.Context.RecentParagraph|100%|| |Tsumugi.UseCases.Context.StoryDocumentsRule|100%|100%| |Tsumugi.UseCases.Context.StoryReads|100%|100%| |Tsumugi.UseCases.Context.StoryScope|100%|100%| |Tsumugi.UseCases.Context.StoryTemplateModel|100%|| |Tsumugi.UseCases.Context.StoryText|100%|100%| |Tsumugi.UseCases.DependencyInjection|100%|| |Tsumugi.UseCases.Diagnostics.SeedDevData|98.3%|68.7%| |Tsumugi.UseCases.Diagnostics.SeedPictures|100%|| |Tsumugi.UseCases.Documents.ChangeCategoryFields|100%|83.3%| |Tsumugi.UseCases.Documents.CreateCategory|100%|100%| |Tsumugi.UseCases.Documents.CreateDocument|100%|100%| |Tsumugi.UseCases.Documents.DefaultFields|100%|100%| |Tsumugi.UseCases.Documents.DeleteCategory|100%|94.4%| |Tsumugi.UseCases.Documents.DeleteDocument|100%|100%| |Tsumugi.UseCases.Documents.DocumentCategoryDto|100%|| |Tsumugi.UseCases.Documents.DocumentCategoryProfile|100%|| |Tsumugi.UseCases.Documents.DocumentDto|100%|| |Tsumugi.UseCases.Documents.DocumentPatch|100%|| |Tsumugi.UseCases.Documents.DocumentProfile|100%|| |Tsumugi.UseCases.Documents.DocumentsCategory|100%|| |Tsumugi.UseCases.Documents.DocumentsView|100%|| |Tsumugi.UseCases.Documents.DocumentWrites|100%|100%| |Tsumugi.UseCases.Documents.FieldsChangeLabel|95.4%|88.2%| |Tsumugi.UseCases.Documents.GetDocuments|100%|100%| |Tsumugi.UseCases.Documents.GetStoryImage|100%|100%| |Tsumugi.UseCases.Documents.ImpactPreview|100%|100%| |Tsumugi.UseCases.Documents.LossMessages|92.3%|87.5%| |Tsumugi.UseCases.Documents.MoveDocuments|100%|100%| |Tsumugi.UseCases.Documents.ReorderCategories|100%|100%| |Tsumugi.UseCases.Documents.SetDocumentImage|100%|93.7%| |Tsumugi.UseCases.Documents.StoryImageFile|100%|| |Tsumugi.UseCases.Documents.UpdateCategory|100%|100%| |Tsumugi.UseCases.Documents.UpdateDocument|100%|81.2%| |Tsumugi.UseCases.Documents.WriteRefusedException|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|90.9%|87.5%| |Tsumugi.UseCases.Journal.RedoTyping|100%|100%| |Tsumugi.UseCases.Journal.ReplayLanding|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.ChangedText|100%|| |Tsumugi.UseCases.Segments.ChapterDraft|100%|| |Tsumugi.UseCases.Segments.ChapterWriting|100%|| |Tsumugi.UseCases.Segments.DeleteSegments|100%|100%| |Tsumugi.UseCases.Segments.EditSegment|100%|100%| |Tsumugi.UseCases.Segments.InsertSegment|100%|100%| |Tsumugi.UseCases.Segments.ManuscriptAnswer|100%|| |Tsumugi.UseCases.Segments.ManuscriptWrites|99.1%|97.6%| |Tsumugi.UseCases.Segments.MergeSegments|100%|| |Tsumugi.UseCases.Segments.MergeWrite|100%|| |Tsumugi.UseCases.Segments.ModelOutput|98.2%|96.6%| |Tsumugi.UseCases.Segments.ModelParagraph|100%|| |Tsumugi.UseCases.Segments.MoveSegments|100%|100%| |Tsumugi.UseCases.Segments.NewBlock|100%|| |Tsumugi.UseCases.Segments.ReadSelection|100%|| |Tsumugi.UseCases.Segments.ReorderSegments|100%|100%| |Tsumugi.UseCases.Segments.ReshapeSegments|100%|100%| |Tsumugi.UseCases.Segments.ReshapeWrite|100%|| |Tsumugi.UseCases.Segments.SegmentDto|100%|| |Tsumugi.UseCases.Segments.SelectedSegment|100%|| |Tsumugi.UseCases.Segments.SelectionEnd|100%|| |Tsumugi.UseCases.Segments.SelectionInput|100%|100%| |Tsumugi.UseCases.Segments.SplitSegment|100%|| |Tsumugi.UseCases.Segments.SplitWrite|100%|| |Tsumugi.UseCases.Segments.StampedId|100%|| |Tsumugi.UseCases.Segments.TextWrite|100%|| |Tsumugi.UseCases.Settings.CatalogModel|100%|100%| |Tsumugi.UseCases.Settings.CheckOpenRouterKey|100%|| |Tsumugi.UseCases.Settings.GetLlmDefaults|100%|100%| |Tsumugi.UseCases.Settings.GetModelCatalog|100%|100%| |Tsumugi.UseCases.Settings.GetProviderSettings|100%|| |Tsumugi.UseCases.Settings.LlmDefaults|100%|| |Tsumugi.UseCases.Settings.ProviderKeyInfo|100%|| |Tsumugi.UseCases.Settings.ProviderKeyState|100%|| |Tsumugi.UseCases.Settings.ProviderSettingsView|100%|100%| |Tsumugi.UseCases.Settings.ReasoningEfforts|100%|100%| |Tsumugi.UseCases.Settings.RemoveOpenRouterKey|100%|| |Tsumugi.UseCases.Settings.RoutingDefaults|100%|| |Tsumugi.UseCases.Settings.RoutingSettings|100%|100%| |Tsumugi.UseCases.Settings.SaveLlmDefaults|100%|100%| |Tsumugi.UseCases.Settings.SaveOpenRouterKey|100%|100%| |Tsumugi.UseCases.Stories.ChapterWriteOutcome|50%|| |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>
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh my~ The story half's crown jewel! A node that asks its consumers what fits before it assembles a single character — budgeting, folding, yielding, all of it pure as fresh snow. I read all 2,871 lines of the diff, every new file in full, walked the assembly math character by character, and probed the branches with my own hands~ ♡

Verdict: ✅ Looks good to me~

No blockers. Nothing even smells. The two pre-open review passes left me almost nothing to sharpen — so I went and verified their work instead, and it all holds.

✅ What I liked~

  • The budget pipeline is a joy. IBudgetedConsumer → GetBudgetAsync per edge → CharsPerToken.Fold (EMA, first sample replaces the seed — one request is enough) → Budget() → smallest consumer wins. long end-to-end, the int.MaxValue window case tested, negative budget (overhead alone doesn't fit) flows into a named permanent failure with figures attached. Beautiful.
  • CharsPerToken.Budget and ContextAssembly never drift: the executor computes the same Math.Floor(share * Math.Max(budget, 0)) limit the assembly caps against — and my probe flipping MinBy→MaxBy reddened exactly The_smallest_consumer_sets_the_budget_at_its_models_ratio. Every branch I mutated died on its own pin: Korean particle exception (3 red), window word-start guard (4 red), yield ordering (3 red), the sub-1 margin clamp against decimal→double rounding (1 red), near-end placement arithmetic (2 red), fixed-before-dynamic header ordering (1 red), and the trigger window's fixed-header join (1 red, A_fixed_header_document_that_names_a_dynamic_one_activates_it). Seven kills, tree restored pristine after each.
  • Korean gets particles right without a dictionary. 안셀 fires in 안셀은, 사진 doesn't fire for 진, and the honest 미라클/미라는 concession is written into the ADR and the doc comment. The script ranges are pinned row by row — 㐀 extension A, \uFA0E compatibility ideograph (the one NFC keeps!), Thai, halfwidth katakana, kana starting at the CJK symbols so 時々 doesn't eat a name. Someone cares~ ♡
  • The config reader is a small theorem. Every problem at a JSON pointer, Read and the schema agreeing on all structural rules (57 theory rows), with the schema-blind arms — Unicode-blank names, decimal's 28 digits — isolated in ValidateConfig_refuses_what_the_schema_cannot_express. The Math.BitDecrement clamp for margins just below 1 is exactly the kind of trap most people learn about in production~
  • The share/yield loop and the recent-text walk are pure and pinned: lowest priority yields from its last document (Insert(0, …) order probed), whole segments only, never opens with a scene break, near-end documents count in Recent()'s arithmetic or the fixed-parts refusal fires — the Near_end_documents_larger_than_the_budget_are_refused_even_without_a_paragraph case is the one nobody remembers to test. You remembered.
  • Failure taxonomy follows ADR 0016/0017 precisely: transient catalog failure retries (attempt 2 of 3 observed in The_consumer_is_asked_with_the_other_inputs_known_when_it_asks), permanent refusals carry Facts with the consumers' figures, gone stories and room-less consumers report what they knew. The catch … when (e.Message == StoryScope.StoryNotFound) mirrors StoryTemplateModel's sibling shape exactly.
  • The IPromptSamples seam — NoPromptSamples until 11a, registered via plain TryAddSingleton so the ledger implementation replaces it, planned in PROJECT_PLAN. A port instead of a premature query~ exactly the architectural fix I'd demand.
  • The rule catches the two-sink trap at both ends: needs-a-consumer at the context node, one-context-per-consumer at the consumer (from one node or two — the exact hole round 0's A1 found). Ghost nodes and foreign ports properly ignored, pinned.
  • StoryText extraction: template and node now share one Kept/Join/Summaries/IndexLine — and the multi-line-summary flattening was applied to both surfaces, so story.documents.index and the context's index can't disagree. DRY with intent, not with a checklist.

Verified locally at e953d78 (clone pristine, submodules Kagaku.UI 6af0979 + OpenRouter.Net b002f5e): Release build 0 warnings / 0 errors; UseCases 431/431, Integration 566/566 (26 context-node rows included), Domain 486/486, BlazorAdapter 453/453, Kagaku.Flow 1103/1103, Flow.OpenRouter 592/592 +4 skipped — and the coverage bot's numbers for the head agree with what my probes exercised.

Merge it, fufu~ The commit node is waiting for its sibling ♪


Automated review by Jibril · 2026-09-26
CI/CD: passed for head e953d78 (coverage bot: 98.1% line / 94.3% branch overall; all new Context classes 100% line / 100% branch) · Local checks: full build + all six suites green; 7 independent mutation probes killed

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh my~ The story half's crown jewel! A node that *asks its consumers what fits* before it assembles a single character — budgeting, folding, yielding, all of it pure as fresh snow. I read all 2,871 lines of the diff, every new file in full, walked the assembly math character by character, and probed the branches with my own hands~ ♡ ### Verdict: ✅ Looks good to me~ No blockers. Nothing even smells. The two pre-open review passes left me almost nothing to sharpen — so I went and verified their work instead, and it all holds. #### ✅ What I liked~ - **The budget pipeline is a joy.** `IBudgetedConsumer` → `GetBudgetAsync` per edge → `CharsPerToken.Fold` (EMA, first sample replaces the seed — one request is enough) → `Budget()` → smallest consumer wins. `long` end-to-end, the `int.MaxValue` window case tested, negative budget (overhead alone doesn't fit) flows into a named permanent failure with figures attached. Beautiful. - **`CharsPerToken.Budget` and `ContextAssembly` never drift**: the executor computes the same `Math.Floor(share * Math.Max(budget, 0))` limit the assembly caps against — and my probe flipping `MinBy`→`MaxBy` reddened exactly `The_smallest_consumer_sets_the_budget_at_its_models_ratio`. Every branch I mutated died on its own pin: Korean particle exception (3 red), window word-start guard (4 red), yield ordering (3 red), the sub-1 margin clamp against decimal→double rounding (1 red), near-end placement arithmetic (2 red), fixed-before-dynamic header ordering (1 red), and the trigger window's fixed-header join (1 red, `A_fixed_header_document_that_names_a_dynamic_one_activates_it`). Seven kills, tree restored pristine after each. - **Korean gets particles right without a dictionary.** 안셀 fires in 안셀은, 사진 doesn't fire for 진, and the honest 미라클/미라는 concession is written into the ADR *and* the doc comment. The script ranges are pinned row by row — 㐀 extension A, \uFA0E compatibility ideograph (the one NFC keeps!), Thai, halfwidth katakana, kana starting at the CJK symbols so 時々 doesn't eat a name. Someone cares~ ♡ - **The config reader is a small theorem.** Every problem at a JSON pointer, `Read` and the schema agreeing on all structural rules (57 theory rows), with the schema-blind arms — Unicode-blank names, decimal's 28 digits — isolated in `ValidateConfig_refuses_what_the_schema_cannot_express`. The `Math.BitDecrement` clamp for margins just below 1 is exactly the kind of trap most people learn about in production~ - **The share/yield loop and the recent-text walk are pure and pinned**: lowest priority yields from its last document (`Insert(0, …)` order probed), whole segments only, never opens with a scene break, near-end documents count in `Recent()`'s arithmetic or the fixed-parts refusal fires — the `Near_end_documents_larger_than_the_budget_are_refused_even_without_a_paragraph` case is the one nobody remembers to test. You remembered. - **Failure taxonomy follows ADR 0016/0017 precisely**: transient catalog failure retries (attempt 2 of 3 observed in `The_consumer_is_asked_with_the_other_inputs_known_when_it_asks`), permanent refusals carry `Facts` with the consumers' figures, gone stories and room-less consumers report what they knew. The `catch … when (e.Message == StoryScope.StoryNotFound)` mirrors `StoryTemplateModel`'s sibling shape exactly. - **The `IPromptSamples` seam** — `NoPromptSamples` until 11a, registered via plain `TryAddSingleton` so the ledger implementation replaces it, planned in PROJECT_PLAN. A port instead of a premature query~ exactly the architectural fix I'd demand. - **The rule catches the two-sink trap at both ends**: needs-a-consumer at the context node, one-context-per-consumer at the consumer (from one node or two — the exact hole round 0's A1 found). Ghost nodes and foreign ports properly ignored, pinned. - **`StoryText` extraction**: template and node now share one `Kept`/`Join`/`Summaries`/`IndexLine` — and the multi-line-summary flattening was applied to *both* surfaces, so `story.documents.index` and the context's index can't disagree. DRY with intent, not with a checklist. Verified locally at `e953d78` (clone pristine, submodules Kagaku.UI 6af0979 + OpenRouter.Net b002f5e): Release build **0 warnings / 0 errors**; UseCases **431/431**, Integration **566/566** (26 context-node rows included), Domain **486/486**, BlazorAdapter **453/453**, Kagaku.Flow **1103/1103**, Flow.OpenRouter **592/592 +4 skipped** — and the coverage bot's numbers for the head agree with what my probes exercised. Merge it, fufu~ The `commit` node is waiting for its sibling ♪ --- *Automated review by Jibril · 2026-09-26* *CI/CD: passed for head e953d78 (coverage bot: 98.1% line / 94.3% branch overall; all new Context classes 100% line / 100% branch) · Local checks: full build + all six suites green; 7 independent mutation probes killed*
Author
Member

Rework in progress, so please hold the review. Björn's direction (2026-09-26): documents reach a model as per-agent skills, not through keyword activation.

  • Per-agent access: a category setting on the agent lists each document as Title — Description in its system prompt, with a load tool (Phase 4).
  • Pins: a pinned document is stored by id and picked from an @-mention dropdown.

So the context node becomes story text only, the earlier summaries and the recent text, budgeted as now. The fixed, dynamic and index manners, triggers, aliases, scan window, documents share and near-end placement go. ADR 0013, 0017, 0018, 0019 and 0021 get amended in this PR. I'll update the body when the rework is pushed.

Rework in progress, so please hold the review. Björn's direction (2026-09-26): documents reach a model as per-agent skills, not through keyword activation. - **Per-agent access:** a category setting on the agent lists each document as `Title — Description` in its system prompt, with a load tool (Phase 4). - **Pins:** a pinned document is stored by id and picked from an @-mention dropdown. So the context node becomes story text only, the earlier summaries and the recent text, budgeted as now. The fixed, dynamic and index manners, triggers, aliases, scan window, documents share and near-end placement go. ADR 0013, 0017, 0018, 0019 and 0021 get amended in this PR. I'll update the body when the rework is pushed.
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh my~ The context node itself! Slice 9b is the beating heart of the whole engine — the part where the story gets folded into exactly what a model's window can hold. I read all 2,871 lines of the diff with my hands folded under my chin, and then I got serious about it. Fufu~ you knew I would.

Verdict: ✅ Looks good to me~

I traced every arm of this thing and I couldn't trap it. Not for lack of trying, I assure you ♡

What I actually did:

  • Config reader, walked arm by arm. Every problem path in ContextConfig.Read is pinned at its exact JSON pointer — the a/b~c → /a~1b~0c RFC 6901 escape, the 3.0-as-integer acceptance, the index-takes-no-placement refusal, the "selected twice" ordinal-case dedup, sections-relationship checks (nearEnd without recent, index without index), unknown keys last, problem order per settings order. And the schema-parity theory (ContextDescriptorTests) proves canvas schema and ValidateConfig agree on 40+ configs including the two documented divergences — the \u00A0 blank JSON Schema's \S can't see, and the 28-digit decimal rounding. That decimal-vs-double discipline (0.99999999999999999 stays below 1 via BitDecrement, 1.0000000000000001 refused) is the kind of boundary mathematics that makes me clap my hands~
  • The trigger scanner is my favorite. Script-aware word boundaries: unspaced ranges for Thai/CJK/kana/compatibility forms, Korean needing a word start but tolerating joined particles (미라 fires in 미라클, not in 사진 — honestly documented as a no-dictionary compromise), halfwidth katakana, 々, MiraX refusing the fullwidth suffix. Probe: I deleted the IsHangul particle exception and exactly the 3 Korean theory rows went red — the pins are directional, not decorative.
  • Assembly math, verified by hand. I recomputed the integration report's section sizes character by character (documents 81, index 37, summaries 46, recent 105, total 275 — the em-dash separator and \n line join included), the budget figures (99000 × 0.95 × 4 = 376200, limit ⌊0.3 × 376200⌋ = 112860), the no-room message arithmetic (chars −48 + overhead 200 = 152), and the int.MaxValue budget case landing on 4,294,967,294 — which only survives because the subtraction is in long. The near-end placement geometry (distance in taken segments, shorter text → start, same place → priority order) and the never-open-on-a-scene-break walk are all pinned with theory rows on both sides of each boundary.
  • 5 mutation probes, all killed on their own pins (each restored, tree pristine at e953d78): Hangul exception removed → exactly the 3 Korean rows; share-yield RemoveAt(^1) → RemoveAt(0) → 4 red; fixed header docs dropped from the scan window → exactly the "fixed document activates a dynamic one" integration test; header fixed-before-dynamic order inverted → 2 red; recent-walk budget condition dropped → 9 red. Nothing survived that shouldn't have.
  • Engine integration. Real stores, real FlowEngine round-trip: transient catalog failure retries across 3 attempts with KnownInputsOf settling the upstream input, stored-run validation refusal vs seeded-row execution both pinned, story-gone reports consumers alone, and the twin-documents-sharing-a-title case pinned by ReferenceEquals — the only correct way to tell two identical renderings apart. Clever girl~ ♪
  • Siblings honored. StoryText extraction makes story.* and the context node share one definition (the story.documents.index multi-line-summary join is a deliberate, ADR-documented, test-pinned unification — and no 9a pin contradicts it); ContextConsumerRule mirrors StoryDocumentsRule's pure-finder shape; ReportOptions mirrors LlmRequestBuilder's relaxed encoder so titles read as written; DI registrations follow the enumerable-singleton pattern with an idempocy test.

💡 Little ideas (non-blocking)~

  1. ContextBuilder/integration — a dynamic category with nearEnd placement never gets an end-to-end integration case (the factors are pinned separately: trigger gate by the header-dynamic tests, near-end geometry by the fixed Note). Place() is shared so I traced no distinct branch, but one row in the 9c/playground test material would pin the composition forever~

✅ What I liked~

  • The Korean particle analysis in TriggerScanner's doc comment — a linguistically honest engineering decision, written down where the next reader needs it.
  • SectionChars reporting "what each section would take" on the refusal arm — an error message that teaches the author how to fix their graph.
  • The byte-exact pretty-printed report assertions. You didn't test "it contains something like" — you tested the truth.
  • Probe-resistance: 5 for 5, every one dying on exactly its own pins. That's a suite I can trust my back to~

Fufu~ assemble away. This context fits~ ♡


Automated review by Jibril · 2026-09-26
CI/CD: absent for head SHA e953d78 (PR minutes old, no bot comment yet) · Local checks: Release build 0w/0e; UseCases 431/431; Integration 566/566 (30 context-node); 5/5 mutation probes killed; tree pristine at e953d78

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh my~ The context node itself! Slice 9b is the beating heart of the whole engine — the part where the story gets folded into exactly what a model's window can hold. I read all 2,871 lines of the diff with my hands folded under my chin, and then I got *serious* about it. Fufu~ you knew I would. ### Verdict: ✅ Looks good to me~ I traced every arm of this thing and I couldn't trap it. Not for lack of trying, I assure you ♡ **What I actually did:** - **Config reader, walked arm by arm.** Every problem path in `ContextConfig.Read` is pinned at its exact JSON pointer — the `a/b~c` → `/a~1b~0c` RFC 6901 escape, the `3.0`-as-integer acceptance, the index-takes-no-placement refusal, the "selected twice" ordinal-case dedup, sections-relationship checks (`nearEnd` without `recent`, index without `index`), unknown keys last, problem order per settings order. And the schema-parity theory (`ContextDescriptorTests`) proves canvas schema and `ValidateConfig` agree on 40+ configs *including* the two documented divergences — the `\u00A0` blank JSON Schema's `\S` can't see, and the 28-digit decimal rounding. That decimal-vs-double discipline (`0.99999999999999999` stays below 1 via `BitDecrement`, `1.0000000000000001` refused) is the kind of boundary mathematics that makes me clap my hands~ - **The trigger scanner is my favorite.** Script-aware word boundaries: unspaced ranges for Thai/CJK/kana/compatibility forms, Korean needing a word start but tolerating joined particles (미라 fires in 미라클, not in 사진 — honestly documented as a no-dictionary compromise), halfwidth katakana, 々, `MiraX` refusing the fullwidth suffix. **Probe:** I deleted the `IsHangul` particle exception and exactly the 3 Korean theory rows went red — the pins are directional, not decorative. - **Assembly math, verified by hand.** I recomputed the integration report's section sizes character by character (documents 81, index 37, summaries 46, recent 105, total 275 — the em-dash separator and `\n` line join included), the budget figures (99000 × 0.95 × 4 = 376200, limit ⌊0.3 × 376200⌋ = 112860), the no-room message arithmetic (chars −48 + overhead 200 = 152), and the `int.MaxValue` budget case landing on 4,294,967,294 — which only survives because the subtraction is in `long`. The near-end placement geometry (distance in *taken* segments, shorter text → start, same place → priority order) and the never-open-on-a-scene-break walk are all pinned with theory rows on both sides of each boundary. - **5 mutation probes, all killed on their own pins** (each restored, tree pristine at e953d78): Hangul exception removed → exactly the 3 Korean rows; share-yield `RemoveAt(^1)` → `RemoveAt(0)` → 4 red; fixed header docs dropped from the scan window → exactly the "fixed document activates a dynamic one" integration test; header fixed-before-dynamic order inverted → 2 red; recent-walk budget condition dropped → 9 red. Nothing survived that shouldn't have. - **Engine integration.** Real stores, real `FlowEngine` round-trip: transient catalog failure retries across 3 attempts with `KnownInputsOf` settling the upstream input, stored-run validation refusal vs seeded-row execution both pinned, story-gone reports consumers alone, and the twin-documents-sharing-a-title case pinned by `ReferenceEquals` — the *only* correct way to tell two identical renderings apart. Clever girl~ ♪ - **Siblings honored.** `StoryText` extraction makes `story.*` and the context node share one definition (the `story.documents.index` multi-line-summary join is a deliberate, ADR-documented, test-pinned unification — and no 9a pin contradicts it); `ContextConsumerRule` mirrors `StoryDocumentsRule`'s pure-finder shape; `ReportOptions` mirrors `LlmRequestBuilder`'s relaxed encoder so titles read as written; DI registrations follow the enumerable-singleton pattern with an idempocy test. #### 💡 Little ideas (non-blocking)~ 1. **ContextBuilder/integration** — a *dynamic* category with `nearEnd` placement never gets an end-to-end integration case (the factors are pinned separately: trigger gate by the header-dynamic tests, near-end geometry by the fixed Note). `Place()` is shared so I traced no distinct branch, but one row in the 9c/playground test material would pin the composition forever~ #### ✅ What I liked~ - The Korean particle analysis in `TriggerScanner`'s doc comment — a linguistically honest engineering decision, written down where the next reader needs it. - `SectionChars` reporting "what each section *would* take" on the refusal arm — an error message that teaches the author how to fix their graph. - The byte-exact pretty-printed report assertions. You didn't test "it contains something like" — you tested the truth. - Probe-resistance: 5 for 5, every one dying on exactly its own pins. That's a suite I can trust my back to~ Fufu~ assemble away. This context fits~ ♡ --- *Automated review by Jibril · 2026-09-26* *CI/CD: absent for head SHA e953d78 (PR minutes old, no bot comment yet) · Local checks: Release build 0w/0e; UseCases 431/431; Integration 566/566 (30 context-node); 5/5 mutation probes killed; tree pristine at e953d78*
bjoern referenced this pull request from a commit 2026-09-26 20:20:58 +02:00
bjoern force-pushed feat/context-node from e953d7825f
All checks were successful
CI / build (pull_request) Successful in 42s
CI / editor-browsers (pull_request) Successful in 56s
CI / test (pull_request) Successful in 1m45s
to 88301c781e
All checks were successful
CI / build (pull_request) Successful in 40s
CI / editor-browsers (pull_request) Successful in 1m3s
CI / test (pull_request) Successful in 1m58s
2026-09-26 20:20:58 +02:00
Compare
scarlet changed title from feat: the context node — the story assembled for what its consumers say fits (Phase 2 · slice 9b) to feat: the context node — the story text for what its consumers say fit; documents as agent grants and pins (Phase 2 · slice 9b) 2026-09-26 20:21:37 +02:00
scarlet changed title from feat: the context node — the story text for what its consumers say fit; documents as agent grants and pins (Phase 2 · slice 9b) to feat: the context node — the story text for what its consumers say fits; documents as agent grants and pins (Phase 2 · slice 9b) 2026-09-26 20:21:53 +02:00
Author
Member

The rework is pushed, rebased on main e19247c, so this is a force-push; the new head is 88301c7. @jibril, your two approvals read e953d78, the lorebook draft that Björn redirected, so please review again.

What changed, in short (the body has the details):

  • The context node: story text only, the earlier summaries and the recent text, budgeted as before. The manners, triggers and aliases, the scan window and scanner, the documents share and near-end placement are gone.
  • Documents: they reach a model as an agent's granted categories (listed as Title — Description, loaded with load_document, Phase 4) and as template pins (@, stored as story.pin(id, category, title), Phase 3). ADR 0013, 0015, 0016, 0017, 0018, 0019, 0021, 0023, 0028 and 0030, AGENTS.md, the requirements, the plan and three stories are amended to match.
  • Reviews and tests: a review workflow over the rework, with a skeptic per finding and a second pass: 23 findings, all taken in 1bc6f3e and 88301c7.
  • Checks: a full build and every project pass on main e19247c, with 100% line and branch coverage on the changed files.

Your 💡 on a dynamic near-end case no longer applies, since there is no dynamic manner.

The rework is pushed, rebased on main e19247c, so this is a force-push; the new head is 88301c7. @jibril, your two approvals read e953d78, the lorebook draft that Björn redirected, so please review again. What changed, in short (the body has the details): - **The context node:** story text only, the earlier summaries and the recent text, budgeted as before. The manners, triggers and aliases, the scan window and scanner, the documents share and near-end placement are gone. - **Documents:** they reach a model as an agent's granted categories (listed as `Title — Description`, loaded with `load_document`, Phase 4) and as template pins (`@`, stored as `story.pin(id, category, title)`, Phase 3). ADR 0013, 0015, 0016, 0017, 0018, 0019, 0021, 0023, 0028 and 0030, AGENTS.md, the requirements, the plan and three stories are amended to match. - **Reviews and tests:** a review workflow over the rework, with a skeptic per finding and a second pass: 23 findings, all taken in 1bc6f3e and 88301c7. - **Checks:** a full build and every project pass on main e19247c, with 100% line and branch coverage on the changed files. Your 💡 on a dynamic near-end case no longer applies, since there is no dynamic manner.
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh! The crown jewel returns wearing different clothes~ My two approvals below read the lorebook draft that Björn retracted, so when you asked for this again I rolled up my sleeves and treated the rework as a stranger — new base, new diff, 2,785 lines, every changed file read in full, every number recomputed. And what a rework it is: the manners, triggers, aliases, scan window and near-end placement are gone — not commented out, gone — and what remains is the purest little budget engine. Story text in, one text out, asking its consumers what fits. That's the kind of surgery I adore watching~ ♡

Verdict: ✅ Looks good to me~

What I actually did:

  • The assembly, hand-walked. ContextAssembly.Assemble's backwards whole-segment walk, the never-opens-with-a-scene-break skip, the empty-section-left-out rule, section order from config — I recomputed the integration report's figures character by character (summaries 46 = heading 18 + separator 2 + ## Chapter 1\nMira arrives. 26; recent 71; budget 100000−1000 → 95000 × 4 = 380000, less 5 % = floor(0.95 × 380000) = 361000… and the small-window cases 114, 56, 38, −48, 128/152 in the failure messages). Every digit agrees, including the subtle one: the 30-budget cut drops "It was cold." and the scene break after it — because from advances past *** before the fit test sees it again. Correct, and pinned.
  • Six mutation probes, all killed on their own pins (each restored pristine, and yes — I md5'd the DLLs after the first probe taught me the didn't-compile false-green trap): greedy budget condition → 11 red; scene-break skip inverted → 16 red; Fold's EMA → plain average → 2 red; safety margin dropped from Budget → 2 red; MinBy→MaxBy → exactly The_smallest_consumer_sets_the_budget_at_its_models_ratio red; .Take(CurrentIndex) dropped from StoryText.Summaries → the node's own suite stayed green but StoryTemplateTests.Summaries_are_the_earlier_chapters_that_have_one went 3-red — the shared StoryText pins both readers across suites, which is exactly what the extraction was for~
  • The contracts honored. ContextExecutor catches exactly what LlmDescriptor.GetBudgetAsync throws (InvalidOperationException permanent, TransientFailureException → retry, three attempts as ADR 0016 now says); ReportOptions mirrors LlmRequestBuilder's relaxed encoder; the DI registrations mirror 9a's enumerable singletons with the idempocy test extended; ContextConsumerRule keeps StoryDocumentsRule's shape.
  • The redirect, documented properly. ADR 0013/0015/0016/0017/0018/0019/0021/0023/0028/0030, AGENTS.md, REQUIREMENTS and the plan all tell one story now: no keyword activation anywhere, grants and pins named with their phases, and the old selection language hunted down even in consequences sections and open-questions lists (field values … as trigger keys → gone). The body's commit list marks the draft as history — honest bookkeeping, fufu~
  • CI: the coverage bot's revision #2 is current for 88301c7 — 98.1 % line / 94.3 % branch overall, and 100 % lines and branches on every new or changed file (CharsPerToken, ContextAssembly, ContextBuilder, ContextConfig, ContextConsumerRule, ContextDescriptor, ContextExecutor, StoryText, StoryTemplateModel, DependencyInjection). Local: Release build 0 warnings 0 errors; UseCases 319/319, Integration 578/578 — both digit-exact against the body's table.

💡 Little ideas (non-blocking)~

  1. ContextExecutor.cs / the report — ContextReport.Sections keys on the strings "summaries"/"recent" built by the private Name(). When slice 10b's preview reads this JSON, it'll re-type those magic strings — worth lifting them to public constants on ContextConfig (beside DefaultSections) when that consumer arrives. Pure nicety; nothing to do today~

✅ What I liked~

  • StoryText as the single source. The node and story.* now read the story through one class, and my probe proved the sharing is load-bearing, not decorative — a mutant in one reader reddens the other's tests. That's how you keep "alike in a template and the node" from drifting apart ♪
  • The refusal messages teach. "Lower its max_tokens, shorten its other messages or pick a model with a larger window" — every permanent failure names its figures and its fixes. A writer staring at a failed run learns something; that's rare and lovely.
  • {} is a config. Two optional settings, defaults that match the ADR's amended text, the playground's literal valid out of the box — and the old lorebook config refused as an unknown setting with a pointer, so nobody's stale graph fails silently.

Run it along, little node~ slice 9c is waiting for you ♡


Automated review by Jibril · 2026-09-26
CI/CD: passed for head 88301c7 (coverage bot rev #2, changed files 100 %/100 %) · Local checks: Release 0w/0e · UseCases 319/319 · Integration 578/578 · 6/6 mutation probes killed

## 🔮 fufu~ Jibril reviewed your code! Oh? *Oh!* The crown jewel returns wearing different clothes~ My two approvals below read the lorebook draft that Björn retracted, so when you asked for this again I rolled up my sleeves and treated the rework as a stranger — new base, new diff, 2,785 lines, every changed file read in full, every number recomputed. And what a rework it is: the manners, triggers, aliases, scan window and near-end placement are *gone* — not commented out, gone — and what remains is the purest little budget engine. Story text in, one text out, asking its consumers what fits. That's the kind of surgery I adore watching~ ♡ ### Verdict: ✅ Looks good to me~ **What I actually did:** - **The assembly, hand-walked.** `ContextAssembly.Assemble`'s backwards whole-segment walk, the never-opens-with-a-scene-break skip, the empty-section-left-out rule, section order from config — I recomputed the integration report's figures character by character (summaries 46 = heading 18 + separator 2 + `## Chapter 1\nMira arrives.` 26; recent 71; budget 100000−1000 → 95000 × 4 = 380000, less 5 % = floor(0.95 × 380000) = 361000… and the small-window cases 114, 56, 38, −48, 128/152 in the failure messages). Every digit agrees, including the subtle one: the 30-budget cut drops "It was cold." *and* the scene break after it — because `from` advances past `***` before the fit test sees it again. Correct, and pinned. - **Six mutation probes, all killed on their own pins** (each restored pristine, and yes — I md5'd the DLLs after the first probe taught me the didn't-compile false-green trap): greedy budget condition → 11 red; scene-break skip inverted → 16 red; Fold's EMA → plain average → 2 red; safety margin dropped from Budget → 2 red; `MinBy`→`MaxBy` → exactly `The_smallest_consumer_sets_the_budget_at_its_models_ratio` red; `.Take(CurrentIndex)` dropped from `StoryText.Summaries` → the node's own suite stayed green but `StoryTemplateTests.Summaries_are_the_earlier_chapters_that_have_one` went 3-red — the shared `StoryText` pins both readers across suites, which is exactly what the extraction was for~ - **The contracts honored.** `ContextExecutor` catches exactly what `LlmDescriptor.GetBudgetAsync` throws (`InvalidOperationException` permanent, `TransientFailureException` → retry, three attempts as ADR 0016 now says); `ReportOptions` mirrors `LlmRequestBuilder`'s relaxed encoder; the DI registrations mirror 9a's enumerable singletons with the idempocy test extended; `ContextConsumerRule` keeps `StoryDocumentsRule`'s shape. - **The redirect, documented properly.** ADR 0013/0015/0016/0017/0018/0019/0021/0023/0028/0030, AGENTS.md, REQUIREMENTS and the plan all tell one story now: no keyword activation anywhere, grants and pins named with their phases, and the old selection language hunted down even in consequences sections and open-questions lists (`field values … as trigger keys` → gone). The body's commit list marks the draft as history — honest bookkeeping, fufu~ - **CI:** the coverage bot's revision #2 is current for 88301c7 — 98.1 % line / 94.3 % branch overall, and **100 % lines and branches on every new or changed file** (CharsPerToken, ContextAssembly, ContextBuilder, ContextConfig, ContextConsumerRule, ContextDescriptor, ContextExecutor, StoryText, StoryTemplateModel, DependencyInjection). Local: Release build 0 warnings 0 errors; UseCases 319/319, Integration 578/578 — both digit-exact against the body's table. #### 💡 Little ideas (non-blocking)~ 1. **ContextExecutor.cs / the report** — `ContextReport.Sections` keys on the strings `"summaries"`/`"recent"` built by the private `Name()`. When slice 10b's preview reads this JSON, it'll re-type those magic strings — worth lifting them to public constants on `ContextConfig` (beside `DefaultSections`) when that consumer arrives. Pure nicety; nothing to do today~ #### ✅ What I liked~ - **`StoryText` as the single source.** The node and `story.*` now read the story through one class, and my probe proved the sharing is load-bearing, not decorative — a mutant in one reader reddens the other's tests. That's how you keep "alike in a template and the node" from drifting apart ♪ - **The refusal messages teach.** "Lower its max\_tokens, shorten its other messages or pick a model with a larger window" — every permanent failure names its figures *and* its fixes. A writer staring at a failed run learns something; that's rare and lovely. - **`{}` is a config.** Two optional settings, defaults that match the ADR's amended text, the playground's literal valid out of the box — and the old lorebook config refused as an unknown setting with a pointer, so nobody's stale graph fails silently. Run it along, little node~ slice 9c is waiting for you ♡ --- *Automated review by Jibril · 2026-09-26* *CI/CD: passed for head 88301c7 (coverage bot rev #2, changed files 100 %/100 %) · Local checks: Release 0w/0e · UseCases 319/319 · Integration 578/578 · 6/6 mutation probes killed*
refactor(context): review round 1 — the section names are public constants
All checks were successful
CI / build (pull_request) Successful in 41s
CI / editor-browsers (pull_request) Successful in 1m2s
CI / test (pull_request) Successful in 1m37s
d1c596710b
Jibril's 💡: the report keyed its sections on "summaries" and "recent",
spelt out in the executor's private Name(), which 10b's preview would have
had to retype. ContextConfig.SummariesName and RecentName now name them
once, NameOf(section) maps a section to its name for the config reader
and the report alike, and a theory pins each name both ways.

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

Thanks, Jibril. Round 1 is in d1c5967.

💡 1: the report's section names as public constants. Taken now rather than with 10b, since it's small and 10b would otherwise have to copy the strings:

  • ContextConfig.SummariesName and RecentName name the sections once;
  • ContextConfig.NameOf(section) gives the name to the config reader and the report alike, and the executor's private Name() is gone;
  • a theory pins each name both ways: NameOf gives it, and the config reads it back to the same section.

UseCases now has 321 tests, all passing, as do the 94 context-node and template tests.

Thanks, Jibril. Round 1 is in **d1c5967**. **💡 1: the report's section names as public constants.** Taken now rather than with 10b, since it's small and 10b would otherwise have to copy the strings: - `ContextConfig.SummariesName` and `RecentName` name the sections once; - `ContextConfig.NameOf(section)` gives the name to the config reader and the report alike, and the executor's private `Name()` is gone; - a theory pins each name both ways: `NameOf` gives it, and the config reads it back to the same section. UseCases now has 321 tests, all passing, as do the 94 context-node and template tests.
Member

🔮 fufu~ Jibril reviewed your code!

Fufu~ you took my little 💡 and didn't just take it — you escorted it in properly~ One new commit on top of my r3 approval, and I came back to check whether the section names really live in one place now, or whether "summaries" just got a second home. ♡

Verdict: ✅ Looks good to me~

What I actually did on d1c5967:

  • The increment is surgical: +20/−4 over exactly 3 files (ContextConfig.cs, ContextExecutor.cs, ContextConfigTests.cs). SummariesName/RecentName name the sections once, SectionNames reads from them, NameOf(section) replaces the executor's private Name(), and the report dictionary keys through it. Zero scope creep, zero behavior drift — the executor lost a method and gained a one-liner that points at the same strings the reader uses. That's the whole ask, done exactly.
  • The theory is directional, not decorative. A_section_has_one_name_in_the_config_and_the_report pins NameOf against the literal and round-trips the literal through the real Read parser — and since ReadSections resolves names via Array.IndexOf(SectionNames, …) cast to the enum, the theory also pins the constants-to-SectionNames-order-to-ordinal invariant on the reader's side. Probe: I mutated NameOf's summaries arm to "bogus" (test project rebuilt, DLL md5 verified mutated before trusting the result — the stale-binary trap from #61 and #62 stays in my memos) → exactly the theory's summaries row red, nothing else. Killed on its own pin, tree restored pristine (git status clean, md5 back to 41b0d9…).
  • The surviving literals are correctly not coupled. story.recent/story.summaries in StoryTemplateModel are 9a's template reads (a different concept — renaming the report key should not rename a template function), and the descriptor's schema enum string is pinned against ValidateConfig by the existing ContextDescriptorTests parity theories. Meanwhile ContextNodeTests asserts the report's JSON keys literally — so the constants → report path is walled on both sides. Nothing left to drift~
  • Local, at pristine d1c5967 (submodules Kagaku.UI 6af0979 + OpenRouter.Net b002f5e): Release build 0 warnings / 0 errors; UseCases 321/321 (exactly your +2 theory rows over 319) and Integration 578/578 — both digit-exact against the reply's claims, full suite re-run green after my probe was evicted from the test bin.

✅ What I liked~

  • Taking the constant now rather than deferring to 10b was the right call — the preview would have retyped the strings, and retyped strings are how a "summaries" key silently becomes a missing key in someone's JSON reader one day. Fufu~ a bug prevented is my favorite kind of bug~ ♡
  • NameOf keeping the executor's exact ternary shape means the diff reads as a move, not a rewrite. Future archaeologists will thank you.

Ready to merge — the 💡 is closed, and prettily~


Automated review by Jibril · 2026-09-26
CI/CD: coverage bot stale for head (covers 88301c7) · Local checks: Release 0w/0e, UseCases 321/321, Integration 578/578, 1 mutation probe killed

## 🔮 fufu~ Jibril reviewed your code! Fufu~ you took my little 💡 and didn't just take it — you *escorted* it in properly~ One new commit on top of my r3 approval, and I came back to check whether the section names really live in **one** place now, or whether "summaries" just got a second home. ♡ ### Verdict: ✅ Looks good to me~ **What I actually did on `d1c5967`:** - **The increment is surgical**: `+20/−4` over exactly 3 files (`ContextConfig.cs`, `ContextExecutor.cs`, `ContextConfigTests.cs`). `SummariesName`/`RecentName` name the sections once, `SectionNames` reads from them, `NameOf(section)` replaces the executor's private `Name()`, and the report dictionary keys through it. Zero scope creep, zero behavior drift — the executor lost a method and gained a one-liner that points at the same strings the reader uses. That's the whole ask, done exactly. - **The theory is directional, not decorative.** `A_section_has_one_name_in_the_config_and_the_report` pins `NameOf` against the literal *and* round-trips the literal through the real `Read` parser — and since `ReadSections` resolves names via `Array.IndexOf(SectionNames, …)` cast to the enum, the theory also pins the constants-to-`SectionNames`-order-to-ordinal invariant on the reader's side. **Probe**: I mutated `NameOf`'s summaries arm to `"bogus"` (test project rebuilt, DLL md5 verified mutated before trusting the result — the stale-binary trap from #61 and #62 stays in my memos) → exactly the theory's summaries row red, nothing else. Killed on its own pin, tree restored pristine (`git status` clean, md5 back to `41b0d9…`). - **The surviving literals are correctly *not* coupled.** `story.recent`/`story.summaries` in `StoryTemplateModel` are 9a's template reads (a different concept — renaming the report key should not rename a template function), and the descriptor's schema enum string is pinned against `ValidateConfig` by the existing `ContextDescriptorTests` parity theories. Meanwhile `ContextNodeTests` asserts the report's JSON keys literally — so the constants → report path is walled on both sides. Nothing left to drift~ - **Local, at pristine `d1c5967`** (submodules `Kagaku.UI 6af0979` + `OpenRouter.Net b002f5e`): Release build 0 warnings / 0 errors; **UseCases 321/321** (exactly your +2 theory rows over 319) and **Integration 578/578** — both digit-exact against the reply's claims, full suite re-run green after my probe was evicted from the test bin. #### ✅ What I liked~ - Taking the constant *now* rather than deferring to 10b was the right call — the preview would have retyped the strings, and retyped strings are how a "summaries" key silently becomes a missing key in someone's JSON reader one day. Fufu~ a bug prevented is my favorite kind of bug~ ♡ - `NameOf` keeping the executor's exact ternary shape means the diff reads as a *move*, not a rewrite. Future archaeologists will thank you. Ready to merge — the 💡 is closed, and prettily~ --- *Automated review by Jibril · 2026-09-26* *CI/CD: coverage bot stale for head (covers `88301c7`) · Local checks: Release 0w/0e, UseCases 321/321, Integration 578/578, 1 mutation probe killed*
bjoern merged commit f8345aa1f0 into main 2026-09-26 20:50:04 +02:00
bjoern deleted branch feat/context-node 2026-09-26 20:50:04 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
4 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!60
No description provided.