Skip to content

Commit 0ef567c

Browse files
authored
Merge pull request #12 from MobileReality/feat/error-messages-parser
Feat/error messages parser
2 parents da2406c + 52dec1b commit 0ef567c

28 files changed

Lines changed: 1809 additions & 627 deletions

README.md

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ function App({ ast, store }) {
229229
| `@mobile-reality/mdma-attachables-core` | Handlers for 7 of the 9 component types — the ones that manage state (form, button, tasklist, table, callout, approval-gate, webhook). Chart and thinking are display-only and rendered directly without state handlers. |
230230
| `@mobile-reality/mdma-renderer-react` | React rendering layer with components for all 9 MDMA types and hooks for state access. Provides `MdmaDocument` for full-document rendering and `useComponentState`/`useBinding` for fine-grained reactivity. |
231231
| `@mobile-reality/mdma-prompt-pack` | System prompts that teach LLMs how to author valid MDMA documents. Exports `buildSystemPrompt()` to combine the full spec reference with optional custom instructions for domain-specific generation. |
232-
| `@mobile-reality/mdma-validator` | Static analysis engine with 10 lint rules covering YAML correctness, schema conformance, ID uniqueness, binding resolution, and PII sensitivity. Powers programmatic validation in CI pipelines and custom tooling. |
232+
| `@mobile-reality/mdma-validator` | Static analysis engine with 17 lint rules covering YAML correctness, schema conformance, ID uniqueness, binding syntax, action references, PII sensitivity, expected component verification, and flow ordering. Includes 6 auto-fix strategies and fuzzy type/ID suggestions. Powers programmatic validation in CI pipelines and custom tooling. |
233233
| `@mobile-reality/mdma-cli` | Interactive CLI tool for creating custom MDMA prompts. Opens a local web app where you visually select components, configure fields, set domain rules and trigger conditions, then an LLM generates a tailored `customPrompt` for use with `buildSystemPrompt()`. Also includes a `validate` command for static document analysis. |
234234
| `@mobile-reality/mdma-mcp` | MCP (Model Context Protocol) server that exposes MDMA spec, prompts, and tooling to AI assistants. Tools: `get-spec`, `get-prompt`, `build-system-prompt`, `validate-prompt`, `list-packages`. Works with Claude Desktop, VS Code, Cursor, and any MCP-compatible client. |
235235
| `@mobile-reality/mdma-evals` | LLM evaluation suite built on promptfoo with 4 test suites: base generation quality (25 tests), custom prompt compliance (10 tests), multi-turn conversation handling (11 conversations, 25 turns), and prompt builder verification (25 tests). Validates that AI-generated MDMA documents are structurally correct and semantically appropriate. |
@@ -286,6 +286,98 @@ const systemPrompt = buildSystemPrompt({
286286
});
287287
```
288288

289+
## Validator
290+
291+
Static analysis engine for MDMA documents. Validates structure, catches common LLM mistakes, and auto-fixes what it can.
292+
293+
```typescript
294+
import { validate } from '@mobile-reality/mdma-validator';
295+
296+
const result = validate(markdown);
297+
// result.ok — true if no unfixed errors
298+
// result.issues — all issues found
299+
// result.output — auto-fixed markdown
300+
// result.fixCount — number of issues auto-fixed
301+
```
302+
303+
### Rules
304+
305+
Every rule can be individually disabled via the `exclude` option:
306+
307+
```typescript
308+
const result = validate(markdown, {
309+
exclude: ['thinking-block', 'placeholder-content'],
310+
});
311+
```
312+
313+
| Rule | Severity | Auto-fix | Description |
314+
|------|----------|----------|-------------|
315+
| `yaml-correctness` | error | -- | YAML parses successfully. Detects and auto-splits multi-component blocks, strips `---` separators LLMs insert. |
316+
| `field-name-typos` | warning | -- | Common field name mistakes: `roles` -> `allowedRoles`, `onClick` -> `onAction`, `submit` -> `onSubmit`. |
317+
| `schema-conformance` | error | yes | Component type exists and data conforms to its Zod schema. Suggests closest type via fuzzy matching (e.g. `"frm"` -> `did you mean "form"?`) and lists all valid types. |
318+
| `duplicate-ids` | error | yes | All component IDs are unique. Auto-fix appends `-1`, `-2` suffixes. |
319+
| `id-format` | warning | yes | IDs follow kebab-case (`my-component-id`). Auto-fix converts camelCase, snake_case, PascalCase and updates all references. |
320+
| `binding-syntax` | error/warning | yes | `{{binding}}` expressions are well-formed. Catches empty `{{ }}`, extra whitespace `{{ path }}`, and single-brace `{path}`. |
321+
| `action-references` | warning | yes | `onSubmit`, `onAction`, `onComplete`, `onApprove`, `onDeny`, `trigger` reference existing component IDs. Suggests near-matches for typos. |
322+
| `sensitive-flags` | warning | yes | Form fields and table columns with PII-like names (email, phone, ssn, address, etc.) have `sensitive: true`. Supports custom PII patterns. |
323+
| `required-markers` | info | -- | Suggests `required: true` for fields named `name`, `email`, `title`, `summary`. |
324+
| `thinking-block` | warning/info | -- | If a thinking block is present, it should be the first component and only one should exist. |
325+
| `table-data-keys` | warning | -- | Data row keys match defined column keys. Flags extra keys and columns with no matching data. |
326+
| `select-options` | warning | -- | `type: select` fields have `options` defined as `[{label, value}]` objects. |
327+
| `chart-validation` | warning | -- | Chart CSV data has headers + data rows. `xAxis`/`yAxis` reference actual CSV column headers. |
328+
| `placeholder-content` | info | -- | Catches `TODO`, `TBD`, `FIXME`, `...`, `lorem ipsum` in content fields. |
329+
| `flow-ordering` | error/info | -- | Forward-only action references, no circular refs, one interactive component type per message. Detects regenerated components from prior conversation turns. |
330+
| `expected-components` | error | -- | Verifies that components present in the message match their expected types, form fields, and table columns. Components not in the message are silently skipped — useful for multi-turn flows where you pass all expected components upfront. |
331+
332+
### Auto-fix Pipeline
333+
334+
When `autoFix: true` (default), 6 fix strategies run in strict dependency order:
335+
336+
1. **id-format** — normalize IDs to kebab-case, update all cross-references
337+
2. **duplicate-ids** — deduplicate after normalization
338+
3. **binding-syntax** — fix `{x}` -> `{{x}}`, strip whitespace
339+
4. **sensitive-flags** — add `sensitive: true` to PII fields
340+
5. **action-references** — remove invalid references
341+
6. **schema-conformance** — patch missing labels/headers/content, infer field types, wrap bare bindings, re-validate with Zod
342+
343+
### Expected Components
344+
345+
When you need to guarantee that the LLM generates specific critical components for the user (e.g. a form with required fields, a table with specific columns), pass their expected shapes to the validator. The rule only validates components that are actually present in the current message — components not found are silently skipped. This makes it safe to pass the full set of expected components across a multi-turn flow:
346+
347+
```typescript
348+
// Define all expected components once (e.g. from a blueprint or flow definition)
349+
const expectedComponents = {
350+
'contact-form': {
351+
type: 'form',
352+
fields: ['email', 'phone', 'full-name'],
353+
},
354+
'approval-gate': { type: 'approval-gate' },
355+
'submit-btn': { type: 'button' },
356+
};
357+
358+
// Pass the same set to every message — the rule checks only what's present
359+
const result = validate(message1, { expectedComponents });
360+
// Message 1 contains contact-form → validates type + fields
361+
// approval-gate and submit-btn not in this message → skipped
362+
363+
const result2 = validate(message2, { expectedComponents });
364+
// Message 2 contains approval-gate → validates type
365+
// contact-form and submit-btn not in this message → skipped
366+
```
367+
368+
For each component found in the message, the rule checks:
369+
- Is the type correct?
370+
- Are all expected form fields present? (lists available fields on mismatch)
371+
- Are all expected table columns present? (lists available columns on mismatch)
372+
373+
### LLM Error Recovery
374+
375+
The parser handles three common LLM mistakes automatically during block extraction:
376+
377+
- **Colon-space in values**`label: Step 1: Enter info` auto-quoted to `label: "Step 1: Enter info"`
378+
- **YAML `---` separators** — stripped before parsing
379+
- **Multiple components in one block** — split at each root-level `type:` line into separate blocks
380+
289381
## MCP Server
290382

291383
MCP (Model Context Protocol) server that lets AI assistants understand and work with MDMA.
@@ -413,7 +505,7 @@ pnpm eval:view
413505
- [x] Improved validator
414506
- [x] Added MCP
415507
- [x] Added Skills for Agentic usage
416-
- [ ] Improved error messages in parser
508+
- [x] Improved error messages in parser
417509
- [ ] File upload field type for forms
418510

419511
### v0.3 — AI & Generation

0 commit comments

Comments
 (0)