Skip to content

test(arch): the F105 architecture fitness suite — six laws, front-and-center (T211–T215) - #407

Merged
genwave-radio merged 6 commits into
mainfrom
feat/f105-suite
Aug 8, 2026
Merged

test(arch): the F105 architecture fitness suite — six laws, front-and-center (T211–T215)#407
genwave-radio merged 6 commits into
mainfrom
feat/f105-suite

Conversation

@genwave-radio

Copy link
Copy Markdown
Collaborator

🏛️ What

PR 1 of the F105 adoption slice (SPEC F105.1–F105.5, gh-#398/#399/#400): the architecture laws become executable fitness tests running inside the normal dotnet test gate, and the contract goes front-and-center in CONTRIBUTING.md.

Commit Task Delivered
aee1b18 /plan scaffold 24 pending specs, tests/GenWave.Architecture.Tests sln-added
411912c T211 L1/L2/L4-references + the named+dated exemption mechanism. ArchUnitNET 0.13.3 adopted for L2's method-body reach; L1/L4 hand-rolled (both candidate libraries silently under-cover unloaded assemblies); L4 rebuilt on the deps.json libraries map after review proved a System.*-prefix bypass
59c821d T212 L3 — the HttpClient/handler/invoker family confined to 18 designated seams, via a hand-rolled metadata scanner (flat type-table walk + compiler-generated roll-up — closes the async-lambda hole ArchUnitNET can't see, review-proven against a live anonymous endpoint); Program.cs source-text pin (3 registrations, AllowAutoRedirect = false, no raw clients)
ec68a1d T213 L4-immutability (interface setters, required, statics, nested types all covered) + L6 (independently valuable: a raw file <Reference> bypasses deps.json — mutation-proven)
74f478f T214 L5 — Host reserved-namespace tripwire seeded Context#378, Ads#380; one shared dot-boundary helper guarded at two layers
7cd1d23 T215 CONTRIBUTING laws table (seven ids, 1:1 with LawId — drop a row and exactly that id reds, both directions) + seam criterion with the demonstrated-need clause + F105.2's "never baseline your own change" sentence

✅ Gates

  • Every task through builder → independent opus review; three of five failed round one and the catches were real: the System.* L4 bypass, the async-lambda L3 blindness, six shipped-doc wording defects including one false claim. All fixes mutation-proven.
  • 77 architecture facts, every law's detector proven discriminating (hermetic probes + live facts split so a real violation reds exactly one fact); self-resolving seam/exemption lists (phantom entries red).
  • Adoption honest per F105.2: zero violations fixed silently — 2 designed composition-root exemptions + 5 real debt entries baselined, named, dated, and filed as gh-arch: 5 baselined L2 violations — Host queries Postgres outside the repository layer (F105.2 debt) #406.
  • Full suite: 3,031 passed / 0 failed across 7 projects, zero warnings. Zero production-code changes.

🚦 Next

PR 2 (feat/f105-seams, T216–T217): the generated SEAMS.md + CI byte-diff rider — building now, targets main after this merges.

…RIES 290–294)

24 pending specs across Story290–294; GenWave.Architecture.Tests sln-added;
library adoption + exemption mechanism are T211's to build.
…es (T211, STORY-290)

- ArchUnitNET 0.13.3 adopted for L2 (Postgres confinement) — method-body reach,
  not just declared references. Both ArchUnitNET and its runner-up
  (NetArchTest.eNhancedEdition) silently under-cover assemblies not explicitly
  loaded up front, so L1 and L4-references use different techniques instead
  (recorded in the csproj comment): L1 hand-rolls an AssemblyRef metadata scan
  (exhaustive over direct references); L4-references reads the project's own
  build-output deps.json libraries map (a name-prefix check has a proven
  bypass — a System.*-named third-party package ships straight into the
  dependency closure without ever failing a "System" prefix check).
- Named+dated exemption baseline: 2 designed composition-root entries
  (NpgsqlDataSource wiring, not querying) + 5 pre-existing debt entries
  stamped gh-#406, all failing on any NEW violation not on the list.
- Hermetic per-law probes (Fixtures/L2Probe, Fixtures/L4Probe, and a stable
  third-party assembly for L1) prove each detector discriminates without
  coupling the proof to production's live dependency graph.
…etadata scan (T212, STORY-291)

- Hand-rolled System.Reflection.Metadata scanner (flat type-table walk,
  compiler-generated roll-up) closes the async-lambda hole ArchUnitNET
  can't see — a nested compiler-generated type inside another never
  surfaces in ArchUnitNET's graph.
- Forbid widened to the 5-type handler/invoker family (HttpClient,
  HttpMessageInvoker, HttpMessageHandler, HttpClientHandler,
  SocketsHttpHandler) — a working outbound client built without ever
  naming HttpClient still trips the law.
- Program.cs source-text pin: exactly 3 AddHttpClient registrations,
  AllowAutoRedirect=false, and no raw hand-rolled client.
- Self-resolving seam and exemption lists — a deleted/typo'd entry now
  reds instead of silently matching nothing.
- AllProductionAssemblies factory on ProductionAssemblies, shared by
  L2 and L3 (and future T213/T214 laws) instead of copy-pasted lists.
…able and Core-free (T213, STORY-291)

- Reflection-based member-shape detector for L4-immutability: init-only detected via the
  IsExternalInit required custom modifier; interface setters, required members, statics, and
  nested types all covered.
- L6 via the AssemblyRef scan scoped to GenWave.Core — independently valuable, not just sharper
  wording over L4-references: a raw file-Reference bypasses deps.json's library map entirely,
  mutation-proven at review.
- Zero violations found in either law; no baseline entries needed.
… (T214, STORY-292)

- Reflection-based detector: no metadata-table workaround needed, unlike L3 — nested/compiler-
  generated types are visible by Assembly.GetTypes()'s own documented contract; still rolled up to
  the outermost declaring type for legible attribution.
- One growth-tolerant reservation list ({ReservedNamespace, RulingReference, Reason}), seeded
  GenWave.Host.Context -> gh-#378 and GenWave.Host.Ads -> gh-#380, both citing F105.4.
- Boundary matching reuses the one shared AssemblyReferenceScan.HasFamilyPrefix instead of a
  hand-rolled duplicate; a same-prefix-lookalike fixture guards the boundary at the L5 layer too.
- ProductionAssemblies.HasType taught member- and assembly-level granularities (T213 review
  carry-forward), with BindingFlags.DeclaredOnly closing the inherited-object-member blind spot.
…suite↔doc parity (T215, STORY-293)

- Seven-id table mirroring LawId 1:1 (drop a row → exactly that id red, both directions)
- F105.2's never-baseline-your-own-change sentence ships
- Seam criterion verbatim with the demonstrated-need clause
- Honest L2 wording (designed exemption vs gh-#406 baselines)
- LawId.IdPattern single-sources the id shape (parser + All guard consume it)
- SolutionLocator.Root() extracted
- knownLawIds carry-forward closed via LawId.All
@genwave-radio
genwave-radio merged commit 1b547ed into main Aug 8, 2026
11 checks passed
@genwave-radio
genwave-radio deleted the feat/f105-suite branch August 8, 2026 02:51
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 8, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant