Skip to content

feat(generator): discover DTOs carried as [Factory] entity properties (TRIM-002) - #70

Merged
keithdv merged 8 commits into
mainfrom
TRIM-002-entity-property-discovery
Jul 6, 2026
Merged

feat(generator): discover DTOs carried as [Factory] entity properties (TRIM-002)#70
keithdv merged 8 commits into
mainfrom
TRIM-002-entity-property-discovery

Conversation

@keithdv

@keithdv keithdv commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Third plan of the TRIM todo — the second of the two zTreatment failure classes. DTO discovery correctly refused to treat [Factory] entities as DTOs, but never walked their properties, so a DTO reachable only as an entity property (TreatmentBanner on the [Execute]-opened aggregate, DashboardContactResult in a List<T> on a query entity) got no preservation and was trimmed on the client.

Changes

  • Entity property-graph discovery: every class carrying [Factory] directly walks its own public property graph (inherited chain included) during generation and emits Register<T>/PreserveType<T> for reachable DTOs in its own registrar. The entity itself is never bucketed (DI registration preserves it); factory-typed properties are skipped — each [Factory] class's own registrar owns its graph, so no global reachability set and free cross-entity cycle safety.
  • Namespace hardening (TRIM-001 code-review callout): IsDtoStructureCandidate's System exclusion is now a segment match — consumer namespaces like Systems.Domain are no longer silently excluded, while System/System.* framework types remain excluded (both halves pinned by tests).
  • Tests: 13 new EntityPropertyDtoDiscoveryTests with per-tree registrar assertions (child-vs-parent separation), base-class inheritance, [Factory] record aggregates, LazyLoad<T> Value-descent, cycles, cross-walk dedupe. Harness: EntityPropertyDtoSmokeTest — carried DTO + record never constructed in harness code, negative control verified (walk disabled → ctor stripped → exit 1).
  • Docs: docs/trimming.md + CLAUDE-DESIGN.md now document the entity-graph entry point, the manual-preservation boundary, and the deliberate interface-factory-impl exception.
  • Skips the second flaky RelayTimingTests member (identical timeout signature; per user decision).

Reviews (in docs/todos/TRIM-dto-trimming-preservation-gaps/reviews/)

  • Plan review: APPROVED, 5 callouts folded in — incl. correcting the draft's LazyLoad suspicion (002-plan-review.md)
  • Test gate: CLEARED — should-covers closed with tests (002-test-review.md)
  • Code review: no veto findings (002-code-review.md)

Test plan

  • Units 581+581 → 585+585 green; integration 561+561 green (sequential run authoritative — the pre-existing FactoryEventRelay family is parallel-load flaky, all members green isolated/sequential)
  • Trimmed harness green locally (win-x64), negative control verified
  • This PR's CI run exercises the trimming gate on linux-x64

🤖 Generated with Claude Code

keithdv and others added 8 commits July 6, 2026 15:28
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Intermittent 2s WaitAsync timeout under parallel test load (observed
locally and on PR #69 CI; passes in isolation and on re-runs). Skipped
per user decision; no fix queued.

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

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… (TRIM-002)

WalkDtoGraph correctly refused to treat [Factory] entities as DTOs but
never walked their properties, so a DTO reachable only as an entity
property (zTreatment's TreatmentBanner / DashboardContactResult) got no
preservation and was trimmed on the client.

Every class carrying [Factory] directly now walks its own public property
graph during TypeInfo construction (alongside the ordinal-property walk)
and emits Register/PreserveType for reachable DTOs in its own registrar.
The entity itself is never bucketed (DI registration preserves it), and
factory-typed properties are skipped — each [Factory] class's own
registrar owns its graph. Also tightens the System-namespace exclusion
to a segment match (Systems.Domain-style consumer namespaces were
silently excluded — TRIM-001 code-review callout).

- Unit: EntityPropertyDtoDiscoveryTests (9) incl. per-tree child-vs-parent
  registrar assertions, LazyLoad<T> Value-descent, cycles, Systems.*
- Trimmed harness: EntityPropertyDtoSmokeTest — carried DTO + record never
  constructed in harness code; negative control verified (walk disabled →
  ctor stripped → harness exits 1)
- Docs: trimming.md + CLAUDE-DESIGN.md entity property-graph discovery
- Skips second flaky RelayTimingTests member (same signature, per user
  decision)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dedupe, System exclusion

Adds the four gate-requested tests (inherited base-chain property,
[Factory] record aggregate self-walk, cross-walk dedupe, System.*
exclusion half of the hardening) and anchors the per-tree FactoryTree
helper to the .{hint}.g.cs file-name shape so hints can never
substring-match another factory's tree.

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

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@keithdv
keithdv merged commit c26bcd2 into main Jul 6, 2026
2 checks passed
@keithdv
keithdv deleted the TRIM-002-entity-property-discovery branch July 6, 2026 21:34
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