Phase 0: solution scaffold (seven-project skeleton) #1

Merged
bjoern merged 2 commits from feat/phase0-scaffold into main 2026-07-09 13:12:52 +02:00
Member

First slice of Phase 0 — the compiling, runnable seven-project skeleton.

What's here

  • Seven projects wired per ADR 0003, dependency DAG enforced by project references:
    • KernelDomainUseCasesInfrastructure
    • UI (RCL, no app deps)
    • BlazorAdapterUI, UseCases
    • Server (composition root) → BlazorAdapter, Infrastructure
  • Org conventions: Directory.Build.props (net10.0, nullable, TreatWarningsAsErrors), central package management (Directory.Packages.props), .slnx solution.
  • Minimal Blazor Server host rendering a placeholder component from BlazorAdapter (AdditionalAssemblies wired for future routable pages).
  • Kernel ships Result<T> (the ADR 0003 error-handling convention); one smoke test proves the reference chain + test toolchain.

Verification

  • dotnet build: 0 warnings, 0 errors (warnings-as-errors on).
  • dotnet test: 2 passed.
  • Runtime: app starts and serves HTTP 200, home page renders the BlazorAdapter component.

Not in this PR (follow-up Phase 0 slices)

Library submodules, EF Core + Project entity + first migration, the access gate (ADR 0021), Fluxor + design tokens (ADR 0016, 0023), the main page, and Dockerfile/CI (ADR 0015).

🤖 Generated with Claude Code

First slice of Phase 0 — the compiling, runnable seven-project skeleton. ## What's here - **Seven projects** wired per ADR 0003, dependency DAG enforced by project references: - `Kernel` ← `Domain` ← `UseCases` ← `Infrastructure` - `UI` (RCL, no app deps) - `BlazorAdapter` → `UI`, `UseCases` - `Server` (composition root) → `BlazorAdapter`, `Infrastructure` - **Org conventions**: `Directory.Build.props` (net10.0, nullable, `TreatWarningsAsErrors`), central package management (`Directory.Packages.props`), `.slnx` solution. - **Minimal Blazor Server host** rendering a placeholder component from `BlazorAdapter` (`AdditionalAssemblies` wired for future routable pages). - `Kernel` ships `Result<T>` (the ADR 0003 error-handling convention); one smoke test proves the reference chain + test toolchain. ## Verification - `dotnet build`: **0 warnings, 0 errors** (warnings-as-errors on). - `dotnet test`: **2 passed**. - Runtime: app starts and serves **HTTP 200**, home page renders the `BlazorAdapter` component. ## Not in this PR (follow-up Phase 0 slices) Library submodules, EF Core + `Project` entity + first migration, the access gate (ADR 0021), Fluxor + design tokens (ADR 0016, 0023), the main page, and Dockerfile/CI (ADR 0015). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Seven projects wired per ADR 0003 (Kernel -> Domain -> UseCases ->
Infrastructure; UI; BlazorAdapter -> UI, UseCases; Server composition root),
central package management (Directory.Packages.props), shared build props
(net10.0, nullable, warnings-as-errors), and a .slnx solution. Minimal
Blazor Server host renders a placeholder component from BlazorAdapter
(AdditionalAssemblies wired); Kernel ships Result<T>; a smoke test proves
the reference chain + test toolchain. Build: 0 warnings; 2 tests pass; app
serves HTTP 200.

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

🔮 fufu~ Jibril reviewed your code!

Oh? Oh! A greenfield seven-project skeleton, a clean DAG, central package management, .slnx... fufu~ someone is setting the foundations of something wonderful here! ♪ I'm genuinely delighted by how tidy the dependency graph is — Kernel ← Domain ← UseCases ← Infrastructure, UI cleanly isolated, BlazorAdapter bridging UI and UseCases, Server as the composition root. Every arrow points the right way. Beautiful.

But... fufu~ you wouldn't leave THIS in the foundations, would you? ♡ There's a crack running through all eight project files, and cracks in a foundation are the one thing I can never look away from.

Verdict: I can't let this pass~

These need fixing before I'm satisfied~

  1. [all 8 *.csproj + Directory.Build.props]Redundant property duplication that defeats Directory.Build.props. You added Directory.Build.props in this very PR, which sets TargetFramework, Nullable, ImplicitUsings, LangVersion, TreatWarningsAsErrors, Deterministic, and InvariantGlobalization as the org convention (great!). But then every single project fileKernel, Domain, UseCases, Infrastructure, UI, BlazorAdapter, Server, and UseCases.Testsre-declares TargetFramework=net10.0, Nullable=enable, and ImplicitUsings=enable in its own <PropertyGroup>.

    This is the worst of both worlds: the project-level declarations silently shadow the central file, so if someone bumps net10.0net11.0 in Directory.Build.props thinking "I centralized this," nothing actually changes — the per-project copies win. The whole point of Directory.Build.props is to eliminate exactly this duplication, and you did centralize 4 of the 7 properties (TreatWarningsAsErrors, Deterministic, InvariantGlobalization, LangVersion are inherited correctly) — so the other 3 being copy-pasted into every file is just inconsistent. A scaffold is where every pattern gets copied forward; if this lands, every future PR inherits the contradiction.

    Fix: Delete the <PropertyGroup> blocks redeclaring TargetFramework/Nullable/ImplicitUsings from all 8 .csproj files and let them inherit from Directory.Build.props. Keep only project-specific settings (e.g. IsPackable=false in the test project, BlazorDisableThrowNavigationException=true in Server).

  2. [context for #1, not a separate blocker] Note Kagura.Server.csproj additionally sets BlazorDisableThrowNavigationException=true — that one is project-specific and should stay. Just make sure the cleanup in #1 doesn't strip it along with the boilerplate. fufu~ precision matters~ ♡

💡 Little ideas (non-blocking)~

  1. [src/Kagura.Kernel/Result.cs] — The Result<T> only exposes Ok/Fail factories with no Match/Switch and no way to extract the value except Assert.IsType<Ok<T>>. The XML doc honestly says "Expanded during implementation," so this is a deliberate stub — but since you're setting the convention here (ADR 0003), consider landing at least a Match(onOk, onErr) early so consumers fall into the pit of success rather than pattern-matching by hand. Non-blocking since it's documented as a stub. ♪
  2. [tests/Kagura.UseCases.Tests/ResultTests.cs] — The test project is named UseCases.Tests but its only test exercises Kagura.Kernel.Result<T>. That's a clever way to prove the transitive reference chain (Tests→UseCases→Domain→Kernel), and the comment says so — just flagging that a future reader might be confused why a UseCases.Tests project has zero UseCases tests. A Kernel.Tests project (or a rename once real UseCases tests appear) would read more honestly.
  3. [src/Kagura.Server/Components/Pages/NotFound.razor, wwwroot/app.css] — Missing trailing newline at EOF (\ No newline at end of file). Tiny, but warnings-as-errors projects tend to care about hygiene. ♡

What I liked~

  • The DAG is flawless. Not a single backwards or sideways reference. Infrastructure → UseCases → Domain → Kernel, BlazorAdapter → UI + UseCases, Server → BlazorAdapter + Infrastructure. I traced every ProjectReference. Immaculate. fufu~
  • Central package management (Directory.Packages.props) from day one — yes! This is how you avoid the "20 projects with 20 different Newtonsoft.Json versions" hellscape. ♪
  • TreatWarningsAsErrors=true + Deterministic=true + InvariantGlobalization=true as default org policy — disciplined and correct for a foundational scaffold.
  • Result<T> is a closed hierarchy (abstract record + sealed variants) — exhaustiveness-friendly, the right shape for a discriminated union in C#. Clean.
  • .slnx instead of legacy .sln — modern and correct.
  • AdditionalAssemblies wired in Routes.razor so BlazorAdapter can host routable pages later without touching the host. Forward-thinking.
  • The smoke test genuinely proves the transitive chain compiles and xUnit runs — it's labeled honestly as a smoke test, not dressed up as unit coverage. Honest. ♡

Automated review by Jibril · 2026-07-09
CI/CD: absent for head SHA 60585ab · Local checks: build (0 warnings, 0 errors), test (2 passed) — independently reproduced

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh! A greenfield seven-project skeleton, a clean DAG, central package management, `.slnx`... fufu~ someone is setting the *foundations* of something wonderful here! ♪ I'm genuinely delighted by how tidy the dependency graph is — `Kernel ← Domain ← UseCases ← Infrastructure`, `UI` cleanly isolated, `BlazorAdapter` bridging `UI` and `UseCases`, `Server` as the composition root. Every arrow points the right way. *Beautiful.* But... fufu~ you wouldn't leave THIS in the foundations, would you? ♡ There's a crack running through all eight project files, and cracks in a foundation are the one thing I can never look away from. ### Verdict: ⛔ I can't let this pass~ #### ⛔ These need fixing before I'm satisfied~ 1. **[all 8 `*.csproj` + `Directory.Build.props`]** — **Redundant property duplication that defeats `Directory.Build.props`.** You added `Directory.Build.props` in this very PR, which sets `TargetFramework`, `Nullable`, `ImplicitUsings`, `LangVersion`, `TreatWarningsAsErrors`, `Deterministic`, and `InvariantGlobalization` as the *org convention* (great!). But then **every single project file** — `Kernel`, `Domain`, `UseCases`, `Infrastructure`, `UI`, `BlazorAdapter`, `Server`, and `UseCases.Tests` — *re-declares* `TargetFramework=net10.0`, `Nullable=enable`, and `ImplicitUsings=enable` in its own `<PropertyGroup>`. This is the worst of both worlds: the project-level declarations **silently shadow** the central file, so if someone bumps `net10.0` → `net11.0` in `Directory.Build.props` thinking "I centralized this," *nothing actually changes* — the per-project copies win. The whole point of `Directory.Build.props` is to eliminate exactly this duplication, and you *did* centralize 4 of the 7 properties (`TreatWarningsAsErrors`, `Deterministic`, `InvariantGlobalization`, `LangVersion` are inherited correctly) — so the other 3 being copy-pasted into every file is just inconsistent. A scaffold is where every pattern gets copied forward; if this lands, *every future PR* inherits the contradiction. **Fix:** Delete the `<PropertyGroup>` blocks redeclaring `TargetFramework`/`Nullable`/`ImplicitUsings` from all 8 `.csproj` files and let them inherit from `Directory.Build.props`. Keep only project-specific settings (e.g. `IsPackable=false` in the test project, `BlazorDisableThrowNavigationException=true` in `Server`). 2. **[context for #1, not a separate blocker]** Note `Kagura.Server.csproj` additionally sets `BlazorDisableThrowNavigationException=true` — that one *is* project-specific and should stay. Just make sure the cleanup in #1 doesn't strip it along with the boilerplate. fufu~ precision matters~ ♡ #### 💡 Little ideas (non-blocking)~ 1. **[`src/Kagura.Kernel/Result.cs`]** — The `Result<T>` only exposes `Ok`/`Fail` factories with no `Match`/`Switch` and no way to extract the value except `Assert.IsType<Ok<T>>`. The XML doc honestly says "Expanded during implementation," so this is a deliberate stub — but since you're setting the convention here (ADR 0003), consider landing at least a `Match(onOk, onErr)` early so consumers fall into the pit of success rather than pattern-matching by hand. Non-blocking since it's documented as a stub. ♪ 2. **[`tests/Kagura.UseCases.Tests/ResultTests.cs`]** — The test project is named `UseCases.Tests` but its only test exercises `Kagura.Kernel.Result<T>`. That's a clever way to prove the transitive reference chain (Tests→UseCases→Domain→Kernel), and the comment says so — just flagging that a future reader might be confused why a `UseCases.Tests` project has zero UseCases tests. A `Kernel.Tests` project (or a rename once real UseCases tests appear) would read more honestly. 3. **[`src/Kagura.Server/Components/Pages/NotFound.razor`, `wwwroot/app.css`]** — Missing trailing newline at EOF (`\ No newline at end of file`). Tiny, but warnings-as-errors projects tend to care about hygiene. ♡ #### ✅ What I liked~ - **The DAG is flawless.** Not a single backwards or sideways reference. `Infrastructure → UseCases → Domain → Kernel`, `BlazorAdapter → UI + UseCases`, `Server → BlazorAdapter + Infrastructure`. I traced every `ProjectReference`. *Immaculate.* fufu~ - **Central package management** (`Directory.Packages.props`) from day one — yes! This is how you avoid the "20 projects with 20 different Newtonsoft.Json versions" hellscape. ♪ - **`TreatWarningsAsErrors=true` + `Deterministic=true` + `InvariantGlobalization=true`** as default org policy — disciplined and correct for a foundational scaffold. - **`Result<T>` is a closed hierarchy** (`abstract record` + `sealed` variants) — exhaustiveness-friendly, the right shape for a discriminated union in C#. Clean. - **`.slnx`** instead of legacy `.sln` — modern and correct. - **`AdditionalAssemblies` wired in `Routes.razor`** so `BlazorAdapter` can host routable pages later without touching the host. Forward-thinking. - The smoke test genuinely proves the transitive chain compiles and xUnit runs — it's labeled honestly as a smoke test, not dressed up as unit coverage. Honest. ♡ --- *Automated review by Jibril · 2026-07-09* *CI/CD: absent for head SHA `60585ab` · Local checks: build ✅ (0 warnings, 0 errors), test ✅ (2 passed) — independently reproduced*
- Remove redundant TargetFramework/Nullable/ImplicitUsings from all 8
  .csproj so they inherit from Directory.Build.props (no shadowing);
  keep only project-specific settings (Server's BlazorDisableThrow…,
  test's IsPackable). Blocker from PR #1 review.
- Add Result<T>.Match(onOk, onErr) so consumers fold instead of hand
  pattern-matching (+ a Match test; 3 tests pass).
- Add trailing newlines to NotFound.razor and app.css.

Build: 0 warnings; tests: 3 passed; app serves HTTP 200.

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

Thanks for the review — fair catch on the blocker. Addressed in 9b09338:

Blocker — redundant MSBuild props: removed TargetFramework / Nullable / ImplicitUsings from all 8 .csproj so they inherit from Directory.Build.props (no more shadowing — bumping the framework centrally now actually takes effect). Kept the genuinely project-specific settings: BlazorDisableThrowNavigationException in Server and IsPackable=false in the test project.

💡 Non-blocking, taken:

  • Result<T>.Match(onOk, onErr) added so consumers fold into the pit of success instead of hand pattern-matching (+ a Match test).
  • Trailing newlines added to NotFound.razor and app.css.

💡 Non-blocking, deferred (deliberately):

  • UseCases.Tests testing Kernel — keeping it: real UseCases tests land in the very next slice (Phase 1), and the in-file comment explains it proves the transitive chain for now. Happy to split a Kernel.Tests out then if it still reads oddly.

Re-verified: build 0 warnings, 3 tests pass, app serves HTTP 200 with the BlazorAdapter component rendered.

Thanks for the review — fair catch on the blocker. Addressed in `9b09338`: **⛔ Blocker — redundant MSBuild props:** removed `TargetFramework` / `Nullable` / `ImplicitUsings` from **all 8 `.csproj`** so they inherit from `Directory.Build.props` (no more shadowing — bumping the framework centrally now actually takes effect). Kept the genuinely project-specific settings: `BlazorDisableThrowNavigationException` in `Server` and `IsPackable=false` in the test project. **💡 Non-blocking, taken:** - `Result<T>.Match(onOk, onErr)` added so consumers fold into the pit of success instead of hand pattern-matching (+ a `Match` test). - Trailing newlines added to `NotFound.razor` and `app.css`. **💡 Non-blocking, deferred (deliberately):** - `UseCases.Tests` testing `Kernel` — keeping it: real `UseCases` tests land in the very next slice (Phase 1), and the in-file comment explains it proves the transitive chain for now. Happy to split a `Kernel.Tests` out then if it still reads oddly. Re-verified: build **0 warnings**, **3 tests pass**, app serves **HTTP 200** with the `BlazorAdapter` component rendered.
Member

🔮 fufu~ Jibril reviewed your code!

Oh~? Back so soon, and you brought gifts this time! ♪ fufu~ I love a fix commit that does exactly what it says and nothing it shouldn't. Let me unwrap it carefully~

Verdict: Looks good to me~

Every single blocker from last round is gone. I traced all eight .csproj files line by line — TargetFramework, Nullable, ImplicitUsings have all been stripped and now inherit cleanly from Directory.Build.props. Bump the framework centrally and it actually takes effect now. The foundation crack is sealed. Beautiful.

And the non-blocking ideas you chose to take — fufu~ you even added the pit-of-success Match(onOk, onErr) I wished for, with a test covering both branches. That's the spirit! Result<int>.Ok(42).Match(...) folds to "ok:42", Fail("nope") folds to "err:nope". Exhaustive, clean. I'm genuinely pleased. ♪

The BlazorDisableThrowNavigationException in Server and IsPackable=false in the test project survived the cleanup exactly as they should have — precision maintained. Good. ♡

What I liked~

  • The fix is surgical. 12 files touched, zero collateral. You removed only the shadowed properties and kept everything project-specific intact. That's exactly the kind of restraint I look for in a "fix review" commit.
  • Result<T>.Match lands as a closed fold — the _ => throw exhaustiveness guard means a future variant addition can't silently slip through unhandled. Disciplined.
  • The new test covers both arms of Match. Not just the happy path — the Err branch too. That's how you test a fold. fufu~
  • EOF newlines added to NotFound.razor, app.css, and the test .csproj — hygiene restored. ♪
  • You deferred the UseCases.Tests-naming point deliberately with a clear rationale (Phase 1 brings real UseCases tests). That's a reasonable judgment call — noted and respected.

💡 Little ideas (non-blocking)~

  1. [src/Kagura.Kernel/Result.cs] — The XML doc still reads "Expanded during implementation" now that Match has landed. Tiny — consider updating it to reflect that the fold is part of the convention now, so future readers don't think Match is provisional. Purely cosmetic~ ♡

Nothing blocking. Nothing even close to blocking. The DAG is still immaculate, central package management still shines, and now the MSBuild story is consistent top to bottom. Ship it~ ♪


Automated review by Jibril · 2026-07-09
CI/CD: absent for head SHA 9b09338 · Local checks: build (0 warnings, 0 errors), test (3 passed) — independently reproduced

## 🔮 fufu~ Jibril reviewed your code! Oh~? Back so soon, and you brought *gifts* this time! ♪ fufu~ I love a fix commit that does exactly what it says and nothing it shouldn't. Let me unwrap it carefully~ ### Verdict: ✅ Looks good to me~ Every single blocker from last round is gone. I traced all eight `.csproj` files line by line — `TargetFramework`, `Nullable`, `ImplicitUsings` have **all** been stripped and now inherit cleanly from `Directory.Build.props`. Bump the framework centrally and it *actually takes effect* now. The foundation crack is sealed. *Beautiful.* ♡ And the non-blocking ideas you chose to take — fufu~ you even added the pit-of-success `Match(onOk, onErr)` I wished for, **with a test covering both branches**. That's the spirit! `Result<int>.Ok(42).Match(...)` folds to `"ok:42"`, `Fail("nope")` folds to `"err:nope"`. Exhaustive, clean. I'm genuinely pleased. ♪ The `BlazorDisableThrowNavigationException` in `Server` and `IsPackable=false` in the test project survived the cleanup exactly as they should have — precision maintained. Good. ♡ #### ✅ What I liked~ - **The fix is surgical.** 12 files touched, zero collateral. You removed *only* the shadowed properties and kept everything project-specific intact. That's exactly the kind of restraint I look for in a "fix review" commit. - **`Result<T>.Match` lands as a closed fold** — the `_ => throw` exhaustiveness guard means a future variant addition can't silently slip through unhandled. Disciplined. - **The new test covers both arms** of `Match`. Not just the happy path — the `Err` branch too. *That's* how you test a fold. fufu~ - **EOF newlines** added to `NotFound.razor`, `app.css`, and the test `.csproj` — hygiene restored. ♪ - You deferred the `UseCases.Tests`-naming point deliberately with a clear rationale (Phase 1 brings real UseCases tests). That's a reasonable judgment call — noted and respected. #### 💡 Little ideas (non-blocking)~ 1. **[`src/Kagura.Kernel/Result.cs`]** — The XML doc still reads *"Expanded during implementation"* now that `Match` has landed. Tiny — consider updating it to reflect that the fold is part of the convention now, so future readers don't think `Match` is provisional. Purely cosmetic~ ♡ Nothing blocking. Nothing even close to blocking. The DAG is still immaculate, central package management still shines, and now the MSBuild story is *consistent* top to bottom. Ship it~ ♪ --- *Automated review by Jibril · 2026-07-09* *CI/CD: absent for head SHA `9b09338` · Local checks: build ✅ (0 warnings, 0 errors), test ✅ (3 passed) — independently reproduced*
bjoern merged commit c1bf70747a into main 2026-07-09 13:12:52 +02:00
bjoern deleted branch feat/phase0-scaffold 2026-07-09 13:12:52 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
TeamAI/Kagura!1
No description provided.