Skip to content

Plugin-host parse-fidelity API + semantic validation tier #202

@fuzzzerd

Description

@fuzzzerd

Context

Branch `fuzzz/clip-aggregate` ships an XML→domain parse-fidelity pipeline:

  • `Clip` aggregate (`src/SharpFM.Model/Clip.cs`) — immutable, lazy-parsed.
  • `IClipTypeStrategy` registry (`src/SharpFM.Model/ClipTypes/`) — compile-time `BuiltIns` array, no extension point.
  • `ClipParseResult` / `ClipParseReport` / `ClipParseDiagnostic` (`src/SharpFM.Model/Parsing/`) — every parse produces a structured report.
  • `XmlRoundTripDiff` substrate detects unmodeled elements/attributes by parse → re-serialize → structural diff.
  • Status-bar + tree-glyph surfaces in the host (`MainWindowViewModel` / `MainWindow.axaml`).
  • `Clip.FromEditor` trusted-edit path — editor edits skip the strategy parse + diff entirely (model is the source of truth).

What did not land in that branch — captured here as follow-up work:

Items

  • Carry `ClipParseReport` on `ClipData`. Today plugins re-parse the XML on every `AsScript()` / `AsTable()` call (`src/SharpFM.Model/ClipDataExtensions.cs`). Extending the record to carry the report is non-breaking (record types accept new properties) and would let plugin authors read fidelity diagnostics without re-parsing. Update `PluginHost` (`src/SharpFM/Services/PluginHost.cs`) to populate the new field from `Clip.Parsed.Report` whenever it constructs a `ClipData` snapshot.

  • `IPluginHost.ValidateClipXml(string xml, string clipType) → ClipParseReport` — pure pre-flight validator API for plugin authors. Implementation routes through `ClipTypeRegistry.For(clipType).Parse(xml).Report`. Lets plugins inspect lossiness before pushing XML through `UpdateClipXml` / `UpdateSelectedClipXml`. No mutation, no side effects.

  • Semantic-validation tier. The current diff catches structural round-trip loss (unmodeled attributes/elements). It does not catch semantic violations like:

    • FileMaker variable names must start with `$` and contain no whitespace/colons (concrete prior bug: PR fix: positional step params no longer carry the label prefix into XML #201 — `FmScript.SynthesizeHrParams` produced `Name: $i`, structurally valid but broken at FileMaker runtime).
    • `Calculation` syntax is opaque text today. A grammar parser exists for autocomplete (`src/SharpFM.Model/Scripting/Calc/FmCalcGrammarBuilder.cs`) but does not validate.
    • Step-param value constraints (some enum-restricted values are checked only via the display-text validator at `src/SharpFM.Model/Scripting/ScriptValidator.cs`).

    Design space: a parallel validator that runs over the parsed `ClipModel` and emits new `ParseDiagnosticKind` values (or its own diagnostic enum). Should not be conflated with `XmlRoundTripDiff` — that's structural; semantic rules are domain-aware.

  • `Clip.Rename` — currently no production caller; kept on the aggregate for symmetry with `WithXml`. Either wire it to a rename UI command or delete (`src/SharpFM.Model/Clip.cs`).

Pointers for picking up

  • Predecessor branch: `fuzzz/clip-aggregate` (head `29637c2`, base `e5009d4` which is the master-side fix shipped as PR fix: positional step params no longer carry the label prefix into XML #201).
  • The host's existing parse-report consumers are `MainWindowViewModel.ParseFidelitySummary` and the tree binding to `Clip.IsLossless` — those readers already exercise the lazy parse path on the active clip, useful as a sanity check that a plugin-side reader does the same.
  • `ClipParseReport.IsLossless` and `ClipParseDiagnostic` are public on `SharpFM.Model.Parsing`; the plugin contract `SharpFM.Plugin` does not yet reference them — this issue is the bridge.

Out of scope

  • Any mention of specific plugin consumers, plugin-author tooling, or plugin runtime concerns — those belong in the consuming plugin's own repo.
  • Reflection-based clip-type registration. Strategies are SharpFM-owned and statically defined (`ClipTypeRegistry.BuiltIns`).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions