Skip to content

MagicAST restructure: Phase 5 — Optional DTO layer for AST/JSON decoupling #6

Description

@Spelkington

Parent

Part of the MagicAST restructure milestone. Phase 5 of 5. Marked ready-for-human because the decision to do this phase at all is a HITL judgment call gated on observable diagnostic quality after Phase 2 ships.

What to build

After Phase 2 (#3) lands, the worst of the AST↔JSON coupling is already gone: base classes no longer carry [JsonPolymorphic] lists, and concrete types carry domain-flavored [OracleAbility] / [OracleEffect] attributes instead of JSON-flavored ones. However, individual AST records may still carry per-property JSON attributes:

  • [JsonPropertyName("...")]
  • [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
  • [JsonConverter(...)]

The open question: are the post-Phase-2 test diagnostics good enough as they are?

When an agent's hand-parsed JSON has an unmapped field or an unknown discriminator, the JsonException they see today references JSON-layer vocabulary (property names, types). If that's clear enough for the TDD loop, this phase is unnecessary and should be closed as wontfix.

If diagnostics still leak JSON-internal vocabulary in a way that confuses agents reading red test output, introduce a thin DTO mirror layer:

libs/magic-ast/
├── AST/                    ← pure domain records, ZERO [Json*] attributes
└── Serialization/
    └── Dto/                ← mirrors of each AST record, carrying JSON attributes
        ├── AbilityDto.cs
        ├── EffectDto.cs
        └── ...             ← each Dto has ToDomain() and FromDomain() methods

The test infrastructure serializes via DTO; the parser produces pure AST. Error messages can be wrapped to reference domain types and discriminators instead of JSON property names.

Acceptance criteria — Decision phase (do this first)

  • Run the existing TDD loop end-to-end on a sample hand-parsed card with an intentionally-introduced schema gap (e.g., add an unknown \"kind\" discriminator or an unmapped field).
  • Capture the actual error message produced.
  • Document the decision in the PR description or as a comment on this issue: either (a) good enough — close as wontfix, or (b) introduce DTO layer.

Acceptance criteria — If proceeding (path b)

  • All AST records under libs/magic-ast/AST/ contain zero [Json*] attributes (including per-property ones).
  • A parallel DTO hierarchy under libs/magic-ast/Serialization/Dto/ (or similar) carries the JSON attributes.
  • Each DTO has ToDomain() and FromDomain(domain) methods (or equivalent mapping). No reflection required for mapping unless it's clearly the right call.
  • Test infrastructure uses the DTO for round-trip serialization; parser output is compared as pure-domain AST.
  • Error messages on schema gap reference domain vocabulary (e.g., "unknown ability kind: 'delayed-trigger'") rather than JSON-internal vocabulary.
  • Full ratchet test suite remains green or improves — no regressions in test-baseline.json.

Blocked by

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-humanRequires human implementation or HITL checkpointsscope:magic-astAffects libs/magic-ast/type:refactorRefactor — no behavior change expected

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions