Skip to content

chore(claude): refine Clean promotion signal — dependency rule vs project split#50

Merged
emeraldleaf merged 2 commits into
mainfrom
chore/refine-clean-promotion-signal
Jun 3, 2026
Merged

chore(claude): refine Clean promotion signal — dependency rule vs project split#50
emeraldleaf merged 2 commits into
mainfrom
chore/refine-clean-promotion-signal

Conversation

@emeraldleaf

@emeraldleaf emeraldleaf commented May 29, 2026

Copy link
Copy Markdown
Owner

Summary

Sharpens the CLAUDE.md "Promotion signal" section. A discussion surfaced that the prior framing ("Clean is earned / for complex services") conflated two separable things that both wear the name "Clean Architecture":

  • The dependency rule (Domain → nothing; IO at the edges) is already in force in VSA, applies at every scale, and is not what the promotion signal gates. Decoupling the domain from frameworks is always worth it.
  • The multi-project structure (4 csprojs) is the only part with ceremony, and the only thing the promotion signal gates. All it buys over single-project VSA is compile-time enforcement of the dependency rule via project references.

The added insight — enforcement is a spectrum

The real axis is how you enforce the dependency rule, escalating with the cost of a violated boundary: convention → architecture tests → project split. Names the middle rung most teams skip: an architecture test (NetArchTest / ArchUnitNET / Roslyn analyzer) asserting "Domain references no EF/Infrastructure namespaces" enforces the same boundary the 4-project split does — deterministically in CI, without the ceremony. So the split is rarely needed for enforcement alone — reach for it only when domain complexity makes you want the compiler (not a test) to hold the line, or when separate deploy/versioning units justify it.

Changes

  • New prose block disentangling the dependency rule from the project structure.
  • New table row for the architecture-tests rung.
  • Existing "5+ aggregates → consider Clean" row reframed as "when you want the compiler to hold the boundary, or need separate deploy/versioning units" (instead of blurring principle into structure).
  • Notes NextAurora enforces the rule today via convention + architecture-reviewer + CodeRabbit; architecture tests (NetArchTest) would be the next rung without changing the VSA shape — flagged as a candidate future improvement, not mandated.

Paraphrase-drift audit (per CLAUDE.md change)

Run /check-rules locally to audit paraphrases against this diff. Done — the refinement is net-new nuance; no existing See CLAUDE.md marker paraphrases the promotion signal or the dependency-rule-vs-structure distinction, and it's consistent with the "Layer Dependencies" rule it references. No drift.

Test plan

  • Paraphrase-drift audit run — no drift
  • Consistent with "Layer Dependencies" (Domain → nothing) and the VSA-everywhere "Project Structure" rule

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Reworked guidance on promoting Clean Architecture to clarify that dependency rules are already met under the current approach and to separate those rules from multi-project (compile-time) splits.
    • Replaced “promotion” phrasing with an explicit escalation ladder: convention → CI-enforceable architecture tests → project split.
    • Updated criteria table and added a link to the portable decision guide.

Review Change Stack

… project split

Sharpens the "Promotion signal" section after a discussion surfaced that
the prior framing ("Clean is earned / for complex services") conflated two
separable things that both wear the name "Clean Architecture":

- The DEPENDENCY RULE (Domain -> nothing; IO at the edges) is already in
  force in VSA, applies at every scale, and is NOT what the promotion
  signal gates. Decoupling the domain from frameworks is always worth it.
- The MULTI-PROJECT STRUCTURE (4 csprojs) is the only part with ceremony
  and the only thing the promotion signal gates — all it buys over
  single-project VSA is compile-time enforcement of the dependency rule
  via project references.

Adds the real axis: how you ENFORCE the dependency rule, escalating with
the cost of a violated boundary — convention -> architecture tests ->
project split. Names the middle rung most teams skip: an architecture test
(NetArchTest / ArchUnitNET / Roslyn analyzer) asserting "Domain references
no EF/Infrastructure namespaces" enforces the same boundary the 4-project
split does, deterministically in CI, without the ceremony. So the project
split is rarely needed for enforcement alone — reach for it only when
domain complexity makes you want the compiler (not a test) to hold the
line, or when separate deploy/versioning units justify it.

New table row for the architecture-tests rung; existing "5+ aggregates"
row reframed as "when you want the compiler to hold the boundary" rather
than "consider Clean" (which blurred principle into structure).

Notes NextAurora enforces the rule today via convention + the
architecture-reviewer agent + CodeRabbit; adding architecture tests would
be the next rung without changing the VSA shape (a candidate future
improvement, not mandated here).

Paraphrase-drift audit: run /check-rules locally to audit paraphrases
against this diff. Done — the refinement is net-new nuance; no existing
See-CLAUDE.md marker paraphrases the promotion signal or the
dependency-rule-vs-structure distinction, and it's consistent with the
"Layer Dependencies" rule it references. No drift.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@codecov

codecov Bot commented May 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@coderabbitai

coderabbitai Bot commented May 29, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fc6cada5-5678-4fc4-a38e-b61c7812d30c

📥 Commits

Reviewing files that changed from the base of the PR and between 4d724ec and e535f1b.

📒 Files selected for processing (1)
  • CLAUDE.md

Walkthrough

The PR updates CLAUDE.md to clarify that the domain dependency rule is already enforced in VSA, defines "promote to Clean" as a multi-project (compile-time) split, and introduces an escalation ladder: convention → architecture tests (NetArchTest/Analyzer) → project split.

Changes

Architecture Promotion Progression

Layer / File(s) Summary
Promotion signal and progression guidance
CLAUDE.md
Rewrote the "Promotion signal" section to define "promote to Clean" as the multi-project structure, stated the dependency rule is already present in VSA, introduced an escalation ladder (convention → architecture tests → project split), and replaced the prior "Clean Architecture promotion" table row with an "Architecture tests" row (NetArchTest/ArchUnitNET/Roslyn analyzer).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and specifically describes the main change: refining the Clean Architecture promotion signal guidance to distinguish between the dependency rule and the project split concept.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/refine-clean-promotion-signal

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CLAUDE.md`:
- Around line 98-127: Add the required follow-up note to CLAUDE.md next to the
changed section stating: "Run /check-rules locally to audit paraphrases against
this diff." Then run the repository's /check-rules tool locally to locate all
paraphrases that end with "See CLAUDE.md", update any that now need revised
wording, and commit those paraphrase updates; ensure the note is present near
the paragraph that distinguishes "dependency rule" vs "multi-project structure"
so reviewers can see the audit instruction.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bbe14d5a-691b-41b8-8038-e49b7eed1661

📥 Commits

Reviewing files that changed from the base of the PR and between 6f340be and 4d724ec.

📒 Files selected for processing (1)
  • CLAUDE.md

Comment thread CLAUDE.md
Comment on lines +98 to +127
**What "promote to Clean" actually means — the dependency rule vs. the project split.** Two
different things wear the name "Clean Architecture," and only one of them is what you'd
promote *to*:

- **The dependency rule** (Domain → nothing; infrastructure/IO at the edges) is *already in
force* in VSA and applies at every scale. It is **not earned, not complexity-gated, and
not what the promotion signal is about** — NextAurora keeps it today as single-project VSA
(see "Layer Dependencies"). Decoupling the domain from frameworks is always worth it.
- **The multi-project structure** (separate Domain/Application/Infrastructure/Api csprojs) is
the only part that carries ceremony, and the only thing the promotion signal gates. All it
buys over single-project VSA is **compile-time enforcement** of the dependency rule via
project references.

So the real axis is *how you enforce the dependency rule*, escalating only as the cost of a
violated boundary rises: **convention → architecture tests → project split.** The middle rung
is the one most teams skip: an **architecture test** (NetArchTest / ArchUnitNET, or a Roslyn
analyzer) asserting "Domain references no EF/Infrastructure namespaces" enforces the *same*
boundary the 4-project split does — deterministically, in CI, **without the project
ceremony**. The project split is therefore rarely needed *for enforcement alone*; reach for it
only when genuine domain complexity makes you want the *compiler* (not a test) to hold the
line, or when separate deploy/versioning units justify it. NextAurora enforces the dependency
rule today via *convention + the architecture-reviewer agent + CodeRabbit*; adding
architecture tests would be the next rung and would make it deterministic **without changing
the VSA shape**.

| Signal | Shape |
|---|---|
| ≤4 aggregates per service, ≤10 features, single team | VSA (current default) |
| 5+ aggregates with cross-cutting domain rules that several features coordinate on, AND `Domain/` growing faster than `Features/` | Consider Clean Architecture promotion |
| "I want the dependency rule enforced, not just held by convention" | **Architecture tests** (NetArchTest / analyzer) — NOT a project split. Same boundary, no ceremony |
| 5+ aggregates with cross-cutting domain rules that several features coordinate on, AND `Domain/` growing faster than `Features/` | Consider the multi-project split — when you want the *compiler* to hold the boundary, or need separate deploy/versioning units |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Required follow-up for CLAUDE.md rule drift audit.

Run /check-rules locally to audit paraphrases against this diff.

As per coding guidelines, “When this changes, every paraphrase ending in ‘See CLAUDE.md’ elsewhere in the repo may need updating. Flag the CLAUDE.md change with a note: ‘Run /check-rules locally to audit paraphrases against this diff.’”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CLAUDE.md` around lines 98 - 127, Add the required follow-up note to
CLAUDE.md next to the changed section stating: "Run /check-rules locally to
audit paraphrases against this diff." Then run the repository's /check-rules
tool locally to locate all paraphrases that end with "See CLAUDE.md", update any
that now need revised wording, and commit those paraphrase updates; ensure the
note is present near the paragraph that distinguishes "dependency rule" vs
"multi-project structure" so reviewers can see the audit instruction.

Adds a deep-dive link from the refined "Promotion signal" section to the
new portable decision guide (docs/vsa-vs-clean-architecture.md, PR #51):
the CLAUDE.md section is NextAurora's specific rule; the doc is the
general two-meanings-of-Clean / enforcement-spectrum / testing-shift /
duplication-tradeoff reference behind it. Pointer only — no rule change.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
emeraldleaf added a commit that referenced this pull request Jun 3, 2026
A reusable, system-agnostic synthesis of the VSA-vs-Clean decision,
distilled from a multi-turn architecture discussion. Written to be lifted
into any project; NextAurora is the worked example at the end, not the
premise. Same pattern as docs/messaging-transport-selection.md — portable
reference knowledge, kept OUT of CLAUDE.md (which holds THIS repo's rules).

Core points it lands:
- "Clean Architecture" is two things: the DEPENDENCY RULE (always-on, not
  earned, not in tension with VSA) and the 4-PROJECT STRUCTURE (the only
  part with ceremony, the only part the "is it worth it" question is about).
- VSA and Clean are orthogonal axes — organization/cohesion vs dependency
  direction. "Combine" = organize by feature + keep the domain decoupled.
- VSA does NOT auto-enforce the dependency rule; you enforce it on a
  spectrum: convention → architecture tests → project split. The middle
  rung (NetArchTest/ArchUnitNET) gives the SAME enforcement as the
  4-project split WITHOUT the ceremony, at the namespace level in a single
  project. Code example included.
- Two meanings of "combine": orthogonal axes + per-slice complexity
  gradient.
- Testcontainers shifted the calculus: integration-default for IO-touching
  code beats mock-heavy unit tests, which collapses the
  repository-interface-for-testability argument. But it's a Testing
  Trophy, not a pure rectangle — keep fast unit tests for pure domain
  logic; mind the Docker dependency + speed cost.
- The duplication tradeoff: keep cross-cutting concerns in pipeline
  behaviors (not per-slice), prefer duplication over the wrong
  abstraction; cost scales with slice count and bites hardest on pure CRUD.
- When-to-use table + common mistakes (incl. "don't add a repo interface
  per slice on EF", "don't 4-project-split just to get the dependency
  rule", "don't mix layered + sliced services in one solution").

README Documentation table updated to index it. No CLAUDE.md edit here
(kept separate to avoid colliding with the open promotion-signal PR #50,
which is where the in-repo deep-dive pointer will be added).

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
@emeraldleaf

Copy link
Copy Markdown
Owner Author

Run /check-rules locally to audit paraphrases against this diff.

@emeraldleaf
emeraldleaf merged commit 1e3863b into main Jun 3, 2026
7 checks passed
@emeraldleaf
emeraldleaf deleted the chore/refine-clean-promotion-signal branch June 3, 2026 00:29
emeraldleaf added a commit that referenced this pull request Jun 10, 2026
dev-loop.md still carried the pre-#50 3-row table; CLAUDE.md's canonical
version added the "architecture tests — NOT a project split" middle rung.
Paraphrase now matches verbatim.

Closes #66

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
emeraldleaf added a commit that referenced this pull request Jun 13, 2026
…oses #66) (#126)

* docs: encoding loop method — hero infographic + skill + supporting infra

The system behind "AI that codes the way I want" — the methodology canon
for AI-assisted code that compounds quality.

- docs/encoding-loop-hero.jpg: v16 hero (Nano Banana Pro at 2K). Navy +
  amber + cream. Signature ratchet wheel hub with 5 trigger entry points
  feeding into "Pick smallest surface." 5 surfaces ordered by enforcement
  strength (soft → strong). 3-tier spectrum. Live YAML CI gate. 6
  disciplines (4 mechanical + 2 convention). Pandey-style numbered grid.

- docs/encoding-loop-infographic.{excalidraw,svg}: canonical editable
  reference. Deterministic counterpart to the hero — same content, fully
  versionable, every text element exact.

- CONTEXT.md: domain vocabulary glossary. Defines encoding loop, 5
  surfaces, 3 tiers, mechanical floor, harness vs method, agentic coding
  tools. Pattern stolen from mattpocock/skills. Distinct from CLAUDE.md
  (rules) — this is vocabulary, not conventions.

- .claude/commands/grid-infographic.md: new skill for the Nano Banana Pro
  pipeline at 2K. Includes blueprint-approval gate so content errors get
  caught before any API call (avoids burning generations on misframed
  prompts).

- .claude/commands/*.md: disable-model-invocation: true on all six
  user-invoked slash commands. Stops them auto-firing on description
  match — they're explicit rituals, not assistive guesses.

- .claude/scripts/render-hero.sh: deterministic HTML → PNG renderer via
  Playwright. Counterpart to rebuild-diagrams.sh for the Excalidraw
  pipeline.

- docs/skill-bucket-organization.md: engineering / productivity bucket
  convention for .claude/commands/. Adapted from mattpocock/skills.

- .gitignore: adds docs/post-ideas/ as the post-draft sandbox.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(audits): log miro-mcp-shared-context audit

Same problem identified (AI lacks decision context); mechanism explicitly
rejected via docs/dev-loop.md:583 ("MCP servers | Not building an MCP server")
+ :586 (Spec Kit per-feature flow as ceremony). Canon-in-repo is the project's
answer. No action — optional one-line consolidation flagged for next
dev-loop.md edit (MCP entry rationale is currently tautological).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(audits): log vsa-when-it-works audit

Anton Martyniuk infographic on VSA "bad if" vs "amazing if" rules.
Most rules aligned with NextAurora's encoding (no MediatR, no IHandler
interface, simple handler class, no business logic in endpoint). Two
material divergences: file granularity (NextAurora: 1 file per slice;
Anton: 4 files per slice) and expected-error handling (NextAurora throws
exceptions; Anton recommends Result<T>). Both NextAurora positions are
intentional choices or unmade-decisions-by-default; neither warrants
flipping.

Three optional consolidations flagged for next CLAUDE.md edit:
line-count soft cap on feature files, exception-vs-Result stance,
no-IHandler-interface rationale.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: consolidate audit-flagged rules across CLAUDE.md + dev-loop.md

Encodes four rules surfaced by recent audits (Miro MCP, VSA-when-it-works):

1. dev-loop.md MCP servers row — replace tautological "Not building an MCP
   server" with the rationale (canon-in-repo + auto-load gives persistent
   decision context; MCP bridge is convergence-in-the-wrong-direction).
   Paraphrase in .github/AI_WORKFLOW.md mcp-builder row updated to match
   per the cross-reference rule. Source: 2026-06-07 Miro audit.

2. CLAUDE.md Project Structure — feature-file size soft cap (~300 lines).
   Co-location stays the canon; "giant file" warning is enforced via size
   cap, not file count per slice. Largest feature today (PlaceOrder.cs)
   is 182 lines. Source: 2026-06-08 VSA audit.

3. CLAUDE.md Key Conventions — exception-based control flow is the canon.
   No Result<T> / OneOf<T> / ErrorOr<T> discriminated-union error type.
   Defensible trigger to flip named (profiled exception cost in hot path
   OR saga step with high expected-failure rate). Source: 2026-06-08 VSA
   audit.

4. CLAUDE.md Communication Patterns — no IRequestHandler / IFooHandler
   interface per handler. Wolverine assembly-scans Features/ and binds
   message-type → handler-type directly; the MediatR-style "interface
   for testability" pattern doesn't apply (Wolverine's bus IS the
   abstraction). Source: 2026-06-08 VSA audit.

All four rules pass the cross-reference grep (only one paraphrase found
outside the edited files — AI_WORKFLOW.md MCP row, updated in this commit).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: align AI_WORKFLOW mcp-builder row with new dev-loop.md MCP rationale

Cross-reference cleanup that should have shipped with 360c879. The
mcp-builder row in .github/AI_WORKFLOW.md was the only paraphrase of
the dev-loop.md MCP-servers rule found by the cross-reference grep.
Now consistent with the canonical wording.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(audits): log vsa-1-folder-4-files audit (Anton restatement)

LinkedIn long-form version of yesterday's Anton Martyniuk VSA infographic.
Same author, same core thesis — verdict and divergences identical to
2026-06-08-vsa-when-it-works.md. Today's post adds teaser content for
tomorrow's newsletter (Shared/ folder rules, auto-registration,
cross-slice events without MediatR, PublicApi pattern), which can't be
audited until the actual newsletter ships.

No new encoding work; the four rules from yesterday's audit shipped this
morning in 360c879 + 9323aff.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(audits): log jwt-authentication-aspnet-core audit

Mukesh Murugan's JWT-in-ASP.NET-Core walkthrough. Most claims aligned or
out-of-scope (NextAurora uses Keycloak as IdP — signing key, login,
refresh token aren't NextAurora's responsibility). One material
divergence: ClockSkew (article: Zero for exact expiry; NextAurora: 30s
to tolerate NTP drift while limiting linger). One consolidation flagged
for next ServiceDefaults edit — explicit MapInboundClaims = false to
make the claim-mapping flow auditable instead of relying on the
Microsoft-flavored default.

NextAurora's encoding is materially stricter on the adjacent
authorization pattern: IDOR-prevention via predicate-in-WHERE-clause +
404-not-403 + integration test required, plus middleware order
threading CorrelationIdMiddleware between auth and authz.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: align dev-loop.md Promotion Signal table with CLAUDE.md (4 rows)

dev-loop.md still carried the pre-#50 3-row table; CLAUDE.md's canonical
version added the "architecture tests — NOT a project split" middle rung.
Paraphrase now matches verbatim.

Closes #66

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(docs): plain-text refs for gitignored paths — broken-link audit

docs/post-ideas/ and .claude/audits/*.md are deliberately local-only
(gitignored); markdown-linking them fails CI's broken-link audit.
Convert to backtick path references — the pointer survives, the link
contract doesn't.

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant