agentic-mermaid 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENT_NATIVE.md +155 -91
- package/CHANGELOG.md +163 -4
- package/Instructions_for_agents.md +10 -10
- package/LICENSES/Apache-2.0.txt +202 -0
- package/README.md +31 -38
- package/THIRD_PARTY_NOTICES.md +29 -0
- package/assets/hero.png +0 -0
- package/dist/agent-core.d.ts +463 -0
- package/dist/agent-core.js +397 -0
- package/dist/agent.d.ts +73 -1868
- package/dist/agent.js +336 -37325
- package/dist/agentic-mermaid-mcp.js +7 -38399
- package/dist/am.js +33626 -40446
- package/dist/chunk-2P5FKUQC.js +3485 -0
- package/dist/chunk-2S3VSS6I.js +149 -0
- package/dist/chunk-2SILJDW2.js +37 -0
- package/dist/chunk-BJYMBT4I.js +61963 -0
- package/dist/chunk-FDM43XU7.js +615 -0
- package/dist/chunk-MYPDVZCO.js +4702 -0
- package/dist/index-DWPa2MJs.d.ts +6780 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +310 -33014
- package/dist/mcp-cli-5J47WEY3.js +17 -0
- package/docs/README.md +39 -31
- package/docs/agent-api-cookbook.md +44 -35
- package/docs/agent-mutation-policy.md +1 -1
- package/docs/agent-workflow-examples.md +2 -2
- package/docs/api.md +284 -77
- package/docs/ascii.md +26 -16
- package/docs/code-mode-impact.md +214 -0
- package/docs/comparison.md +23 -11
- package/docs/computational-aesthetics-prototype-plan.md +252 -0
- package/docs/config.md +26 -10
- package/docs/custom-fonts.md +265 -0
- package/docs/custom-style-cookbook.md +130 -9
- package/docs/diagram-families.md +48 -23
- package/docs/features.md +59 -52
- package/docs/fork-differences.md +6 -3
- package/docs/getting-started.md +23 -16
- package/docs/issue-derived-test-cases.md +29 -22
- package/docs/mcp-code-mode-rationale.md +13 -6
- package/docs/mcp-http-transport.md +20 -13
- package/docs/mermaid-layout-complaints.md +66 -52
- package/docs/mutation-testing.md +145 -66
- package/docs/quality.md +23 -14
- package/docs/react.md +2 -2
- package/docs/schemas/style-spec.schema.json +1221 -30
- package/docs/style-authoring.md +241 -38
- package/docs/svg-semantic-contract.md +49 -0
- package/docs/testing-strategy.md +166 -58
- package/docs/theming.md +19 -32
- package/examples/styles/catalog.json +54 -0
- package/examples/styles/cloudflare-workers-inspired-prototype.mmd +9 -0
- package/examples/styles/cloudflare-workers-inspired-prototype.style.json +110 -0
- package/examples/styles/cupertino-prototype.mmd +10 -0
- package/examples/styles/cupertino-prototype.style.json +63 -0
- package/examples/styles/mid-century-report.style.json +2 -2
- package/examples/styles/star-chart-atlas.style.json +2 -1
- package/examples/styles/transit-route-map.style.json +2 -2
- package/examples/styles/vercel-inspired-prototype.mmd +6 -0
- package/examples/styles/vercel-inspired-prototype.style.json +87 -0
- package/package.json +85 -45
- package/server.json +2 -2
- package/skills/agentic-mermaid-diagram-workflow/SKILL.md +17 -36
- package/skills/agentic-mermaid-diagram-workflow/references/cli.md +4 -5
- package/skills/agentic-mermaid-diagram-workflow/references/code-mode.md +15 -31
- package/skills/agentic-mermaid-diagram-workflow/references/sequence.md +10 -14
- package/skills/agentic-mermaid-live-editor/SKILL.md +100 -206
- package/TODO.md +0 -684
- package/dist/index-wjRjbsP-.d.ts +0 -1102
- package/docs/assets/improvements/box-start-connector.png +0 -0
- package/docs/assets/improvements/comment-dropped-lint.png +0 -0
- package/docs/assets/improvements/er-content-loss.png +0 -0
- package/docs/assets/improvements/fan-in-trunks.png +0 -0
- package/docs/assets/improvements/gantt-family.png +0 -0
- package/docs/assets/improvements/gantt-milestone-clamp.png +0 -0
- package/docs/assets/improvements/gantt-verify-seam.png +0 -0
- package/docs/assets/improvements/subgraph-container-edges.png +0 -0
- package/docs/assets/improvements/wrapper-frontmatter.png +0 -0
- package/docs/assets/improvements/wrapper-init-directive.png +0 -0
- package/docs/assets/improvements/wrapper-leading-comment.png +0 -0
- package/docs/assets/style-cookbook/mid-century-report.png +0 -0
- package/docs/assets/style-cookbook/star-chart-atlas.png +0 -0
- package/docs/assets/style-cookbook/transit-route-map.png +0 -0
- package/docs/contributing/adding-diagram-types.md +0 -144
- package/docs/contributing/diagram-family-citizenship.matrix.json +0 -2127
- package/docs/contributing/diagram-family-citizenship.md +0 -82
- package/docs/contributing/harvesting-upstream-tests.md +0 -126
- package/docs/contributing/lessons-learned.md +0 -276
- package/docs/contributing/releasing.md +0 -82
- package/docs/contributing/visual-review-evidence.md +0 -53
- package/docs/design/families/README.md +0 -26
- package/docs/design/families/architecture-beta.md +0 -48
- package/docs/design/families/flowchart-parser-conformance.md +0 -22
- package/docs/design/families/gantt-research.md +0 -137
- package/docs/design/families/gantt.md +0 -329
- package/docs/design/families/journey-agentic-cards-before.png +0 -0
- package/docs/design/families/journey-experience-curve-implementation.png +0 -0
- package/docs/design/families/journey-mermaid-classic-implementation.png +0 -0
- package/docs/design/families/journey-mermaid-classic-prototype.png +0 -0
- package/docs/design/families/journey-mermaid-classic-prototype.svg +0 -163
- package/docs/design/families/journey-mermaid-classic-prototype.svg.png +0 -0
- package/docs/design/families/journey-migration-parity.md +0 -439
- package/docs/design/families/journey-section-overlap-after.png +0 -0
- package/docs/design/families/journey-section-overlap-before.png +0 -0
- package/docs/design/families/journey-usage-research.md +0 -423
- package/docs/design/families/journey.md +0 -153
- package/docs/design/families/xychart.md +0 -85
- package/docs/design/system/README.md +0 -45
- package/docs/design/system/abstraction-audit.md +0 -224
- package/docs/design/system/abstraction-recommendations.md +0 -655
- package/docs/design/system/architecture.mmd +0 -29
- package/docs/design/system/architecture.svg +0 -137
- package/docs/design/system/layout-guarantees-and-robustness.md +0 -351
- package/docs/design/system/layout-rubric.md +0 -138
- package/docs/design/system/route-contracts.md +0 -848
- package/docs/design/system/source-preservation-ladder.md +0 -52
- package/docs/design/system/styles-rollout.md +0 -216
- package/docs/design/system/ugly-layouts.md +0 -119
- package/docs/layout-characterization/README.md +0 -245
- package/docs/layout-characterization/contact-sheet-families.md +0 -498
- package/docs/layout-characterization/contact-sheet.md +0 -638
- package/docs/layout-characterization/properties.md +0 -281
- package/docs/layout-characterization/visual-quality.md +0 -160
- package/docs/layout-characterization/visual-snapshots/architecture.svg +0 -79
- package/docs/layout-characterization/visual-snapshots/class.svg +0 -60
- package/docs/layout-characterization/visual-snapshots/er.svg +0 -61
- package/docs/layout-characterization/visual-snapshots/flowchart.svg +0 -58
- package/docs/layout-characterization/visual-snapshots/gantt.svg +0 -52
- package/docs/layout-characterization/visual-snapshots/journey.svg +0 -98
- package/docs/layout-characterization/visual-snapshots/pie.svg +0 -36
- package/docs/layout-characterization/visual-snapshots/quadrant.svg +0 -47
- package/docs/layout-characterization/visual-snapshots/sequence.svg +0 -59
- package/docs/layout-characterization/visual-snapshots/state.svg +0 -52
- package/docs/layout-characterization/visual-snapshots/timeline.svg +0 -64
- package/docs/layout-characterization/visual-snapshots/xychart.svg +0 -97
- package/docs/project/divergences.md +0 -98
- package/docs/project/dogfooding-docs-strategy.md +0 -66
- package/docs/project/hosted-mcp-cloudflare-plan.md +0 -338
- package/docs/project/lessons-learned.md +0 -1019
- package/docs/project/remove-role-styling-plan.md +0 -176
- package/examples/agent-improve-auth-flow.ts +0 -206
- package/examples/agent-loop.ts +0 -53
- package/examples/mcp-vs-cli-complex-diagrams.ts +0 -133
- package/llms.txt +0 -104
- package/skill-evals/README.md +0 -77
- package/skill-evals/fixtures/architecture-cache/input.mmd +0 -5
- package/skill-evals/fixtures/class-payment/input.mmd +0 -4
- package/skill-evals/fixtures/er-orders/input.mmd +0 -10
- package/skill-evals/fixtures/flowchart-cache/input.mmd +0 -3
- package/skill-evals/fixtures/gantt-release/input.mmd +0 -7
- package/skill-evals/fixtures/journey-checkout/input.mmd +0 -6
- package/skill-evals/fixtures/pie-exports/input.mmd +0 -5
- package/skill-evals/fixtures/quadrant-priorities/input.mmd +0 -11
- package/skill-evals/fixtures/sequence-retry/input.mmd +0 -8
- package/skill-evals/fixtures/state-lifecycle/input.mmd +0 -5
- package/skill-evals/fixtures/timeline-release/input.mmd +0 -6
- package/skill-evals/fixtures/xychart-growth/input.mmd +0 -5
- package/skill-evals/shared-benchmark.json +0 -510
- package/src/agent/analyze.ts +0 -157
- package/src/agent/apply.ts +0 -146
- package/src/agent/architecture-body.ts +0 -458
- package/src/agent/certificates.ts +0 -110
- package/src/agent/class-body.ts +0 -319
- package/src/agent/core.ts +0 -207
- package/src/agent/create.ts +0 -106
- package/src/agent/describe.ts +0 -368
- package/src/agent/er-body.ts +0 -224
- package/src/agent/facts.ts +0 -360
- package/src/agent/families-builtin.ts +0 -920
- package/src/agent/families.ts +0 -232
- package/src/agent/family-layouts.ts +0 -832
- package/src/agent/flowchart-body.ts +0 -372
- package/src/agent/flowchart-unsupported.ts +0 -243
- package/src/agent/font-coverage.ts +0 -288
- package/src/agent/gantt-body.ts +0 -495
- package/src/agent/index.ts +0 -10
- package/src/agent/journey-body.ts +0 -374
- package/src/agent/label-metrics.ts +0 -28
- package/src/agent/layout-to-rendered.ts +0 -63
- package/src/agent/mutate.ts +0 -97
- package/src/agent/mutation-ops.ts +0 -51
- package/src/agent/op-schema.ts +0 -443
- package/src/agent/parse.ts +0 -223
- package/src/agent/pie-body.ts +0 -270
- package/src/agent/png.ts +0 -171
- package/src/agent/quadrant-body.ts +0 -336
- package/src/agent/quality.ts +0 -363
- package/src/agent/readability-audit.ts +0 -92
- package/src/agent/rendered-route-audit.ts +0 -61
- package/src/agent/sequence-body.ts +0 -345
- package/src/agent/serialize.ts +0 -214
- package/src/agent/state-body.ts +0 -589
- package/src/agent/structural-count.ts +0 -150
- package/src/agent/timeline-body.ts +0 -280
- package/src/agent/trace-log.ts +0 -43
- package/src/agent/types.ts +0 -995
- package/src/agent/verify.ts +0 -603
- package/src/agent/xychart-body.ts +0 -472
- package/src/architecture/config.ts +0 -282
- package/src/architecture/layout.ts +0 -496
- package/src/architecture/parser.ts +0 -375
- package/src/architecture/renderer.ts +0 -611
- package/src/architecture/types.ts +0 -113
- package/src/ascii/ansi.ts +0 -423
- package/src/ascii/architecture.ts +0 -210
- package/src/ascii/canvas.ts +0 -443
- package/src/ascii/class-diagram.ts +0 -697
- package/src/ascii/converter.ts +0 -475
- package/src/ascii/draw.ts +0 -1693
- package/src/ascii/edge-bundling.ts +0 -328
- package/src/ascii/edge-routing.ts +0 -330
- package/src/ascii/er-diagram.ts +0 -439
- package/src/ascii/gantt.ts +0 -276
- package/src/ascii/grid.ts +0 -747
- package/src/ascii/index.ts +0 -196
- package/src/ascii/journey.ts +0 -169
- package/src/ascii/meta.ts +0 -244
- package/src/ascii/multiline-utils.ts +0 -80
- package/src/ascii/pathfinder.ts +0 -301
- package/src/ascii/pie.ts +0 -67
- package/src/ascii/quadrant.ts +0 -158
- package/src/ascii/reverse.ts +0 -216
- package/src/ascii/sequence.ts +0 -499
- package/src/ascii/shapes/circle.ts +0 -27
- package/src/ascii/shapes/corners.ts +0 -143
- package/src/ascii/shapes/diamond.ts +0 -27
- package/src/ascii/shapes/hexagon.ts +0 -27
- package/src/ascii/shapes/index.ts +0 -106
- package/src/ascii/shapes/rectangle.ts +0 -168
- package/src/ascii/shapes/rounded.ts +0 -27
- package/src/ascii/shapes/special.ts +0 -332
- package/src/ascii/shapes/stadium.ts +0 -110
- package/src/ascii/shapes/state.ts +0 -192
- package/src/ascii/shapes/types.ts +0 -73
- package/src/ascii/timeline.ts +0 -141
- package/src/ascii/types.ts +0 -312
- package/src/ascii/validate.ts +0 -120
- package/src/ascii/width.ts +0 -81
- package/src/ascii/wrap.ts +0 -131
- package/src/ascii/xychart.ts +0 -919
- package/src/browser.ts +0 -29
- package/src/class/layout.ts +0 -240
- package/src/class/parser.ts +0 -332
- package/src/class/renderer.ts +0 -638
- package/src/class/types.ts +0 -129
- package/src/cli/agent-instructions.ts +0 -1
- package/src/cli/am-bin.ts +0 -6
- package/src/cli/exit-codes.ts +0 -18
- package/src/cli/index.ts +0 -1132
- package/src/cli/init-agent.ts +0 -147
- package/src/cli/run-entrypoint.ts +0 -10
- package/src/color-resolver.ts +0 -152
- package/src/elk-instance.ts +0 -114
- package/src/er/layout.ts +0 -187
- package/src/er/parser.ts +0 -226
- package/src/er/renderer.ts +0 -792
- package/src/er/types.ts +0 -99
- package/src/family-rubric.ts +0 -425
- package/src/font-manifest.ts +0 -31
- package/src/gantt/layout.ts +0 -365
- package/src/gantt/parser.ts +0 -282
- package/src/gantt/pipeline.ts +0 -27
- package/src/gantt/renderer.ts +0 -414
- package/src/gantt/schedule.ts +0 -513
- package/src/gantt/types.ts +0 -255
- package/src/index.ts +0 -368
- package/src/journey/layout.ts +0 -554
- package/src/journey/parse-core.ts +0 -251
- package/src/journey/parser.ts +0 -101
- package/src/journey/renderer.ts +0 -917
- package/src/journey/types.ts +0 -144
- package/src/layout/geometry.ts +0 -182
- package/src/layout/pass.ts +0 -142
- package/src/layout/passes/index.ts +0 -3916
- package/src/layout-engine.ts +0 -1565
- package/src/layout-rubric.ts +0 -659
- package/src/mcp/artifacts.ts +0 -137
- package/src/mcp/dynamic-harness.ts +0 -31
- package/src/mcp/dynamic-modules.d.ts +0 -7
- package/src/mcp/facade.ts +0 -608
- package/src/mcp/harness-runtime.ts +0 -203
- package/src/mcp/hosted-server.ts +0 -468
- package/src/mcp/mcp-bin.ts +0 -3
- package/src/mcp/mcp-cli.ts +0 -82
- package/src/mcp/protocol.ts +0 -13
- package/src/mcp/sandbox.ts +0 -195
- package/src/mcp/sdk-decl.ts +0 -391
- package/src/mcp/server.ts +0 -362
- package/src/mcp/tool-surface.ts +0 -146
- package/src/mermaid-source.ts +0 -655
- package/src/multiline-utils.ts +0 -228
- package/src/parser.ts +0 -1031
- package/src/pie/layout.ts +0 -168
- package/src/pie/parser.ts +0 -136
- package/src/pie/renderer.ts +0 -234
- package/src/pie/types.ts +0 -82
- package/src/quadrant/layout.ts +0 -191
- package/src/quadrant/parser.ts +0 -183
- package/src/quadrant/renderer.ts +0 -322
- package/src/quadrant/types.ts +0 -113
- package/src/render-family-hooks.ts +0 -244
- package/src/renderer.ts +0 -1099
- package/src/route-contracts.ts +0 -2723
- package/src/scene/backend.ts +0 -76
- package/src/scene/fidelity.ts +0 -183
- package/src/scene/hybrid-backend.ts +0 -174
- package/src/scene/ir.ts +0 -181
- package/src/scene/marks.ts +0 -127
- package/src/scene/rough-backend.ts +0 -378
- package/src/scene/seed.ts +0 -46
- package/src/scene/style-registry.ts +0 -556
- package/src/sequence/layout.ts +0 -456
- package/src/sequence/parser.ts +0 -255
- package/src/sequence/renderer.ts +0 -604
- package/src/sequence/types.ts +0 -154
- package/src/shape-clipping.ts +0 -351
- package/src/shared/accessibility-directives.ts +0 -22
- package/src/shared/batched.ts +0 -61
- package/src/shared/color-math.ts +0 -93
- package/src/shared/svg-a11y.ts +0 -29
- package/src/shared/syntax-error.ts +0 -17
- package/src/shared/unicode-ranges.ts +0 -135
- package/src/styles.ts +0 -318
- package/src/svg-paths.ts +0 -28
- package/src/text-metrics.ts +0 -248
- package/src/theme.ts +0 -710
- package/src/timeline/layout.ts +0 -381
- package/src/timeline/parser.ts +0 -215
- package/src/timeline/renderer.ts +0 -538
- package/src/timeline/types.ts +0 -105
- package/src/types.ts +0 -462
- package/src/website-worker-modules.d.ts +0 -18
- package/src/xychart/axis-utils.ts +0 -109
- package/src/xychart/colors.ts +0 -124
- package/src/xychart/config.ts +0 -88
- package/src/xychart/layout.ts +0 -656
- package/src/xychart/parser.ts +0 -504
- package/src/xychart/renderer.ts +0 -640
- package/src/xychart/types.ts +0 -282
package/AGENT_NATIVE.md
CHANGED
|
@@ -26,7 +26,7 @@ D2 has a better language than Mermaid. The Beautiful Mermaid renderer foundation
|
|
|
26
26
|
|
|
27
27
|
1. **Deterministic layout** — same input → structurally identical layout JSON across runs with the same ELK version. (Not "byte-identical SVG across versions" — that's a stronger claim that needs a forked ELK to actually deliver.)
|
|
28
28
|
2. **Verifiable rendering** — structured "did this render cleanly?" check. Structural warnings (anchors, bounds, emptiness, group containment) are reliable; metric warnings (label fit, overlap) are best-effort because they depend on font-measurement parity with ELK.
|
|
29
|
-
3. **Round-trippable** — `
|
|
29
|
+
3. **Round-trippable** — `parseRegisteredMermaid` produces a `ValidDiagram` that carries source needed to re-emit the diagram. For flowchart/state, sequence, timeline, class, ER, journey, architecture, xychart, pie, quadrant, gantt, mindmap, gitgraph, and radar, `mutate` operates on structured bodies; for opaque-fallback bodies, preserved source is the round-trip mechanism.
|
|
30
30
|
|
|
31
31
|
(Composition — `@include`, templates, layered scenarios — was the fourth in earlier drafts and is deferred. Agents do not currently reach for composition; they paste and edit. Add when evidence demands.)
|
|
32
32
|
|
|
@@ -34,24 +34,9 @@ D2 has a better language than Mermaid. The Beautiful Mermaid renderer foundation
|
|
|
34
34
|
|
|
35
35
|
## Honest scope
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
The checked family roster, capability states, edit policies, narrowers, and mutation operations are generated from `FamilyDescriptor`: read [`docs/project/section-a-capability-report.md`](./docs/project/section-a-capability-report.md) or `am capabilities --json`, and use `describeOps(family)` for exact operation schemas. This rationale deliberately does not copy that live inventory.
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|---|---|---|
|
|
41
|
-
| Flowchart | Full | ✅ 6 ops |
|
|
42
|
-
| State | Structured round-trip for the modeled subset (simple states/transitions/`[*]`/composites/direction); `<<fork>>`/`<<choice>>`/notes/`--`/`classDef` fall back to opaque losslessly | 8 ops via `asState` (BUILD-19) |
|
|
43
|
-
| Sequence | Structured-with-segments (BUILD-18): participant/message ops stay live while Note/alt/loop/par/activate/autonumber/title ride along verbatim as opaque-block segments; only un-segmentable input (unbalanced `end`) falls back to whole-body opaque | ✅ 5 ops when structured |
|
|
44
|
-
| Timeline | Full | ✅ 10 ops |
|
|
45
|
-
| Class | Full | ✅ 10 ops |
|
|
46
|
-
| ER | Full | ✅ 7 ops |
|
|
47
|
-
| Journey | Full structured round-trip (title/sections/tasks) | 10 ops via `asJourney` (BUILD-15 pilot) |
|
|
48
|
-
| Architecture | Structured round-trip for the modeled subset (groups/services/junctions/edges); `{group}` boundary edges + accTitle/accDescr fall back to opaque losslessly | 10 ops via `asArchitecture` (BUILD-17) |
|
|
49
|
-
| XY chart | Structured round-trip for the modeled subset (title/axes/series); quoted text, `;` lines, accTitle/accDescr fall back to opaque losslessly | 8 ops via `asXyChart` (BUILD-16) |
|
|
50
|
-
| Pie | Structured round-trip (title/showData/slices); accTitle/accDescr + malformed entries fall back to opaque losslessly | 7 ops via `asPie` |
|
|
51
|
-
| Quadrant | Structured round-trip (title/axes/quadrant labels/points); styling + out-of-range coords fall back to opaque losslessly | 7 ops via `asQuadrant` |
|
|
52
|
-
| Gantt | Structured-with-segments from day one ([`docs/design/families/gantt.md`](./docs/design/families/gantt.md)): title/section/task ops stay live while calendar directives, click lines, and comments ride along verbatim as opaque-block segments; duplicate task ids / unclosed accDescr fall back to whole-body opaque losslessly. Rendering is deterministic — the today marker needs a caller-supplied clock (`ganttToday`), never the wall clock | 9 ops via `asGantt` |
|
|
53
|
-
|
|
54
|
-
The implication: for any opaque fallback, the agent's tool surface is *parse → verify → render → serialize*, not *parse → mutate → verify → serialize*. Cross-cutting edits on those bodies happen at the preserved source level (`body.source` for opaque bodies), not at the typed mutation layer. Code Mode opportunity #1 covers this for the cases where it matters.
|
|
39
|
+
The generated edit policy decides where typed mutation is available. For an opaque fallback, the agent's tool surface is *parse → verify → render → serialize*, not *parse → mutate → verify → serialize*. Cross-cutting edits on those bodies happen at the preserved source level (`body.source` for opaque bodies), not at the typed mutation layer. Code Mode opportunity #1 covers this for the cases where it matters.
|
|
55
40
|
|
|
56
41
|
---
|
|
57
42
|
|
|
@@ -128,6 +113,7 @@ Correctly detect what they claim to detect, but the occurrence may be intentiona
|
|
|
128
113
|
| `ROUTE_HITCH` | warning | An edge bends although a direct lane for it is provably clear (route-contract tripwire) |
|
|
129
114
|
| `ROUTE_UNEXPLAINED_BEND` | warning | An edge contains a diagonal segment under orthogonal routing (route-contract tripwire) |
|
|
130
115
|
| `ROUTE_LABEL_ON_SHARED_TRUNK` | warning | A label pill sits on a line segment another edge shares (route-contract tripwire) |
|
|
116
|
+
| `ROUTE_SELF_LOOP_OCCUPANCY` | warning | A self-loop certificate has invalid side/boundary geometry or collides with another loop/label |
|
|
131
117
|
| `ROUTE_CONTAINER_MISANCHOR` | warning | A container edge does not terminate on the container border (route-contract tripwire) |
|
|
132
118
|
| `ROUTE_SHAPE_MISANCHOR` | warning | An endpoint is off the rendered shape boundary (route-contract tripwire) |
|
|
133
119
|
| `ROUTE_STALE_AFTER_NODE_MOVE` | warning | An endpoint detached from its node entirely (route-contract tripwire) |
|
|
@@ -136,7 +122,7 @@ Codes are the contract surface agents reason about. Emitting an undocumented cod
|
|
|
136
122
|
|
|
137
123
|
### Tier 3 — Lint (advisory)
|
|
138
124
|
|
|
139
|
-
Tier 3 warnings are family-specific quality hints for "common LLM mistakes" that parse and render but are probably not what the agent intended.
|
|
125
|
+
Tier 3 warnings are family-specific quality hints for "common LLM mistakes" that parse and render but are probably not what the agent intended. Advisory lint never flips `verify.ok`; an explicitly authored Brand constraint with `action: "error"` emits `BRAND_CONSTRAINT_ERROR` and does flip it.
|
|
140
126
|
|
|
141
127
|
| Code | Severity | Description |
|
|
142
128
|
|---|---|---|
|
|
@@ -147,8 +133,11 @@ Tier 3 warnings are family-specific quality hints for "common LLM mistakes" that
|
|
|
147
133
|
| `UNSUPPORTED_SYNTAX` | warning | The source uses Mermaid syntax that is preserved losslessly but not fully modeled by local structured mutation/render semantics (for example flowchart edge IDs, edge metadata, click/href directives, or markdown strings). Payload includes `syntax`, optional `line`, and `message`. |
|
|
148
134
|
| `CONTENT_DROPPED_ON_ROUNDTRIP` | warning | The structured `{nodes, edges, groups}` tally changed across a parse → serialize → re-parse cycle, so canonical serialization is silently dropping or duplicating content even though the bytes may re-parse (payload carries `before`/`after` counts). The faithfulness analogue of `COMMENT_DROPPED` — "100% parse success is not faithfulness". Runs on every verify, for every family; opaque bodies (byte-verbatim) are exempt. |
|
|
149
135
|
| `INEFFECTIVE_CONFIG` | warning | A Mermaid config field was accepted (for config-shape compatibility) but has no effect on this family's geometry or paint — e.g. Journey's sequence-era fields (`boxMargin`, `rightAngles`, …). Payload names the `field`. Accepting-and-ignoring silently misleads migrating users; this lint says so. |
|
|
136
|
+
| `LOW_CONTRAST` | warning | A concrete authored paint remains authoritative but misses a measurable contrast threshold against the final resolved opaque background. Payload names the `field`, `foreground`, `background`, measured `ratio`, and required `minimum`; verification diagnoses without repainting authored intent. Transparent output is not measured because its host backdrop is unknown. |
|
|
137
|
+
| `BRAND_CONSTRAINT_WARNING` | warning | A caller-selected inspect-only `contrast`, `accent-area`, or `mono-role` Brand constraint failed or could not be measured. Payload reports the constraint, `measurement`, applicable role/mark, and concrete evidence without repainting or relayout. |
|
|
138
|
+
| `BRAND_CONSTRAINT_ERROR` | error | The same inspect-only Brand constraint contract with `action: "error"`; it preserves authored output but flips `verify.ok` so a caller can enforce its declared brand policy. |
|
|
150
139
|
|
|
151
|
-
`
|
|
140
|
+
`FamilyDescriptor.verify` hooks are wired and run today; built-ins use them for Tier 1 structural warnings for class/ER and the central flowchart verifier emits the initial Tier 3 lint catalogue. Future lint codes should be added deliberately to `WARNING_TIER`, documented here, and covered by doc-sync tests.
|
|
152
141
|
|
|
153
142
|
**Branded coordinate types** (`Finite`) prevent NaN / Infinity from reaching the renderer. `toFinite()` is the only constructor; it throws on invalid input.
|
|
154
143
|
|
|
@@ -183,44 +172,31 @@ type DiagramBody =
|
|
|
183
172
|
| { kind: 'flowchart'; graph: MermaidGraph }
|
|
184
173
|
| StateBody | SequenceBody | TimelineBody | ClassBody | ErBody
|
|
185
174
|
| JourneyBody | ArchitectureBody | XyChartBody | PieBody | QuadrantBody | GanttBody
|
|
175
|
+
| MindmapBody | GitGraphBody | RadarBody
|
|
186
176
|
| { kind: 'opaque'; family: DiagramKind; source: string }
|
|
187
177
|
|
|
188
|
-
type MutableValidDiagram =
|
|
189
|
-
| FlowchartValidDiagram | StateValidDiagram | SequenceValidDiagram
|
|
190
|
-
| TimelineValidDiagram | ClassValidDiagram | ErValidDiagram
|
|
191
|
-
| JourneyValidDiagram | ArchitectureValidDiagram | XyChartValidDiagram
|
|
192
|
-
| PieValidDiagram | QuadrantValidDiagram | GanttValidDiagram
|
|
178
|
+
type MutableValidDiagram = import('agentic-mermaid/agent').MutableValidDiagram
|
|
193
179
|
```
|
|
194
180
|
|
|
195
181
|
```ts
|
|
196
|
-
|
|
182
|
+
parseRegisteredMermaid(source: string): Result<ValidDiagram, ParseError[]>
|
|
197
183
|
serializeMermaid(d: ValidDiagram): string
|
|
198
184
|
synthesizeFromGraph(payload): Result<ValidDiagram, ParseError[]>
|
|
199
185
|
createMermaid(kind, opts?): MutableValidDiagram // empty structured diagram; overloads narrow per kind
|
|
200
186
|
buildMermaid(kind, ops, opts?): Result<MutableValidDiagram, MutationError & { opIndex: number }>
|
|
201
|
-
mutate(d
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
mutate(d: TimelineValidDiagram, op: TimelineMutationOp): Result<TimelineValidDiagram, MutationError>
|
|
205
|
-
mutate(d: ClassValidDiagram, op: ClassMutationOp): Result<ClassValidDiagram, MutationError>
|
|
206
|
-
mutate(d: ErValidDiagram, op: ErMutationOp): Result<ErValidDiagram, MutationError>
|
|
207
|
-
mutate(d: JourneyValidDiagram, op: JourneyMutationOp): Result<JourneyValidDiagram, MutationError>
|
|
208
|
-
mutate(d: ArchitectureValidDiagram, op: ArchitectureMutationOp): Result<ArchitectureValidDiagram, MutationError>
|
|
209
|
-
mutate(d: XyChartValidDiagram, op: XyChartMutationOp): Result<XyChartValidDiagram, MutationError>
|
|
210
|
-
mutate(d: PieValidDiagram, op: PieMutationOp): Result<PieValidDiagram, MutationError>
|
|
211
|
-
mutate(d: QuadrantValidDiagram, op: QuadrantMutationOp): Result<QuadrantValidDiagram, MutationError>
|
|
212
|
-
mutate(d: GanttValidDiagram, op: GanttMutationOp): Result<GanttValidDiagram, MutationError>
|
|
213
|
-
asFlowchart/asState/asSequence/asTimeline/asClass/asEr/asJourney/asArchitecture/asXyChart/asPie/asQuadrant/asGantt(d): narrowed diagram | null
|
|
187
|
+
mutate(d, op): Result<MutableValidDiagram, MutationError>
|
|
188
|
+
// Concrete overloads preserve the narrowed family. Overloads and narrowers are
|
|
189
|
+
// registry-derived; discover them with am capabilities --json and describeOps(family).
|
|
214
190
|
```
|
|
215
191
|
|
|
216
|
-
**`mutate` is overloaded by family.**
|
|
192
|
+
**`mutate` is overloaded by family.** A registry-declared narrower returns the family-specific mutable type or `null`; the generated capability entry and `describeOps(family)` own the live operation contract. Opaque-fallback diagrams are not typed for mutation, so agents get a compile-time/null-narrower stop rather than a lossy edit path.
|
|
217
193
|
|
|
218
194
|
Two contracts:
|
|
219
195
|
|
|
220
|
-
- `serializeMermaid(
|
|
221
|
-
- `
|
|
196
|
+
- `serializeMermaid(parseRegisteredMermaid(s)) ≡ normalize(s)` for canonical input. For structured families this emits a fresh canonical form; for opaque families it emits preserved source with `meta` re-attached.
|
|
197
|
+
- `parseRegisteredMermaid(serializeMermaid(d)) ≡ d` for every `d` produced by `parseRegisteredMermaid` or `mutate`.
|
|
222
198
|
|
|
223
|
-
**Flowchart MutationOp kinds** (
|
|
199
|
+
**Flowchart MutationOp kinds** (the authoritative menu is generated from the registry; `shape` fields accept geometry names and documented v11 names/aliases, and edge targets accept authored edge IDs or endpoint forms):
|
|
224
200
|
|
|
225
201
|
| Kind | Required | Optional | Inverse |
|
|
226
202
|
|---|---|---|---|
|
|
@@ -230,73 +206,111 @@ Two contracts:
|
|
|
230
206
|
| `set_label` | `target`, `label` | — | `set_label(target, prev_label)` |
|
|
231
207
|
| `add_edge` | `from`, `to` | `label`, `style` | `remove_edge(id)` |
|
|
232
208
|
| `remove_edge` | `id` | — | `add_edge(from, to, label, style)` |
|
|
209
|
+
| `set_shape` | `id`, `shape` | — | `set_shape(id, prev_shape)` |
|
|
210
|
+
| `set_direction` | `direction` | `subgraph` (sets that subgraph's override; omit = diagram) | `set_direction(prev_direction, subgraph)` |
|
|
211
|
+
| `add_subgraph` | `id` | `label`, `parent`, `members` (existing nodes MOVED in — the state `make_composite` precedent) | `remove_subgraph(id)` |
|
|
212
|
+
| `remove_subgraph` | `id` | `removeMembers` (default dissolves the box — members move to the parent scope; `true` deletes member nodes and their edges) | `add_subgraph(...)` |
|
|
213
|
+
| `move_node` | `id`, `subgraph \| null` (null = top level) | — | `move_node(id, prev_subgraph)` |
|
|
214
|
+
| `define_class` | `name`, `style` (CSS-like pairs, parsed by the parser's own style grammar) | — | `define_class(name, prev_style)` |
|
|
215
|
+
| `set_node_class` | `id`, `className \| null` | — | `set_node_class(id, prev_class)` |
|
|
216
|
+
| `set_node_style` | `id`, `style \| null` | — | `set_node_style(id, prev_style)` |
|
|
233
217
|
|
|
234
|
-
**State MutationOp kinds** (
|
|
218
|
+
**State MutationOp kinds** (18, BUILD-19 + the family elevation — promoting state from a "parses AS flowchart" projection to a dedicated `StateBody` IR with state-shaped ops and a real `asState` narrower). Modeled grammar: simple states (`state "Label" as id`, `id : Label`), transitions `from --> to [: label]` where `from`/`to` may be the reserved pseudostate `[*]` (source = start, target = end, scoped per composite level) or a history reference (`[H]`, `Base[H*]`), composite blocks `state X { … }` (nestable), `direction`, pseudostate stereotypes (`state id <<fork|join|choice>>` plus the history forms `<<history>>`/`<<H>>`/`<<deephistory>>`/`<<H*>>`), and notes (`note left|right of X : text`, block form included). Concurrency `--`, `classDef`/`class`/`:::` styling, bare state lines, and hyphenated composite ids are modeled structurally. `[*]` is contextual, not a state node:
|
|
235
219
|
|
|
236
220
|
| Kind | Required | Optional | Inverse |
|
|
237
221
|
|---|---|---|---|
|
|
238
222
|
| `add_state` | `id` | `label`, `parent` (composite) | `remove_state(id)` |
|
|
239
|
-
| `remove_state` | `id` (refused on a non-empty composite
|
|
223
|
+
| `remove_state` | `id` (refused on a non-empty composite unless `recursive`) | `recursive` (`true` removes the whole subtree; touching transitions/notes cascade, history refs `X[H]` included) | `add_state(...)` |
|
|
240
224
|
| `rename_state` | `from`, `to` | — (rewrites transitions) | `rename_state(to, from)` |
|
|
241
225
|
| `set_state_label` | `id`, `label \| null` | — | `set_state_label(id, prev_label)` |
|
|
242
226
|
| `add_transition` | `from`, `to` (`[*]` allowed) | `label`, `parent` | `remove_transition(from->to)` |
|
|
243
227
|
| `remove_transition` | `index` or `from`/`to` pair | `parent` | `add_transition(...)` |
|
|
244
228
|
| `set_transition_label` | `label \| null` + (`index` or `from`/`to`) | `parent` | `set_transition_label(..., prev_label)` |
|
|
245
|
-
| `make_composite` | `id`, `members: string[]` | `label` | (
|
|
246
|
-
|
|
247
|
-
|
|
229
|
+
| `make_composite` | `id`, `members: string[]` | `label` | `dissolve_composite(id)` |
|
|
230
|
+
| `set_direction` | `direction` | `state` (composite override; omit/null = diagram) | `set_direction(prev, state)` |
|
|
231
|
+
| `move_state` | `id`, `parent \| null` (null = top level; a simple parent promotes to a composite) | — | `move_state(id, prev_parent)` |
|
|
232
|
+
| `dissolve_composite` | `id` (hoists children + inner transitions into the parent scope; rejects while transitions/notes still reference it) | — | `make_composite(id, members, label)` |
|
|
233
|
+
| `add_note` | `target`, `text` | `side` (`left`/`right`, default `right`) | `remove_note(index)` |
|
|
234
|
+
| `remove_note` | `index` | — | `add_note(target, side, text)` |
|
|
235
|
+
| `set_note_text` | `index`, `text` | — | `set_note_text(index, prev_text)` |
|
|
236
|
+
| `define_class` | `name`, `style` | — | restore previous definition |
|
|
237
|
+
| `set_state_class` | `id`, `className \| null` | — | restore previous class |
|
|
238
|
+
| `set_state_style` | `id`, `style \| null` | — | restore previous style |
|
|
239
|
+
| `set_transition_style` | selector + `style \| null` | `parent`, `region` | restore previous style |
|
|
240
|
+
|
|
241
|
+
**Sequence MutationOp kinds** (top-level message indices remain separate from typed fragment-message indices):
|
|
248
242
|
|
|
249
243
|
| Kind | Required | Optional | Inverse |
|
|
250
244
|
|---|---|---|---|
|
|
251
|
-
| `add_participant` | `id` | `label` | `remove_participant(id)` |
|
|
245
|
+
| `add_participant` | `id` | `label`, `participantKind` (`participant`/`actor`) | `remove_participant(id)` |
|
|
252
246
|
| `remove_participant` | `id` | — | `add_participant(id, label)` |
|
|
253
|
-
| `add_message` | `from`, `to`, `text` | `style` (sync/async) | `remove_message(index)` |
|
|
247
|
+
| `add_message` | `from`, `to`, `text` | `style` (sync/async), insert `index` (omitted = append) | `remove_message(index)` |
|
|
254
248
|
| `remove_message` | `index` | — | `add_message(...)` |
|
|
255
249
|
| `set_message_text` | `index`, `text` | — | `set_message_text(index, prev_text)` |
|
|
250
|
+
| `move_message` | `from`, `to` (source order IS the interaction timeline, so reorder is a first-class edit) | — | `move_message(to, from)` |
|
|
251
|
+
| `set_participant_label` | `id`, `label` | — | `set_participant_label(id, prev_label)` |
|
|
252
|
+
| `add_fragment` / `remove_fragment` / `set_fragment_label` | fragment kind or index | label/index | matching inverse |
|
|
253
|
+
| `add_fragment_branch` / `set_fragment_branch_label` | fragment/branch indices | label | matching inverse |
|
|
254
|
+
| `add_fragment_message` / `remove_fragment_message` / `set_fragment_message_text` | fragment index + message fields/index | branch/index/style | matching inverse |
|
|
256
255
|
|
|
257
|
-
**Timeline MutationOp kinds** (
|
|
256
|
+
**Timeline MutationOp kinds** (15 — the journey conventions from PR #141: `index?` on add ops is an insert position, move ops take the insert position after removal, and errors name the legal range):
|
|
258
257
|
|
|
259
258
|
| Kind | Required | Inverse |
|
|
260
259
|
|---|---|---|
|
|
261
260
|
| `set_title` | `title \| null` | `set_title(prev_title)` |
|
|
262
|
-
| `add_section` | `label`
|
|
261
|
+
| `add_section` | `label` (+ optional insert `index`) | `remove_section(index)` |
|
|
263
262
|
| `remove_section` | `index` | `add_section(label)` |
|
|
264
263
|
| `set_section_label` | `index`, `label` | `set_section_label(index, prev_label)` |
|
|
265
|
-
| `add_period` | `sectionIndex`, `label` (+ optional `events: string[]`)
|
|
264
|
+
| `add_period` | `sectionIndex`, `label` (+ optional `events: string[]`, insert `index`) | `remove_period(sectionIndex, periodIndex)` |
|
|
266
265
|
| `remove_period` | `sectionIndex`, `periodIndex` | `add_period(...)` |
|
|
267
266
|
| `set_period_label` | `sectionIndex`, `periodIndex`, `label` | `set_period_label(... prev_label)` |
|
|
268
|
-
| `add_event` | `sectionIndex`, `periodIndex`, `text`
|
|
267
|
+
| `add_event` | `sectionIndex`, `periodIndex`, `text` (+ optional insert `index`) | `remove_event(... eventIndex)` |
|
|
269
268
|
| `remove_event` | `sectionIndex`, `periodIndex`, `eventIndex` | `add_event(...)` |
|
|
270
269
|
| `set_event_text` | `sectionIndex`, `periodIndex`, `eventIndex`, `text` | `set_event_text(... prev_text)` |
|
|
270
|
+
| `move_period` | `fromSection`, `fromIndex`, `toSection`, `toIndex` (timeline order IS the chronology, so reorder is a first-class edit) | `move_period(toSection, toIndex, fromSection, fromIndex)` |
|
|
271
|
+
| `move_event` | `fromSection`, `fromPeriod`, `fromIndex`, `toSection`, `toPeriod`, `toIndex` | `move_event(...)` |
|
|
272
|
+
| `move_section` | `from`, `to` | `move_section(to, from)` |
|
|
273
|
+
| `set_accessibility_title` | `title \| null` | `set_accessibility_title(prev)` |
|
|
274
|
+
| `set_accessibility_description` | `description \| null` | `set_accessibility_description(prev)` |
|
|
271
275
|
|
|
272
|
-
**Class MutationOp kinds** (
|
|
276
|
+
**Class MutationOp kinds** (15):
|
|
273
277
|
|
|
274
278
|
| Kind | Required | Inverse |
|
|
275
279
|
|---|---|---|
|
|
276
280
|
| `set_title` | `title \| null` | `set_title(prev_title)` |
|
|
277
|
-
| `add_class` | `id` (+ optional `label`, `members: string[]`)
|
|
281
|
+
| `add_class` | `id` (+ optional `label`, `generic`, `members: string[]`, `namespace` dot path) | `remove_class(id)` |
|
|
278
282
|
| `remove_class` | `id` | `add_class(id, label, members)` |
|
|
279
283
|
| `rename_class` | `from`, `to` | `rename_class(to, from)` |
|
|
284
|
+
| `set_class_generic` | `class`, `generic \| null` | `set_class_generic(class, prev_generic)` |
|
|
280
285
|
| `add_member` | `class`, `text` | `remove_member(class, index)` |
|
|
281
286
|
| `remove_member` | `class`, `index` | `add_member(class, text)` |
|
|
282
287
|
| `add_relation` | `from`, `to`, `relKind` (+ optional `label`) | `remove_relation(index)` |
|
|
283
288
|
| `remove_relation` | `index` | `add_relation(...)` |
|
|
284
289
|
| `add_note` | `text` (+ optional `for: class`) | `remove_note(index)` |
|
|
285
290
|
| `remove_note` | `index` | `add_note(text, for)` |
|
|
291
|
+
| `set_class_namespace` | `class`, `namespace \| null` (a dot path like `Platform.Auth`, declared on demand; null = top level) | `set_class_namespace(class, prev_namespace)` |
|
|
292
|
+
| `define_class` | `name`, `style` | restore previous definition |
|
|
293
|
+
| `set_css_class` | `class`, `className \| null` | restore previous assignment |
|
|
294
|
+
| `set_class_style` | `class`, `style \| null` | restore previous style |
|
|
286
295
|
|
|
287
|
-
**ER MutationOp kinds** (
|
|
296
|
+
**ER MutationOp kinds** (12):
|
|
288
297
|
|
|
289
298
|
| Kind | Required | Inverse |
|
|
290
299
|
|---|---|---|
|
|
291
|
-
| `add_entity` | `id` (+ optional `attributes: string[]`)
|
|
292
|
-
| `remove_entity` | `id` | `add_entity(id, attributes)` |
|
|
300
|
+
| `add_entity` | `id` (+ optional `label`, `attributes: string[]`) | `remove_entity(id)` |
|
|
301
|
+
| `remove_entity` | `id` | `add_entity(id, label, attributes)` |
|
|
293
302
|
| `rename_entity` | `from`, `to` | `rename_entity(to, from)` |
|
|
303
|
+
| `set_entity_label` | `entity`, `label \| null` | `set_entity_label(entity, previous_label)` |
|
|
294
304
|
| `add_attribute` | `entity`, `text` | `remove_attribute(entity, index)` |
|
|
295
305
|
| `remove_attribute` | `entity`, `index` | `add_attribute(entity, text)` |
|
|
296
306
|
| `add_relation` | `from`, `to`, `leftCard`, `rightCard` (+ `dashed`, `label`) | `remove_relation(index)` |
|
|
297
307
|
| `remove_relation` | `index` | `add_relation(...)` |
|
|
308
|
+
| `set_direction` | `direction` | restore previous direction |
|
|
309
|
+
| `define_class` | `name`, `style` | restore previous definition |
|
|
310
|
+
| `set_entity_class` | `entity`, `className \| null` | restore previous assignment |
|
|
311
|
+
| `set_entity_style` | `entity`, `style \| null` | restore previous style |
|
|
298
312
|
|
|
299
|
-
**Journey MutationOp kinds** (
|
|
313
|
+
**Journey MutationOp kinds** (promoted from opaque-only fallback semantics through the family-descriptor registry; ordering and accessibility are typed because Journey order is the timeline):
|
|
300
314
|
|
|
301
315
|
| Kind | Required | Inverse |
|
|
302
316
|
|---|---|---|
|
|
@@ -315,22 +329,31 @@ Two contracts:
|
|
|
315
329
|
| `set_accessibility_title` | `title \| null` | `set_accessibility_title(prev)` |
|
|
316
330
|
| `set_accessibility_description` | `description \| null` | `set_accessibility_description(prev)` |
|
|
317
331
|
|
|
318
|
-
**Architecture MutationOp kinds** (
|
|
332
|
+
**Architecture MutationOp kinds** (19):
|
|
319
333
|
|
|
320
334
|
| Kind | Required | Inverse |
|
|
321
335
|
|---|---|---|
|
|
322
|
-
| `
|
|
323
|
-
| `
|
|
324
|
-
| `
|
|
325
|
-
| `
|
|
326
|
-
| `
|
|
327
|
-
| `
|
|
328
|
-
| `
|
|
329
|
-
| `
|
|
330
|
-
| `
|
|
331
|
-
| `
|
|
332
|
-
|
|
333
|
-
|
|
336
|
+
| `set_title` | `title \| null` | `set_title(prev_title)` |
|
|
337
|
+
| `set_accessibility_title` | `title \| null` | `set_accessibility_title(prev)` |
|
|
338
|
+
| `set_accessibility_description` | `description \| null` | `set_accessibility_description(prev)` |
|
|
339
|
+
| `add_service` | `id` (+ optional `label`, `icon`, `group`) | `remove_service(id)` |
|
|
340
|
+
| `remove_service` | `id` (cascades edges/alignments) | `add_service(...)` + re-add edges |
|
|
341
|
+
| `rename_service` | `from`, `to` (rewrites edges/alignments) | `rename_service(to, from)` |
|
|
342
|
+
| `set_service_label` | `id`, `label` | `set_service_label(id, prev_label)` |
|
|
343
|
+
| `set_service_icon` | `id`, `icon: string \| null` | `set_service_icon(id, prev_icon)` |
|
|
344
|
+
| `move_service` | `id`, `group: string \| null` | `move_service(id, prev_group)` |
|
|
345
|
+
| `add_junction` | `id` (+ optional `group`) | `remove_junction(id)` |
|
|
346
|
+
| `remove_junction` | `id` (cascades edges/alignments) | `add_junction(...)` + re-add edges |
|
|
347
|
+
| `rename_junction` | `from`, `to` (rewrites edges/alignments) | `rename_junction(to, from)` |
|
|
348
|
+
| `move_junction` | `id`, `group: string \| null` | `move_junction(id, prev_group)` |
|
|
349
|
+
| `add_group` | `id` (+ optional `label`, `icon`, `parent`) | `remove_group(id)` |
|
|
350
|
+
| `set_group_label` | `id`, `label` | `set_group_label(id, prev_label)` |
|
|
351
|
+
| `remove_group` | `id` (refused if non-empty) | `add_group(...)` |
|
|
352
|
+
| `add_edge` | `from`, `to`, `fromSide`, `toSide` (+ optional boundaries/label/arrows) | `remove_edge(id)` |
|
|
353
|
+
| `update_edge` | `index` (+ any endpoint/side/boundary/label/arrow fields) | `update_edge(index, previous fields)` |
|
|
354
|
+
| `remove_edge` | `index` or `id` (`from->to`) | `add_edge(...)` |
|
|
355
|
+
|
|
356
|
+
**XY chart MutationOp kinds** (10, BUILD-16 — promoting the xychart family to structured mutation via the family-descriptor registry, following the BUILD-15 journey and BUILD-17 architecture pilots). Canonical number format is `String(n)` (shortest round-tripping decimal); all values must be finite. Modeled grammar covers bare titles/axis-names/series-names/categories — quoted text whose content is bare parses and canonicalizes to unquoted form; embedded quotes/brackets, multi-statement `;` lines, accTitle/accDescr, and any other unmodeled syntax fall back to opaque:
|
|
334
357
|
|
|
335
358
|
| Kind | Required | Inverse |
|
|
336
359
|
|---|---|---|
|
|
@@ -342,8 +365,10 @@ Two contracts:
|
|
|
342
365
|
| `set_series_values` | `index`, `values: number[]` | `set_series_values(index, prev_values)` |
|
|
343
366
|
| `set_series_name` | `index`, `name: string \| null` | `set_series_name(index, prev_name)` |
|
|
344
367
|
| `reorder_series` | `from`, `to` | `reorder_series(to, from)` |
|
|
368
|
+
| `set_orientation` | `horizontal: boolean` (`true` adds the `horizontal` header suffix; `false` drops it — vertical is the serialized default) | `set_orientation(prev)` |
|
|
369
|
+
| `set_data_point` | `seriesIndex`, `index`, `value` (finite; out-of-range indices name the valid ranges) | `set_data_point(seriesIndex, index, prev_value)` |
|
|
345
370
|
|
|
346
|
-
**Pie MutationOp kinds** (7 — promoting the pie family to structured mutation via the
|
|
371
|
+
**Pie MutationOp kinds** (7 — promoting the pie family to structured mutation via the family-descriptor registry, following the journey/architecture/xychart pilots). Slices are addressed by their (unique) label; values must be positive finite numbers. The header's `showData` flag and an optional `title` are modeled; any unmodeled line (accTitle/accDescr, malformed entry) falls back to opaque losslessly:
|
|
347
372
|
|
|
348
373
|
| Kind | Required | Inverse |
|
|
349
374
|
|---|---|---|
|
|
@@ -355,7 +380,7 @@ Two contracts:
|
|
|
355
380
|
| `set_slice_value` | `label`, `value` (> 0) | `set_slice_value(label, prev_value)` |
|
|
356
381
|
| `reorder_slice` | `from`, `to` | `reorder_slice(to, from)` |
|
|
357
382
|
|
|
358
|
-
**Quadrant MutationOp kinds** (7 — promoting the quadrantChart family to structured mutation via the
|
|
383
|
+
**Quadrant MutationOp kinds** (7 — promoting the quadrantChart family to structured mutation via the family-descriptor registry). Points are addressed by their (unique) label; coordinates must be in `[0, 1]`. Quadrant numbering follows Mermaid core (1=top-right, 2=top-left, 3=bottom-left, 4=bottom-right). Styling (`classDef`, `:::`), out-of-range coordinates, and any unmodeled line fall back to opaque losslessly:
|
|
359
384
|
|
|
360
385
|
| Kind | Required | Inverse |
|
|
361
386
|
|---|---|---|
|
|
@@ -367,7 +392,7 @@ Two contracts:
|
|
|
367
392
|
| `move_point` | `label`, `x`, `y` (in `[0,1]`) | `move_point(label, prev_x, prev_y)` |
|
|
368
393
|
| `rename_point` | `from`, `to` | `rename_point(to, from)` |
|
|
369
394
|
|
|
370
|
-
**Gantt MutationOp kinds** (
|
|
395
|
+
**Gantt MutationOp kinds** (13 — segment-preserving from day one per [`docs/design/families/gantt.md`](./docs/design/families/gantt.md)). Sections and tasks are addressed by index (`sectionIndex`, `taskIndex`); `taskId` is the Mermaid id used by `after`/`until`/`click`. Calendar directives (`dateFormat`, `excludes`, `includes`, `weekend`, `weekday`, `todayMarker`, `tickInterval`, `inclusiveEndDates`, `topAxis`), `click` lines, accTitle/accDescr, and comments ride along VERBATIM as opaque-block segments — preserved, source-level-editable, never typed-editable in v1. Every value an op writes is validated by rendering its canonical line and re-parsing it (correctness by construction), so labels with `:` or values with `,` are rejected rather than corrupting the source. Gantt source order IS scheduling semantics (a task with an implicit start chains from the previous task in flat source order), so the move ops REJECT prescriptively whenever they would change an implicit-start task's predecessor — materialize an explicit start (`set_task_dates` or an `after` dependency) and retry:
|
|
371
396
|
|
|
372
397
|
| Kind | Required | Inverse |
|
|
373
398
|
|---|---|---|
|
|
@@ -375,32 +400,65 @@ Two contracts:
|
|
|
375
400
|
| `add_section` | `label` | `remove_section(index)` |
|
|
376
401
|
| `rename_section` | `index`, `label` | `rename_section(index, prev_label)` |
|
|
377
402
|
| `remove_section` | `index` (drops its tasks too) | `add_section(...)` + `add_task(...)` |
|
|
378
|
-
| `add_task` | `sectionIndex`, `label`, `end` (+ optional `taskId`, `tags`, `start`) | `remove_task(sectionIndex, taskIndex)` |
|
|
403
|
+
| `add_task` | `sectionIndex`, `label`, `end` (+ optional `taskId`, `tags`, `start`, insert `index` — a mid-chain insert deliberately re-chains the follower) | `remove_task(sectionIndex, taskIndex)` |
|
|
379
404
|
| `remove_task` | `sectionIndex`, `taskIndex` | `add_task(...)` |
|
|
380
405
|
| `rename_task` | `sectionIndex`, `taskIndex`, `label` | `rename_task(..., prev_label)` |
|
|
381
406
|
| `set_task_status` | `sectionIndex`, `taskIndex`, `status: 'active' \| 'done' \| 'crit' \| null` (milestone/vert tags are never disturbed) | `set_task_status(..., prev_status)` |
|
|
382
407
|
| `set_task_dates` | `sectionIndex`, `taskIndex`, `start?: string \| null`, `end?: string` | `set_task_dates(..., prev_start, prev_end)` |
|
|
408
|
+
| `set_task_flags` | `sectionIndex`, `taskIndex`, `milestone?`, `vert?` (structural-tag toggles; `set_task_status` never touches them) | `set_task_flags(..., prev_flags)` |
|
|
409
|
+
| `set_task_id` | `sectionIndex`, `taskIndex`, `taskId \| null` (a rename REWRITES structured `after`/`until` references; REJECTS while opaque segments reference the id, and `null` rejects while ANY reference exists) | `set_task_id(..., prev_id)` |
|
|
410
|
+
| `move_task` | `fromSection`, `fromIndex`, `toSection`, `toIndex` (implicit-start guard above) | `move_task(toSection, toIndex, fromSection, fromIndex)` |
|
|
411
|
+
| `move_section` | `from`, `to` (implicit-start guard above) | `move_section(to, from)` |
|
|
412
|
+
|
|
413
|
+
**Mindmap MutationOp kinds** (10; see [`docs/design/families/mindmap.md`](./docs/design/families/mindmap.md)):
|
|
414
|
+
|
|
415
|
+
`add_node`, `remove_node`, `rename_node`, `set_label`, `move_node`, `set_shape`, `set_icon`, `set_node_class`, `set_accessibility_title`, `set_accessibility_description`.
|
|
416
|
+
|
|
417
|
+
**GitGraph MutationOp kinds** (11; see [`docs/design/families/gitgraph.md`](./docs/design/families/gitgraph.md)):
|
|
418
|
+
|
|
419
|
+
`append_commit`, `create_branch`, `checkout_branch`, `merge_branch`, `cherry_pick`, `set_commit_message`, `set_commit_type`, `set_commit_tags`, `rename_branch`, `set_accessibility_title`, `set_accessibility_description`.
|
|
420
|
+
|
|
421
|
+
**Radar MutationOp kinds** (14 — promoting the `radar-beta` family to structured mutation via the FamilyPlugin registry). Axes and curves are addressed by unique ids; each curve carries exactly one finite value per axis, in axis order. The header keyword is `radar-beta`; order-independent and multiline `title`, `axis`/`curve`, and option declarations are modeled. Duplicate identities, vector mismatches, accessibility directives, and any unmodeled line fall back to opaque losslessly rather than weakening the typed invariant:
|
|
422
|
+
|
|
423
|
+
| Kind | Required | Inverse |
|
|
424
|
+
|---|---|---|
|
|
425
|
+
| `set_title` | `title \| null` | `set_title(prev_title)` |
|
|
426
|
+
| `add_axis` | `id` (+ optional `label`, insert `index`, `fill`) | `remove_axis(id)` |
|
|
427
|
+
| `remove_axis` | `id` | `add_axis(...)` |
|
|
428
|
+
| `rename_axis` | `from`, `to` | `rename_axis(to, from)` |
|
|
429
|
+
| `set_axis_label` | `id`, `label \| null` | `set_axis_label(id, prev_label)` |
|
|
430
|
+
| `reorder_axis` | `from`, `to` (permutes every curve's value vector) | `reorder_axis(to, from)` |
|
|
431
|
+
| `add_curve` | `id`, `values` (one per axis) (+ optional `label`, insert `index`) | `remove_curve(id)` |
|
|
432
|
+
| `remove_curve` | `id` | `add_curve(...)` |
|
|
433
|
+
| `set_curve_values` | `id`, `values` (one per axis) | `set_curve_values(id, prev_values)` |
|
|
434
|
+
| `set_curve_value` | `curve`, `axis`, `value` (finite) | `set_curve_value(curve, axis, prev_value)` |
|
|
435
|
+
| `set_curve_label` | `id`, `label \| null` | `set_curve_label(id, prev_label)` |
|
|
436
|
+
| `rename_curve` | `from`, `to` | `rename_curve(to, from)` |
|
|
437
|
+
| `reorder_curve` | `from`, `to` | `reorder_curve(to, from)` |
|
|
438
|
+
| `set_config` | optional `max`, `min`, `ticks` (`1..64`), `graticule`, `showLegend`; `null` resets each field | `set_config(prev_fields)` |
|
|
383
439
|
|
|
384
|
-
**Structured-or-opaque rule (v4): never lossy.** The parser only produces a structured body when it fully understands every non-blank, non-comment line for most structured families. If the source contains *any* construct the parser doesn't model — `direction TB` in class,
|
|
440
|
+
**Structured-or-opaque rule (v4): never lossy.** The parser only produces a structured body when it fully understands every non-blank, non-comment line for most structured families. If the source contains *any* construct the parser doesn't model — `direction TB` in class, out-of-range scores in journey, duplicate Architecture title declarations, a `;`-joined multi-statement line in xychart, a malformed entry in pie, or out-of-range coordinates in quadrant, etc. — parsing **falls back to an opaque body**. The diagram still parses, renders, verifies (structurally), and round-trips losslessly via preserved `body.source`; it simply isn't offered for structured mutation (structured-family narrowers return `null` on opaque fallbacks). This guarantees the parser never silently drops information. Earlier drafts dropped unrecognized lines on the floor; v4 does not.
|
|
385
441
|
|
|
386
|
-
**Segment-preserving bodies (BUILD-18) — sequence ends the all-or-nothing cliff.** Sequence
|
|
442
|
+
**Segment-preserving bodies (BUILD-18) — sequence ends the all-or-nothing cliff.** Sequence carries an ordered `statements: SequenceStatement[]` list. `alt|opt|loop|par` are typed fragments: their branches/messages participate in describe/facts/verify and have dedicated mutation ops. Other block constructs (`critical|break|rect|box … end`) and `Note`/`activate`/`deactivate`/`create`/`destroy`/`autonumber`/`title` remain VERBATIM opaque segments. Top-level message indices stay backward-compatible and distinct from fragment indices. Only an un-segmentable body (a stray `end`, an unclosed block) falls back to whole-body opaque. Gantt adopts the same pattern for calendar directives/click/comments. ER also uses ordered typed and opaque-block segments; Class and Timeline are the remaining follow-up work.
|
|
387
443
|
|
|
388
|
-
For any opaque fallback, cross-cutting edits are source-level only: operate against preserved source intentionally, then re-parse and verify before returning. Every renderable family now ships structured mutation; a new family follows the same pattern as its definition of done: narrowed type + body parser + serializer + per-family ops + verify hook + round-trip property tests + doc sync (most recently
|
|
444
|
+
For any opaque fallback, cross-cutting edits are source-level only: operate against preserved source intentionally, then re-parse and verify before returning. Every renderable family now ships structured mutation; a new family follows the same pattern as its definition of done: narrowed type + body parser + serializer + per-family ops + verify hook + round-trip property tests + doc sync (most recently Mindmap and GitGraph). See `docs/contributing/adding-diagram-types.md`.
|
|
389
445
|
|
|
390
|
-
Convention bans constructing `ValidDiagram` outside `
|
|
446
|
+
Convention bans constructing `ValidDiagram` outside `parseRegisteredMermaid`, `mutate`, `synthesizeFromGraph`, and `createMermaid`/`buildMermaid`.
|
|
391
447
|
|
|
392
448
|
---
|
|
393
449
|
|
|
394
450
|
## Public API
|
|
395
451
|
|
|
396
452
|
```ts
|
|
397
|
-
|
|
453
|
+
parseRegisteredMermaid(source: string): Result<ValidDiagram, ParseError[]>
|
|
398
454
|
layoutMermaid(d: ValidDiagram): RenderedLayout
|
|
399
455
|
renderMermaidASCII(input: ValidDiagram | string, opts?): string
|
|
400
456
|
renderMermaidPNG(input: ValidDiagram | string, opts?): Uint8Array
|
|
401
457
|
renderMermaidSVG(input: ValidDiagram | string, opts?): string
|
|
402
458
|
verifyMermaid(input: ValidDiagram | string, opts?: VerifyOptions): VerifyResult
|
|
403
459
|
serializeMermaid(d: ValidDiagram): string
|
|
460
|
+
// ASCII opts.targetWidth is a hard display-cell bound; impossible bounds throw
|
|
461
|
+
// AsciiWidthError { code, requestedWidth, requiredWidth, family, reason }.
|
|
404
462
|
|
|
405
463
|
// Mutation is overloaded by family. Opaque/source-only families don't typecheck.
|
|
406
464
|
mutate(d: FlowchartValidDiagram, op: FlowchartMutationOp): Result<FlowchartValidDiagram, MutationError>
|
|
@@ -415,6 +473,9 @@ mutate(d: XyChartValidDiagram, op: XyChartMutationOp): Result<XyChartValidDi
|
|
|
415
473
|
mutate(d: PieValidDiagram, op: PieMutationOp): Result<PieValidDiagram, MutationError>
|
|
416
474
|
mutate(d: QuadrantValidDiagram, op: QuadrantMutationOp): Result<QuadrantValidDiagram, MutationError>
|
|
417
475
|
mutate(d: GanttValidDiagram, op: GanttMutationOp): Result<GanttValidDiagram, MutationError>
|
|
476
|
+
mutate(d: MindmapValidDiagram, op: MindmapMutationOp): Result<MindmapValidDiagram, MutationError>
|
|
477
|
+
mutate(d: GitGraphValidDiagram, op: GitGraphMutationOp): Result<GitGraphValidDiagram, MutationError>
|
|
478
|
+
mutate(d: RadarValidDiagram, op: RadarMutationOp): Result<RadarValidDiagram, MutationError>
|
|
418
479
|
|
|
419
480
|
// Narrowing helpers; null when the diagram isn't of that family or is opaque/source-level.
|
|
420
481
|
asFlowchart(d: ValidDiagram): FlowchartValidDiagram | null
|
|
@@ -429,6 +490,9 @@ asXyChart(d: ValidDiagram): XyChartValidDiagram | null
|
|
|
429
490
|
asPie(d: ValidDiagram): PieValidDiagram | null
|
|
430
491
|
asQuadrant(d: ValidDiagram): QuadrantValidDiagram | null
|
|
431
492
|
asGantt(d: ValidDiagram): GanttValidDiagram | null
|
|
493
|
+
asMindmap(d: ValidDiagram): MindmapValidDiagram | null
|
|
494
|
+
asGitGraph(d: ValidDiagram): GitGraphValidDiagram | null
|
|
495
|
+
asRadar(d: ValidDiagram): RadarValidDiagram | null
|
|
432
496
|
|
|
433
497
|
// Build a ValidDiagram from a JSON-safe graph payload without re-parsing
|
|
434
498
|
// source. Used by `am parse | am serialize` shell pipelines.
|
|
@@ -455,9 +519,9 @@ There is no `LayoutContext`, no `SeededRNG`, no `Clock`, no font-metric table in
|
|
|
455
519
|
- **Agent surface exposed via the `./agent` subpath export** on the `agentic-mermaid` package. Agentic Mermaid is the product/docs name, npm identity, and repository path (`adewale/agentic-mermaid`). The subpath export keeps renderer and agent surfaces side by side.
|
|
456
520
|
- **Deterministic layout, verified.** Layout JSON is byte-identical across processes because ELK is configured for model-order layout with no random seed (see § (1)). No seed parameter is exposed because none affects output. Cross-machine byte equality across different CPU float behavior is not claimed; structural determinism within an ELK version is guaranteed and tested cross-process.
|
|
457
521
|
- **IDs are content-hashed and stable** across runs (within an ELK version).
|
|
458
|
-
- **`MermaidGraph` is kept** as an exported type — `ValidDiagram` wraps it in `body.graph` for flowchart, rather than replacing it. The original spec called for removal;
|
|
522
|
+
- **`MermaidGraph` is kept** as an exported type — `ValidDiagram` wraps it in `body.graph` for flowchart, rather than replacing it. The original spec called for removal; characterization showed it would break existing tests and the Craft Agents consumer. The wrapping shape costs nothing.
|
|
459
523
|
- **`renderMermaidSVGAsync` is kept**. Removing it was a v1-aspiration that turned out to break consumers for no win at the agent surface.
|
|
460
|
-
- **`mermaidConfig` precedence**
|
|
524
|
+
- **`mermaidConfig` precedence** is source frontmatter < init < explicit render options for supported family fields. Normalization merges source wrappers; family resolvers then reapply the original explicit section last. State has direct public-path precedence and geometry probes in `state-config.test.ts`.
|
|
461
525
|
|
|
462
526
|
---
|
|
463
527
|
|
|
@@ -468,7 +532,7 @@ Five artifacts, all derived from this doc:
|
|
|
468
532
|
- **npm package** `agentic-mermaid` with the `agentic-mermaid/agent` subpath. The full TypeScript API, including ASCII, PNG, and SVG output helpers. Agents with shell access import the library directly and compose verbs in their own JS/TS runtime; no MCP wrapper required.
|
|
469
533
|
- **`skills/agentic-mermaid-diagram-workflow/`** agent-agnostic skill bundle. Master `SKILL.md` routes by *both* diagram family and composition channel: it picks Code Mode when the MCP is connected, library import when the agent can run JS/TS with imports, the CLI for shell-only contexts. Per-family references (`flowchart.md`, `sequence.md`, etc.) describe syntax. Two channel references — `code-mode.md` (the canonical multi-step pattern) and `cli.md` (shell-only) — describe composition. Progressive disclosure means the LLM loads only what it needs. Family references sync from upstream Mermaid docs weekly via the shipped GitHub Action at `.github/workflows/sync-mermaid-docs.yml`, alongside our additions (LayoutWarning codes, MutationOp taxonomy).
|
|
470
534
|
- **Substrate grep-lint** runs under `bun test` (not an uninstalled ESLint): `src/__tests__/agent-substrate-lint.test.ts` fails the build if `Math.random`, `Date.now`, or `performance.now` appear in `src/agent/**` or `src/layout-engine.ts`. This is real enforcement, executed in CI, not an aspirational config file.
|
|
471
|
-
- **`agentic-mermaid-mcp`** Code Mode-style MCP server. The primary tool is `execute(code: string)`: the model writes JavaScript against the typed `mermaid.*` SDK declaration embedded in the system prompt
|
|
535
|
+
- **`agentic-mermaid-mcp`** Code Mode-style MCP server. The primary tool is `execute(code: string)`: the model writes JavaScript against the typed `mermaid.*` SDK declaration embedded in the system prompt. Local stdio/HTTP runs synchronous code in a `node:vm` sandbox. The hosted `/mcp` endpoint runs the same hardened facade in per-request Cloudflare Dynamic Worker isolates with bounded CPU/subrequests and no outbound network. Pure render/verify/describe helpers share transport-neutral behavior. Differential tests pin the common contract and explicitly name strict-module and CPU-time divergences; neither runtime depends on `@cloudflare/codemode`.
|
|
472
536
|
- **`Instructions_for_agents.md`** at repo root, hard-capped under 100 lines. `am --agent-instructions` prints the same content at runtime; a doc-sync test asserts the two are byte-identical.
|
|
473
537
|
|
|
474
538
|
No HTTP endpoint or editor WebSocket watch in v1. The skill teaches Code Mode for both paths: agents-with-shell write JS/TS against the imported library; agents-without-shell write JavaScript against the MCP's `mermaid.*` SDK. Same surface in both cases.
|
|
@@ -495,8 +559,8 @@ Agent-contract CLI verbs for explicit self-discovery, summaries, and batch opera
|
|
|
495
559
|
The canonical runtime guide lives in `Instructions_for_agents.md` and is emitted byte-for-byte by `am --agent-instructions`; this spec intentionally does not duplicate the full snippet. The stable contract is:
|
|
496
560
|
|
|
497
561
|
1. For new diagrams, `buildMermaid(kind, ops)` — or `createMermaid(kind)` then typed mutations — then `verifyMermaid` / render or return it. Author Mermaid source directly only for syntax the typed ops do not model.
|
|
498
|
-
2. For existing diagrams, `
|
|
499
|
-
3.
|
|
562
|
+
2. For existing diagrams, `parseRegisteredMermaid(source)` → `ValidDiagram`.
|
|
563
|
+
3. Use the family entry's registry-advertised narrower; `null` means no structured mutation for that body.
|
|
500
564
|
4. Apply typed `mutate` ops only to narrowed mutable bodies; Code Mode SDK-returned diagrams are read-only to block direct IR edits.
|
|
501
565
|
5. Run `verifyMermaid(d)` at every commit point and inspect `ok` / `warnings` / `layout`.
|
|
502
566
|
6. Only then `serializeMermaid(d)`.
|
|
@@ -546,15 +610,15 @@ MermaidSeqBench is wired as an external corpus signal; live model transcript eva
|
|
|
546
610
|
|
|
547
611
|
- **Determinism is empirical, not proven.** It's established by cross-process test over a corpus + the drift sentinel, plus reading ELK's config (`considerModelOrder: NODES_AND_EDGES`, no `randomSeed`). An ELK upgrade could in principle change this; the cross-process test and sentinel would catch it. There is no layout seed to fall back on because seeding never affected geometry. (The render option `seed` is a *style* seed: it re-rolls the ink wobble of styled looks and never moves layout.)
|
|
548
612
|
- **Determinism claim, precisely.** Layout JSON is byte-identical (after structural parse) across processes AND across JS runtimes (bun, node) on the same machine and same ELK version; this is verified on same-machine x86_64 and ARM64 when Node + built `dist/` are present. Direct cross-architecture byte equality (x86_64 output compared to ARM64 output) is still not a separate claim.
|
|
549
|
-
- **Sequence structured coverage is segment-preserving (BUILD-18).** Participant declarations
|
|
550
|
-
- **
|
|
613
|
+
- **Sequence structured coverage is segment-preserving (BUILD-18).** Participant declarations, top-level messages, and direct-message `alt`/`opt`/`loop`/`par` fragments are typed; fragment messages participate in describe/facts/verify and dedicated mutation ops. Note/critical/break/rect/box/activate/autonumber/title and nested or otherwise unmodeled fragment content ride along as verbatim opaque-block *segments*, so the structured ops survive instead of going whole-body opaque. Messages inside those remaining opaque blocks are deliberately not modeled. Only un-segmentable input (unbalanced `end`, unclosed block) falls back to whole-body opaque. The honest tradeoff is unchanged — never lossy — it just no longer sacrifices the structured ops at the first unmodeled line. ER also has ordered typed and opaque-block segments; Class and Timeline are the remaining follow-up work.
|
|
614
|
+
- **Every registered renderable family ships structured mutation; opaque fallbacks stay source-level only.** A typed narrower exists for every family kind; only opaque-fallback bodies for unmodeled syntax remain deliberate, lossless source-level paths.
|
|
551
615
|
- **Live-model agent-usage eval is periodic, not PR CI.** Stored Code Mode scripts, sandbox traces, task oracles, and the committed pi-subagent transcript replay run in CI; API-backed release-model transcripts remain in `TODO.md` because they need model access and selected release tasks.
|
|
552
616
|
- **Bloat in agent-facing docs.** `Instructions_for_agents.md` is hard-capped under 100 lines; doc-sync test enforces.
|
|
553
617
|
|
|
554
618
|
## What v4 delivers (vs. earlier drafts)
|
|
555
619
|
|
|
556
620
|
- **Determinism is structural and verified cross-process** — not a seed apparatus. The seed/RNG/clock machinery and the font-metric table are *removed* (they did nothing).
|
|
557
|
-
- **Mutation for
|
|
621
|
+
- **Mutation for every registered renderable family**, with family-narrowed overloads and compile-time rejection of opaque/source-only fallback bodies.
|
|
558
622
|
- **Sequence parsing is lossless** — segment-preserving structured body (BUILD-18): Note/alt/loop/etc. ride along verbatim as opaque-block segments while the structured ops stay live; only un-segmentable input falls back to whole-body opaque; never silently drops constructs.
|
|
559
623
|
- **Substrate enforcement is a real grep test** that runs under `bun test`, not an ESLint config that was never installed.
|
|
560
624
|
- **`synthesizeFromGraph`** lets `am parse | am serialize` round-trip without `canonicalSource` on the wire.
|
|
@@ -578,7 +642,7 @@ Concrete consequences, in roughly descending impact:
|
|
|
578
642
|
5. **No need to ship `diffDiagrams` or `explainDiagram`.** Already cut. Code Mode confirms the cut: an agent that wants structural diff writes it from `parse` + `ValidDiagram` inspection in JavaScript. Every "would be nice to have a verb for" becomes "write the code for it in `execute()`."
|
|
579
643
|
6. **Library as the cross-tool agent interface for diagrams.** A Mermaid linter, a `mermaid → d2` converter, a `graphviz → mermaid` importer can each expose the same Code Mode shape. Any agent then writes one JavaScript snippet that composes across libraries. We've effectively defined the agent interface for diagrams in this language.
|
|
580
644
|
7. **Benchmark eval at speed.** MermaidSeqBench (and any future eval) runs as one `execute()` per case rather than N round-trips. Internal velocity multiplier.
|
|
581
|
-
8. **
|
|
645
|
+
8. **Hosted Worker path.** The shipped `/mcp` endpoint uses Cloudflare Dynamic Worker isolates through the platform loader binding, not `@cloudflare/codemode`. The runtime has explicit security/resource limits and differential parity with local Code Mode; remaining WAF and abuse-control operations are tracked separately in `TODO.md`.
|
|
582
646
|
9. **The skill becomes runnable, not just descriptive.** `references/code-mode.md` ships canonical executable JavaScript snippets the agent copy-pastes into `execute()`. Skill stops being prose; starts being a library of executable patterns.
|
|
583
647
|
10. **A future diagram REPL would be a thin transport.** An `am repl` could become an interactive Code Mode shell — paste JavaScript, get structured results, iterate. Same sandbox, different transport. It is not shipped and would need promotion to `TODO.md` before implementation.
|
|
584
648
|
|