agentic-mermaid 0.4.1 → 0.5.3
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 +94 -627
- package/CHANGELOG.md +651 -0
- package/Instructions_for_agents.md +44 -23
- package/LICENSES/Khroma-MIT.txt +21 -0
- package/LICENSES/Mermaid-MIT.txt +21 -0
- package/LICENSES/es-toolkit-MIT.txt +21 -0
- package/LICENSES/pele-MIT.txt +40 -0
- package/LICENSES/zenuml-core-MIT.txt +21 -0
- package/README.md +93 -50
- package/SECURITY.md +28 -12
- package/THIRD_PARTY_NOTICES.md +60 -0
- package/assets/hero.png +0 -0
- package/dist/agent-core.d.ts +478 -210
- package/dist/agent-core.js +1 -396
- package/dist/agent.d.ts +17 -8
- package/dist/agent.js +1 -408
- package/dist/agentic-mermaid-mcp.js +1 -11
- package/dist/am.js +1 -34562
- package/dist/browser-lazy/chunks/agentic-producer-core-CC6OOLDW.js +1 -0
- package/dist/browser-lazy/chunks/architecture-QUFVKYJR.js +13 -0
- package/dist/browser-lazy/chunks/block-6J3Q63BO.js +11 -0
- package/dist/browser-lazy/chunks/builtin-backends-7SOZZHPF.js +12 -0
- package/dist/browser-lazy/chunks/c4-SQVBZAKJ.js +10 -0
- package/dist/browser-lazy/chunks/chunk-2GPK4VFF.js +5 -0
- package/dist/browser-lazy/chunks/chunk-2I4UPL7Q.js +3 -0
- package/dist/browser-lazy/chunks/chunk-2SH76OTH.js +1 -0
- package/dist/browser-lazy/chunks/chunk-2UIA2IME.js +3 -0
- package/dist/browser-lazy/chunks/chunk-4LHYF3BS.js +1 -0
- package/dist/browser-lazy/chunks/chunk-5B2Z7575.js +1 -0
- package/dist/browser-lazy/chunks/chunk-5FQ534HP.js +1 -0
- package/dist/browser-lazy/chunks/chunk-5UVGUSD6.js +1 -0
- package/dist/browser-lazy/chunks/chunk-5X6MJX3H.js +1 -0
- package/dist/browser-lazy/chunks/chunk-AMJLVPUB.js +4 -0
- package/dist/browser-lazy/chunks/chunk-BU5LHXNJ.js +3 -0
- package/dist/browser-lazy/chunks/chunk-BY2CPG6B.js +1 -0
- package/dist/browser-lazy/chunks/chunk-CN7WTBWB.js +1 -0
- package/dist/browser-lazy/chunks/chunk-CQE4HQEW.js +1 -0
- package/dist/browser-lazy/chunks/chunk-CSFUKSU6.js +1 -0
- package/dist/browser-lazy/chunks/chunk-DF6765YX.js +17 -0
- package/dist/browser-lazy/chunks/chunk-E2WMJZNM.js +1 -0
- package/dist/browser-lazy/chunks/chunk-FAIMVOX5.js +6 -0
- package/dist/browser-lazy/chunks/chunk-GVOEAY52.js +1 -0
- package/dist/browser-lazy/chunks/chunk-HLWUNUCM.js +1 -0
- package/dist/browser-lazy/chunks/chunk-ICC7HBJX.js +1 -0
- package/dist/browser-lazy/chunks/chunk-J35HAQQF.js +20 -0
- package/dist/browser-lazy/chunks/chunk-J7FFAFQF.js +1 -0
- package/dist/browser-lazy/chunks/chunk-LH7HUDKW.js +1 -0
- package/dist/browser-lazy/chunks/chunk-N5ELX7LR.js +2 -0
- package/dist/browser-lazy/chunks/chunk-NMQQMRIR.js +1 -0
- package/dist/browser-lazy/chunks/chunk-NO7ZIVRU.js +1 -0
- package/dist/browser-lazy/chunks/chunk-OZ443IVJ.js +16 -0
- package/dist/browser-lazy/chunks/chunk-PQGPS2YV.js +7 -0
- package/dist/browser-lazy/chunks/chunk-QA6GJQ4X.js +1 -0
- package/dist/browser-lazy/chunks/chunk-RIVTHZAQ.js +1 -0
- package/dist/browser-lazy/chunks/chunk-SZELX2EJ.js +1 -0
- package/dist/browser-lazy/chunks/chunk-TYZOZXUJ.js +22 -0
- package/dist/browser-lazy/chunks/chunk-UL6NDWLL.js +1 -0
- package/dist/browser-lazy/chunks/chunk-VQYYGAXP.js +1 -0
- package/dist/browser-lazy/chunks/chunk-VWVZGQE2.js +1 -0
- package/dist/browser-lazy/chunks/chunk-X2UYKWKM.js +4 -0
- package/dist/browser-lazy/chunks/chunk-YCEICNM6.js +1 -0
- package/dist/browser-lazy/chunks/chunk-Z3FDIVLN.js +20 -0
- package/dist/browser-lazy/chunks/class-5QA4SCTS.js +13 -0
- package/dist/browser-lazy/chunks/decode-63UIZGD2.js +1 -0
- package/dist/browser-lazy/chunks/elk.bundled-L4CADV5W.js +24 -0
- package/dist/browser-lazy/chunks/er-7ZSKGN7Y.js +11 -0
- package/dist/browser-lazy/chunks/eventmodeling-2BPLHWRN.js +19 -0
- package/dist/browser-lazy/chunks/flowchart-NEIMZTB5.js +4 -0
- package/dist/browser-lazy/chunks/forest-implementation-AEP24AIP.js +1 -0
- package/dist/browser-lazy/chunks/gantt-RDPIFYAF.js +11 -0
- package/dist/browser-lazy/chunks/gitgraph-N4Y5RYB7.js +9 -0
- package/dist/browser-lazy/chunks/ishikawa-LD3YBDJN.js +6 -0
- package/dist/browser-lazy/chunks/journey-6YQR5DJX.js +16 -0
- package/dist/browser-lazy/chunks/kanban-PLMJ7NBW.js +20 -0
- package/dist/browser-lazy/chunks/mermaid-yaml-runtime-QVYX4EWK.js +136 -0
- package/dist/browser-lazy/chunks/mindmap-K2UBFO3Y.js +12 -0
- package/dist/browser-lazy/chunks/packet-CUW4QY6Y.js +7 -0
- package/dist/browser-lazy/chunks/pie-7F7UUCG3.js +15 -0
- package/dist/browser-lazy/chunks/quadrant-TOONO2WC.js +10 -0
- package/dist/browser-lazy/chunks/radar-J6JVWVAX.js +16 -0
- package/dist/browser-lazy/chunks/render-core-BZOM3K7D.js +3 -0
- package/dist/browser-lazy/chunks/requirement-CMAKDJPO.js +19 -0
- package/dist/browser-lazy/chunks/sankey-AWXQEP3F.js +13 -0
- package/dist/browser-lazy/chunks/sequence-Q2RJRB4L.js +5 -0
- package/dist/browser-lazy/chunks/state-WRBFQEDX.js +4 -0
- package/dist/browser-lazy/chunks/timeline-D2KILFXM.js +6 -0
- package/dist/browser-lazy/chunks/treemap-N3VYX5D4.js +6 -0
- package/dist/browser-lazy/chunks/xychart-G73OGK66.js +16 -0
- package/dist/browser-lazy/chunks/zenuml-H4BXNYXR.js +16 -0
- package/dist/browser-lazy/index.d.ts +544 -275
- package/dist/browser-lazy/index.js +1 -1
- package/dist/browser.global.js +802 -565
- package/dist/chunk-3LGLPG33.js +2 -0
- package/dist/chunk-7CRDX2QR.js +2 -0
- package/dist/chunk-7PPW2BMO.js +2 -0
- package/dist/chunk-DQDKA5ND.js +2 -0
- package/dist/chunk-EHCMJUMD.js +52 -0
- package/dist/chunk-GVCHLSHH.js +4 -0
- package/dist/chunk-H3NCS2XZ.js +19 -0
- package/dist/chunk-JZOJ4YGS.js +201 -0
- package/dist/chunk-MKE7GNYU.js +146 -0
- package/dist/chunk-NKNFOREZ.js +2 -0
- package/dist/chunk-O7H2UX5K.js +2 -0
- package/dist/chunk-OMY6NRQD.js +58 -0
- package/dist/chunk-UA234O4M.js +4 -0
- package/dist/chunk-VUFVLGTH.js +2 -0
- package/dist/chunk-XU5LPD2D.js +2 -0
- package/dist/cli-YGGTJZH7.js +226 -0
- package/dist/elk-constructor.js +2 -0
- package/dist/elk-constructor.node.js +11 -0
- package/dist/index-EeXqJXr5.d.ts +1223 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +1 -334
- package/dist/jsonl-RPJY6YWO.js +2 -0
- package/dist/mcp-cli-63DYXTVD.js +2 -0
- package/dist/{index-BGA_-6LV.d.ts → paint-certification-6rwQjIv_.d.ts} +5283 -6173
- package/dist/server-5NEOHOFS.js +524 -0
- package/dist/svg-styles-BdnoM7AT.d.ts +724 -0
- package/dist/svg-styles.d.ts +1 -0
- package/dist/svg-styles.js +2 -0
- package/dist/svg.d.ts +13 -0
- package/dist/svg.js +2 -0
- package/dist/types-BcS52Mjt.d.ts +1360 -0
- package/dist/zenuml/chunks/appearance-UOQ5KA6O.js +1 -0
- package/dist/zenuml/chunks/builtin-backends-KDKE7YHO.js +12 -0
- package/dist/zenuml/chunks/chunk-42DXZ5C6.js +4 -0
- package/dist/zenuml/chunks/chunk-7TVYPTDW.js +1 -0
- package/dist/zenuml/chunks/chunk-EVPSMEKN.js +1 -0
- package/dist/zenuml/chunks/chunk-OXQWRSBM.js +20 -0
- package/dist/zenuml/chunks/chunk-QWX77U7G.js +2 -0
- package/dist/zenuml/chunks/chunk-RLJEI7YN.js +29 -0
- package/dist/zenuml/chunks/chunk-RZ6XK5CD.js +29 -0
- package/dist/zenuml/chunks/decode-BWERFDGK.js +1 -0
- package/dist/zenuml/chunks/mermaid-yaml-runtime-KZVU74WU.js +136 -0
- package/dist/zenuml/chunks/render-core-V5RQ737O.js +3 -0
- package/dist/zenuml/chunks/zenuml-EA2ZFRUX.js +20 -0
- package/dist/zenuml-frame.global.js +3626 -0
- package/dist/zenuml.d.ts +83 -0
- package/dist/zenuml.js +1 -0
- package/docs/MCP-DIRECTORY-LISTINGS.md +5 -1
- package/docs/README.md +59 -103
- package/docs/agent-api-cookbook.md +26 -16
- package/docs/agent-mutation-policy.md +86 -15
- package/docs/agent-workflow-examples.md +1 -1
- package/docs/api-advanced.md +385 -0
- package/docs/api.md +320 -366
- package/docs/ascii.md +40 -4
- package/docs/browser.md +46 -7
- package/docs/choosing-a-diagram.md +148 -0
- package/docs/code-mode-impact.md +1 -0
- package/docs/comparison.md +244 -28
- package/docs/computational-aesthetics-prototype-plan.md +10 -10
- package/docs/config.md +60 -2
- package/docs/custom-fonts.md +78 -21
- package/docs/diagram-families.md +160 -10
- package/docs/eventmodeling-and-zenuml.md +165 -0
- package/docs/features.md +21 -19
- package/docs/fork-differences.md +105 -32
- package/docs/getting-started.md +56 -51
- package/docs/layout-certification.md +126 -0
- package/docs/mcp-code-mode-rationale.md +20 -12
- package/docs/mcp-http-transport.md +14 -8
- package/docs/quality.md +145 -15
- package/docs/react.md +76 -31
- package/docs/style-authoring.md +23 -11
- package/docs/svg-semantic-contract.md +104 -4
- package/docs/testing-strategy.md +684 -126
- package/docs/theming.md +27 -8
- package/examples/styles/readme-hero.md +25 -0
- package/examples/styles/readme-hero.mmd +13 -0
- package/examples/styles/readme-hero.style.json +7 -0
- package/package.json +114 -57
- package/server.json +2 -2
- package/skills/agentic-mermaid-diagram-workflow/SKILL.md +26 -8
- package/skills/agentic-mermaid-diagram-workflow/references/cli.md +13 -3
- package/skills/agentic-mermaid-diagram-workflow/references/code-mode.md +2 -1
- package/skills/agentic-mermaid-diagram-workflow/references/flowchart.md +9 -6
- package/skills/agentic-mermaid-diagram-workflow/references/hosted-mcp.md +1 -0
- package/skills/agentic-mermaid-diagram-workflow/references/sequence.md +4 -3
- package/skills/agentic-mermaid-diagram-workflow/references/timeline.md +7 -6
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/agentflow.md +574 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/architecture.md +10 -2
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/c4.md +18 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/classDiagram.md +123 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/cynefin.md +6 -1
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/entityRelationshipDiagram.md +129 -9
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/eventmodeling.md +22 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/flowchart.md +188 -60
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/gitgraph.md +13 -7
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/mindmap.md +110 -1
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/packet.md +38 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/requirementDiagram.md +115 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/sequenceDiagram.md +101 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/stateDiagram.md +87 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/swimlanes.md +105 -2
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/timeline.md +12 -6
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/usecase.md +953 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/venn.md +77 -0
- package/skills/agentic-mermaid-diagram-workflow/references/upstream/xyChart.md +1 -1
- package/dist/browser-lazy/chunks/architecture-KTHE2HX3.js +0 -31
- package/dist/browser-lazy/chunks/chunk-2XCPFAD5.js +0 -46
- package/dist/browser-lazy/chunks/chunk-3H4F7RBT.js +0 -1
- package/dist/browser-lazy/chunks/chunk-4EVLW2NJ.js +0 -1
- package/dist/browser-lazy/chunks/chunk-5Q4S74UO.js +0 -1
- package/dist/browser-lazy/chunks/chunk-6OAPWSDO.js +0 -1
- package/dist/browser-lazy/chunks/chunk-A7L4WWVW.js +0 -143
- package/dist/browser-lazy/chunks/chunk-C7FJO2I3.js +0 -4
- package/dist/browser-lazy/chunks/chunk-D3XXDKIO.js +0 -1
- package/dist/browser-lazy/chunks/chunk-DXA5WL7H.js +0 -4
- package/dist/browser-lazy/chunks/chunk-EPFMQPXX.js +0 -1
- package/dist/browser-lazy/chunks/chunk-FFOHLPDA.js +0 -2
- package/dist/browser-lazy/chunks/chunk-FLD63DXE.js +0 -2
- package/dist/browser-lazy/chunks/chunk-G6OLSHRG.js +0 -7
- package/dist/browser-lazy/chunks/chunk-GRXCKTHX.js +0 -0
- package/dist/browser-lazy/chunks/chunk-I6VE56S7.js +0 -1
- package/dist/browser-lazy/chunks/chunk-KJVNXJ5Y.js +0 -1
- package/dist/browser-lazy/chunks/chunk-L227EPFP.js +0 -11
- package/dist/browser-lazy/chunks/chunk-LNIHDJSF.js +0 -1
- package/dist/browser-lazy/chunks/chunk-M6BT2HIP.js +0 -1
- package/dist/browser-lazy/chunks/chunk-NZRUMODH.js +0 -1
- package/dist/browser-lazy/chunks/chunk-OFRMKQA6.js +0 -1
- package/dist/browser-lazy/chunks/chunk-P7HMSKHJ.js +0 -1
- package/dist/browser-lazy/chunks/chunk-PXKL3O6H.js +0 -1
- package/dist/browser-lazy/chunks/chunk-PZEWZT35.js +0 -1
- package/dist/browser-lazy/chunks/chunk-STQRDZ67.js +0 -1
- package/dist/browser-lazy/chunks/chunk-SUFMSWTX.js +0 -1
- package/dist/browser-lazy/chunks/chunk-T7IJ6V4B.js +0 -3
- package/dist/browser-lazy/chunks/chunk-UAEZO5VL.js +0 -1
- package/dist/browser-lazy/chunks/chunk-WEUWIFG3.js +0 -1
- package/dist/browser-lazy/chunks/chunk-X64T74C5.js +0 -24
- package/dist/browser-lazy/chunks/class-F7R6TJ73.js +0 -9
- package/dist/browser-lazy/chunks/er-BDK7CM5L.js +0 -9
- package/dist/browser-lazy/chunks/flowchart-KFU6XV7S.js +0 -4
- package/dist/browser-lazy/chunks/gantt-I64VVDSP.js +0 -28
- package/dist/browser-lazy/chunks/gitgraph-EDUVJ5IJ.js +0 -8
- package/dist/browser-lazy/chunks/journey-TLO2RNM3.js +0 -40
- package/dist/browser-lazy/chunks/mindmap-OJCNDYPM.js +0 -9
- package/dist/browser-lazy/chunks/pie-HVG6XO7K.js +0 -19
- package/dist/browser-lazy/chunks/quadrant-U6S2L4MJ.js +0 -24
- package/dist/browser-lazy/chunks/radar-ZDLOBTVG.js +0 -32
- package/dist/browser-lazy/chunks/render-core-Y2DFNMQG.js +0 -12
- package/dist/browser-lazy/chunks/sequence-Z4WFS3VB.js +0 -12
- package/dist/browser-lazy/chunks/state-2HV2YGN3.js +0 -4
- package/dist/browser-lazy/chunks/timeline-XM4UFPOC.js +0 -20
- package/dist/browser-lazy/chunks/xychart-7JDHWTQY.js +0 -36
- package/dist/chunk-GGXCNCNA.js +0 -4118
- package/dist/chunk-IVD4NXNE.js +0 -615
- package/dist/chunk-JDMRPUAG.js +0 -37
- package/dist/chunk-JWAAW3FH.js +0 -149
- package/dist/chunk-LCGBT32P.js +0 -62036
- package/dist/chunk-RWMZRUIC.js +0 -4715
- package/dist/mcp-cli-4MLKC3ZH.js +0 -17
- package/docs/mutation-testing.md +0 -285
package/docs/testing-strategy.md
CHANGED
|
@@ -7,30 +7,66 @@ than it looks, this document says so — an honest map is more useful than a
|
|
|
7
7
|
flattering one.
|
|
8
8
|
|
|
9
9
|
For the *definition* of "good looking" and the determinism guarantees, see
|
|
10
|
-
[`quality.md`](./quality.md). For
|
|
11
|
-
[`mutation-testing.md`](./mutation-testing.md). For the layout/visual
|
|
10
|
+
[`quality.md`](./quality.md). For the layout/visual
|
|
12
11
|
contracts, see [`layout-characterization/README.md`](./layout-characterization/README.md).
|
|
13
|
-
The
|
|
14
|
-
|
|
15
|
-
[
|
|
16
|
-
its
|
|
17
|
-
`eval/test-portfolio/`.
|
|
12
|
+
The complexity-aware and registry-derived interaction portfolio is implemented
|
|
13
|
+
in `src/__tests__/render-conformance-plan.test.ts` and its helpers. The
|
|
14
|
+
[July migration record](./project/archive/complexity-aware-test-portfolio-plan.md)
|
|
15
|
+
is historical; its removed reports and receipts are not current requirements.
|
|
18
16
|
|
|
19
17
|
## Local CI parity
|
|
20
18
|
|
|
19
|
+
Test-order and fresh-process sweeps are manual diagnostics for changes to shared
|
|
20
|
+
fixtures or module state. Replay a focused failure with
|
|
21
|
+
`AM_TEST_ORDER_SEED=<seed> bun run scripts/ci/find-test-order.ts shuffled <files>`
|
|
22
|
+
or replace `shuffled` with `fresh-process`. No scheduled whole-suite order sweep
|
|
23
|
+
or issue collector runs. Each test must initialize its own reference fixture;
|
|
24
|
+
another test's initialization is not a prerequisite.
|
|
25
|
+
|
|
21
26
|
Run `bun run quality:check` to execute the complete GitHub **Quality gates**
|
|
22
27
|
job locally. The command installs the frozen dependency graph and then runs
|
|
23
|
-
the dependency audit, font
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
the dependency audit, the font-subset, lazy browser-family catalog, and website
|
|
29
|
+
regeneration checks, the whole-corpus audit, lint,
|
|
30
|
+
repository-wide typechecking, and hero freshness (the
|
|
31
|
+
list is `QUALITY_CHECKS` in `scripts/ci/quality-gates.ts`). The workflow calls
|
|
32
|
+
this same entry point, so the local list and CI list cannot diverge.
|
|
33
|
+
|
|
34
|
+
The E2E lanes build their own inputs and start alongside unit tests; only the
|
|
35
|
+
final `CI complete` gate waits for every lane. Package manifest and export/type
|
|
36
|
+
checks run after the Node 24 tarball consumer has built the package, rather
|
|
37
|
+
than rebuilding all browser artifacts in a unit shard. Unit shards build only
|
|
38
|
+
the Node bundle. Browser contracts run in two disjoint file shards, retaining
|
|
39
|
+
one test process per file. Payload measurement has its own lane: each site
|
|
40
|
+
build supplies the lazy bundle for comparison, so neither head nor base needs
|
|
41
|
+
a second full package build. Generic PR render evidence is generated on demand
|
|
42
|
+
with `scripts/pr-assets/meaning-preservation-evidence.ts BASE_SHA HEAD_SHA OUT_DIR`;
|
|
43
|
+
automatic rendering of the same fixtures is no longer appended to every PR.
|
|
44
|
+
|
|
45
|
+
Both tarball-consumer lanes also execute the Getting Started commands from the
|
|
46
|
+
built website's shell blocks and `docs/getting-started.md`'s bash fences in fresh
|
|
47
|
+
consumer directories. Only the registry package spec is replaced with the packed
|
|
48
|
+
tarball; the guide's separate repository-development alternative is excluded.
|
|
49
|
+
The gate checks verification JSON, parsed SVG and PNG files, terminal output,
|
|
50
|
+
style discovery, and stdio MCP initialization/tool discovery for both the CLI
|
|
51
|
+
command and the version-pinned config card. Failures name the page, step, and
|
|
52
|
+
copied command. Run it locally with
|
|
53
|
+
`cd e2e && bun test tarball-consumer-fuzz.e2e.test.ts --timeout 600000`.
|
|
54
|
+
|
|
55
|
+
Committed galleries and before/after sheets are dated review snapshots, not
|
|
56
|
+
gates: regenerate one with its `gallery:*` command when the rendering is
|
|
57
|
+
reviewed again. Where an evidence script carried a real assertion, the unit
|
|
58
|
+
suite now runs it against current code (for example the issue #87 link-rank
|
|
59
|
+
gaps and the Section B sheet, which is regenerated in memory and
|
|
60
|
+
byte-compared). Generated runtime modules are the narrow committed exception
|
|
61
|
+
when production code imports them. Other derived discovery views are generated
|
|
62
|
+
at delivery: `am llms-txt` and the website use current registries, while the
|
|
63
|
+
repository's authored `llms.txt` points readers to those sources. A second
|
|
64
|
+
committed capability roster and its snapshot-freshness test are unnecessary.
|
|
65
|
+
There are no input-hash receipts.
|
|
66
|
+
|
|
67
|
+
The sketch prototype remains an on-demand research tool (`bun run sketch:check`).
|
|
68
|
+
Production styling is exercised by the Scene/backend and render-conformance
|
|
69
|
+
tests; the browser label-contrast check renders the shipped looks.
|
|
34
70
|
|
|
35
71
|
## The central problem: this is a partly non-testable program
|
|
36
72
|
|
|
@@ -61,7 +97,6 @@ audit-clean").
|
|
|
61
97
|
| **Derived (golden)** | Output matches a previously-blessed artifact | ASCII goldens, SVG snapshots, contact sheets, screenshot baselines |
|
|
62
98
|
| **Derived (differential)** | Our output agrees with an external reference corpus | mermaid-docs corpus, MermaidSeqBench, upstream-suite bench |
|
|
63
99
|
| **Metamorphic** | Related inputs produce related outputs (no ground truth needed) | round-trip idempotence, cross-process/cross-runtime determinism |
|
|
64
|
-
| **Pseudo / fault sensitivity** | Selected seeded faults make the intended tests fail | incremental Stryker gate, sabotage suite |
|
|
65
100
|
| **Heuristic / perceptual** | Geometry falls inside human-plausible bounds | `measureQuality`/`checkQuality`, ugly-detector, layout rubric, heuristic-tracker |
|
|
66
101
|
| **Human / model** | Subjective quality on the axis nothing else covers | LLM-as-judge (periodic), manual visual review |
|
|
67
102
|
|
|
@@ -70,16 +105,28 @@ whether it gates per-PR, and what it does *not* prove.
|
|
|
70
105
|
|
|
71
106
|
## 1. Specified oracles — structural correctness
|
|
72
107
|
|
|
73
|
-
**Tier-1 `verify`** is the non-negotiable structural gate:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
108
|
+
**Tier-1 `verify`** is the non-negotiable structural gate: none of
|
|
109
|
+
<!-- BEGIN GENERATED: warning-codes:structural -->`EMPTY_DIAGRAM`, `EDGE_MISANCHORED`, `OFF_CANVAS`, `GROUP_BREACH`, `UNKNOWN_SHAPE`, `LABEL_OVERFLOW`, `UNRESOLVABLE_SCHEDULE`, `RENDER_FAILED`, `INTERNAL_ERROR`<!-- END GENERATED: warning-codes:structural --> fires. It is reliable and universal across
|
|
110
|
+
families. Geometric and lint findings use their canonical severity: most are
|
|
111
|
+
advisory, while measured `CONTENT_OCCLUDED` and an explicit error policy fail verification.
|
|
77
112
|
|
|
78
113
|
Alongside it sit the **contract gates**: `am capabilities --json` schema
|
|
79
|
-
tests, `
|
|
80
|
-
citizenship
|
|
81
|
-
help, and
|
|
82
|
-
like code
|
|
114
|
+
tests, the `agent-doc-sync` tests, and the behavioural
|
|
115
|
+
diagram-family citizenship loop. For an agent-native product the docs, schemas, CLI
|
|
116
|
+
help, and live generated discovery *are* runtime surfaces (Loop 14), so their
|
|
117
|
+
behavior is tested like code. The repository `llms.txt` is an authored pointer
|
|
118
|
+
to those live surfaces.
|
|
119
|
+
|
|
120
|
+
Citizenship requires a small smoke input and a domain-rich scenario for every
|
|
121
|
+
registered built-in family. Required witnesses in the existing closed
|
|
122
|
+
`FAMILY_CONFORMANCE_PROFILES` record specify independent semantic expectations,
|
|
123
|
+
visible labels and a meaningful typed edit. Those expectations must survive
|
|
124
|
+
canonical export/reload and editing, alongside verification, graphical/terminal
|
|
125
|
+
rendering, layout regions and uncached determinism. This closes the former gap
|
|
126
|
+
where a minimal count fixture passed citizenship while richer inputs appeared
|
|
127
|
+
only in the separate rendering portfolio. Source length and node counts do not
|
|
128
|
+
establish representativeness; the interacting domain features do. See the
|
|
129
|
+
[citizenship review contract](./contributing/diagram-family-citizenship.md#representative-examples-are-mandatory).
|
|
83
130
|
|
|
84
131
|
**Runs:** every PR (`bun run test`, including the canonical 30-second per-test budget).
|
|
85
132
|
**Does not prove:** that the diagram is *visually* good. `verify.ok` is
|
|
@@ -95,25 +142,24 @@ independent spec:
|
|
|
95
142
|
- **SVG snapshots** and **contact sheets** — per-family rendered output.
|
|
96
143
|
- **Screenshot baselines** — `e2e/screenshots/baseline-*.png`, diffed against
|
|
97
144
|
fresh Playwright renders with a per-channel threshold in `e2e/browser.test.ts`.
|
|
98
|
-
- **
|
|
99
|
-
|
|
145
|
+
- **Golden review** — each PR description lists every changed golden under
|
|
146
|
+
`src/__tests__/testdata/` and why it changed, for reviewer judgment.
|
|
100
147
|
|
|
101
148
|
**Runs:** ASCII/SVG goldens per PR. The browser/screenshot e2e suite also runs
|
|
102
|
-
per PR —
|
|
149
|
+
per PR — the `e2e` matrix in `ci.yml` runs alongside unit and quality checks, including
|
|
103
150
|
an installed-tarball consumer run at the advertised Node 22 floor. Its
|
|
104
|
-
browser
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
before
|
|
151
|
+
browser shards retain Chromium/Firefox/WebKit bundle checks, `browser.test.ts`
|
|
152
|
+
(screenshot diff), security contracts, and the explicitly enabled
|
|
153
|
+
theme/style/accessibility suites. The site-only shard needs Chromium. Each
|
|
154
|
+
shard builds the gitignored `website/public` tree once before its contracts serve it (`browser.test.ts` builds only the separate root
|
|
108
155
|
`editor.html`). Each browser contract file then runs in its own Bun process so its
|
|
109
156
|
Chromium/server hooks cannot overlap and exhaust a constrained hosted runner. The
|
|
110
157
|
package and CI both invoke `e2e/run-browser-contracts.ts`, whose canonical file
|
|
111
158
|
list also fails if any contract executes zero positive tests, while independent
|
|
112
159
|
lanes run the CLI/single-binary, dist-artifact, and tarball-consumer suites.
|
|
113
|
-
Broad contact-sheet rendering is periodic/triggered rather than a per-PR sweep
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
and remains hash-bound when recorded, but it is advisory rather than a package-publication gate.
|
|
160
|
+
Broad contact-sheet rendering is periodic/triggered rather than a per-PR sweep.
|
|
161
|
+
Human review is recommended for visual releases, but it is advisory rather than
|
|
162
|
+
a package-publication gate.
|
|
117
163
|
**Does not prove:** that a *changed* golden is an improvement — only that
|
|
118
164
|
change was noticed. Judging the change still needs a human or the
|
|
119
165
|
before/after harness (`eval/layout-compare`).
|
|
@@ -131,34 +177,133 @@ Style registries and mandatory family conformance profiles generate:
|
|
|
131
177
|
palette-sensitive role, external-reference and contact-sheet obligations;
|
|
132
178
|
- a separate SVG/PNG/ASCII/Unicode portfolio with every-family Unicode stress.
|
|
133
179
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
180
|
+
Each family profile declares its automatic-outline roles or explains why they
|
|
181
|
+
do not apply. The SVG portfolio binds those Scene obligations to the actual
|
|
182
|
+
emitted primitives, including class-styled swatches and sketched outline
|
|
183
|
+
siblings. It checks positive visible ink and 3:1 source-paint contrast against
|
|
184
|
+
known opaque pages, preserves declared opacity, and requires every applicable
|
|
185
|
+
family/role/backend to have a witness. Representative looks without explicit
|
|
186
|
+
border roles exercise all six strata, including the default crisp look.
|
|
187
|
+
Deliberate role colors, `none`, and authored zero-width borders have separate
|
|
188
|
+
preservation checks; active family paint aliases are treated as overrides.
|
|
189
|
+
These checks do not certify every antialiased pixel or an unknown transparent
|
|
190
|
+
host background.
|
|
191
|
+
|
|
192
|
+
The planner and tuple-verifier helpers describe the interaction obligations;
|
|
193
|
+
the retained tests exercise family-profile closure, resolver behavior,
|
|
194
|
+
rendered output and determinism. Do not infer current enforcement merely from
|
|
195
|
+
the existence of a helper or from the historical plan's removed sabotage suite.
|
|
196
|
+
A new `DiagramKind` requires typed profiles and generators, including an
|
|
197
|
+
outline declaration. Missing fixture files or eval-corpus examples fail when
|
|
198
|
+
the conformance inputs are constructed.
|
|
199
|
+
|
|
200
|
+
**Runs:** executable conformance runs per PR. The
|
|
141
201
|
larger citizenship/interaction/outlier contact sheets run when visual inputs
|
|
142
202
|
change, during periodic design review, or before release.
|
|
143
203
|
**Does not prove:** an unrendered three-way family/Look/Palette combination is
|
|
144
|
-
beautiful.
|
|
145
|
-
|
|
204
|
+
beautiful. Inspect the current planner, verifier and actual assertions for the
|
|
205
|
+
retained obligations; there is no published candidate report to serve as a gate.
|
|
146
206
|
|
|
147
207
|
## 3. Derived oracles — differential corpora
|
|
148
208
|
|
|
149
209
|
The strongest defense against our own blind spots is testing against
|
|
150
210
|
sources we did not write:
|
|
151
211
|
|
|
212
|
+
- **Modern semantic gate** (`bun run test:mermaid-modern`, after
|
|
213
|
+
`bun run reference:mermaid` installs the pinned source and reference locally)
|
|
214
|
+
— selected assertions from the current Mermaid policy pin, with the exact
|
|
215
|
+
source commit and independently installed parser admitted before execution. Repeated subgraph declarations
|
|
216
|
+
must retain both member identities and the first title in public IR, typed
|
|
217
|
+
editing, positioned layout and SVG. Repeated class assignments must survive
|
|
218
|
+
typed rename and serialization in author order. Two official XYChart
|
|
219
|
+
examples must serialize to valid Mermaid with their titles, axes, values and
|
|
220
|
+
point labels intact. Reference projections contain those semantic fields;
|
|
221
|
+
Class arrow markers, metadata-shaped Flowchart named edges, quoted Mindmap
|
|
222
|
+
delimiters and reserved Quadrant axis text also have reviewed writer
|
|
223
|
+
assertions. These preservation assertions are complemented by reviewed seeded writer
|
|
224
|
+
regressions and operation checks: each native family's canonical example plus focused
|
|
225
|
+
witnesses compares selected ordered builder operands against the real
|
|
226
|
+
reference. The operation scopes are declared per family and do not imply
|
|
227
|
+
equality of all internal calls.
|
|
228
|
+
The checks do not compare Mermaid geometry or styling. Existing State, Architecture
|
|
229
|
+
and Sequence syntax gaps are recorded as diagnostics, not permanent expected
|
|
230
|
+
failures. This gate has an explicit local command and the dedicated **Modern
|
|
231
|
+
Mermaid semantic compatibility** workflow is a required reusable lane of canonical CI
|
|
232
|
+
for every PR and main revision, including reference policy and corpus changes; it does not change the normal product
|
|
233
|
+
compatibility pin or development dependency.
|
|
234
|
+
The job also publishes all-family documentation outcomes and 100 seeded
|
|
235
|
+
mutations as a seven-day diagnostic artifact. Those counts do not gate
|
|
236
|
+
unsupported families or expand the reviewed assertions.
|
|
237
|
+
|
|
238
|
+
**All-family grammar assessment** (`bun run eval:mermaid-grammar`) uses the
|
|
239
|
+
actual selected Mermaid 12+ grammar for every core family, including families
|
|
240
|
+
without native Agentic support. It records lexer tokens, Jison model calls or
|
|
241
|
+
Langium/Chevrotain syntax trees and native renderer-parser admission. Hooks
|
|
242
|
+
inside all 17 native parsers record consumed classified statements and actual
|
|
243
|
+
semantic writes, with values copied before later mutation; Flowchart also
|
|
244
|
+
records its consumed compound fragments. Every observed native attempt has
|
|
245
|
+
an unobserved acceptance/error/model control. A changed result fails the
|
|
246
|
+
assessment as an instrumentation failure.
|
|
247
|
+
|
|
248
|
+
Independent per-family adapters compare selected native semantic fields
|
|
249
|
+
against actual reference getters/actions/AST, retaining logical IDs, marker
|
|
250
|
+
sides, labels and parents where applicable. Additional adapters compare
|
|
251
|
+
ordered operands from actual native mutation events and actual reference
|
|
252
|
+
calls, expanding recorded batch arguments rather than returned IR. These
|
|
253
|
+
arrays are never sorted. Each case declares the compared operation scopes
|
|
254
|
+
and counts omitted kinds, methods and batch operands; empty scoped traces
|
|
255
|
+
are unavailable evidence. Stable-getter and original-to-serialized reference
|
|
256
|
+
comparisons remain separate. Parent fields are retained, and generated-looking
|
|
257
|
+
authored strings are not globally rewritten. None of these selected scopes
|
|
258
|
+
proves full semantic fidelity. Manual runs default to 5,000
|
|
259
|
+
seeded mutations per family; required CI uses 100 per family at seed 7.
|
|
260
|
+
The separate weekly contract-discovery job samples at a recorded fresh seed
|
|
261
|
+
with the bounds described below. Mutations draw on the
|
|
262
|
+
corpus's own token images and on fixed lexer-boundary fragments
|
|
263
|
+
(`grammar-fragments.ts`). Each run counts **silent reads** per family (pinned
|
|
264
|
+
Mermaid rejects, ours reads, verify names no problem) and lists them reduced;
|
|
265
|
+
weekly discovery retains confirmed public-contract candidates for human
|
|
266
|
+
review without opening issues. Per-input JSONL and detailed counterexamples are
|
|
267
|
+
ignored build artifacts. This measures native admission and reference grammar
|
|
268
|
+
round trips as well as the scoped native semantics/operations. Agentic has
|
|
269
|
+
no homologous Mermaid token/`yy` interface, so exact protocol equality
|
|
270
|
+
remains unavailable; the actual native units are labelled separately. Exact reference stream differences
|
|
271
|
+
need semantic review and are not conflated with lost content or layout.
|
|
272
|
+
|
|
152
273
|
- **mermaid-docs corpus** (271 entries) — harvested from Mermaid's own
|
|
153
274
|
documentation; gates parse, verify, and round-trip.
|
|
154
275
|
- **MermaidSeqBench** (132 IBM-curated sequence diagrams) — parse rate,
|
|
155
276
|
structured-vs-opaque split, verify rate, round-trip stability.
|
|
156
|
-
- **upstream-suite bench** (`eval/mermaid-upstream-suite-bench/`,
|
|
157
|
-
executable cases /
|
|
277
|
+
- **upstream-suite bench** (`eval/mermaid-upstream-suite-bench/`, 742
|
|
278
|
+
executable cases / 752 imported blocks from pinned upstream commits) — with
|
|
158
279
|
a **ratchet** (`ratchet.json`) that fails the build if coverage drops or
|
|
159
|
-
per-family local-gap budgets grow.
|
|
160
|
-
|
|
161
|
-
|
|
280
|
+
per-family local-gap budgets grow. These imported corpora retain the source
|
|
281
|
+
revisions recorded in their manifests. Mindmap/GitGraph retain their
|
|
282
|
+
`f3dea583…` source revision and account for all 26/69 official spec blocks in
|
|
283
|
+
a dedicated executable oracle; that historical corpus pin is separate from
|
|
284
|
+
the current writing/reference target.
|
|
285
|
+
- **Official-fence corpus** (`official-fence-corpus.test.ts`) — every one of
|
|
286
|
+
the Mermaid syntax fences on the pinned upstream pages named by the
|
|
287
|
+
upstream policy. The fences of rendered families must parse to a
|
|
288
|
+
structured body, verify, render, and keep their structural counts through
|
|
289
|
+
serialize → re-parse; the fences of unrendered families must be
|
|
290
|
+
diagnosed `UNSUPPORTED_FAMILY` with their bytes preserved. Deviations live in
|
|
291
|
+
one small expectations table (`id [ outcomes ] # reason`); a new deviation
|
|
292
|
+
and an unexpected pass both fail, so the table cannot go stale.
|
|
293
|
+
- **Grammar-based differentials** (`property-upstream-flowchart.test.ts`,
|
|
294
|
+
`property-upstream-sequence.test.ts`) — recursive `fc.letrec` grammars
|
|
295
|
+
generate sources that pinned upstream Mermaid 12.2.0 must accept; ours must
|
|
296
|
+
accept them too, agree on node/edge/participant counts, shapes, labels, and
|
|
297
|
+
arrows, and round-trip. A long-lived upstream worker
|
|
298
|
+
(`helpers/upstream-mermaid.ts`) lets async properties shrink. Known
|
|
299
|
+
divergences are pinned as explicit cases that fail once fixed.
|
|
300
|
+
The worker runs Node (CI uses Node 24) with development-only jsdom 26.1.0,
|
|
301
|
+
public preprocessing and actual DOMPurify; no sanitizer is replaced. The
|
|
302
|
+
Flowchart grammar property observes authored label operands at live builder
|
|
303
|
+
calls while still invoking each original method. Sanitized HTML can lose
|
|
304
|
+
those tokens, so that property is a grammar contract rather than a claim of
|
|
305
|
+
identical sanitized DB text. Selected modern tests independently inspect
|
|
306
|
+
public runtime values. Snapshots retain parent fields and explicit cycles.
|
|
162
307
|
|
|
163
308
|
These exist because our hand-written fixtures encode what we already knew
|
|
164
309
|
the parser modeled. Upstream examples are "adversarial in exactly the
|
|
@@ -166,15 +311,32 @@ right way" — they encode what real sources contain (wrapper-fidelity
|
|
|
166
311
|
lesson). The `@{shape}` silent-loss and ER `}o` bugs both escaped 2,200+
|
|
167
312
|
self-authored tests and were caught only by docs-derived sources.
|
|
168
313
|
|
|
169
|
-
|
|
314
|
+
Harvesting an upstream source is different from porting its assertions. A
|
|
315
|
+
fixture count recorded from our own implementation protects existing behavior;
|
|
316
|
+
it does not independently establish agreement with Mermaid's semantic model.
|
|
317
|
+
The selected modern assertions use reviewed upstream expectations and narrow
|
|
318
|
+
reference projections to close that gap for the covered behavior.
|
|
319
|
+
|
|
320
|
+
**Runs:** every PR (corpus + seqbench + upstream-suite ratchet); a separate CI
|
|
321
|
+
job installs the pinned modern reference for the selected semantic gate when
|
|
322
|
+
its code inputs change. Its broader
|
|
323
|
+
[`eval/mermaid-modern-compat`](../eval/mermaid-modern-compat/README.md) runner
|
|
324
|
+
reports documentation coverage across every modern core family, including
|
|
325
|
+
unsupported families. Optional extracted spec literals and seeded mutations
|
|
326
|
+
remain diagnostic seed corpora. Extracted test titles, CSS fragments and empty
|
|
327
|
+
scaffolds are not feature support or ported upstream assertions. Raw getter
|
|
328
|
+
differences are drift candidates requiring review; only the narrow assertions
|
|
329
|
+
above fail the semantic gate.
|
|
170
330
|
**Faithfulness count-oracle:** the corpus gate now also asserts that the
|
|
171
331
|
structured `{nodes, edges, groups}` tally survives a parse → serialize →
|
|
172
332
|
re-parse cycle for **every** renderable family
|
|
173
333
|
(`eval/shared/structural-count.ts`, gated in `agent-mermaid-corpus.test.ts`).
|
|
174
|
-
Round-trip *byte*-stability only proves serialize∘parse is idempotent
|
|
175
|
-
count check
|
|
176
|
-
|
|
177
|
-
|
|
334
|
+
Round-trip *byte*-stability only proves serialize∘parse is idempotent. The
|
|
335
|
+
count check detects changes in the number of nodes, edges and groups, including
|
|
336
|
+
the ER `}o` class of bug. It cannot establish that identities, labels, class
|
|
337
|
+
assignments or group membership remain correct, or that SVG displays every
|
|
338
|
+
parsed element. The modern semantic gate checks selected identity and content
|
|
339
|
+
contracts through independent upstream expectations and actual output.
|
|
178
340
|
|
|
179
341
|
## 4. Metamorphic oracles — relations instead of ground truth
|
|
180
342
|
|
|
@@ -197,6 +359,17 @@ must agree." This sidesteps the oracle problem without a human:
|
|
|
197
359
|
Statement-permutation invariance is deliberately *not* asserted — source
|
|
198
360
|
order is a stated design property, so permuting statements may legitimately
|
|
199
361
|
change geometry.
|
|
362
|
+
- **Colour and source relations** — `property-invariance-colour.test.ts`:
|
|
363
|
+
palettes, colour options, named themes, theme colour variables, and family
|
|
364
|
+
colour config never move geometry (layout and paint-free SVG, via the shared
|
|
365
|
+
`helpers/svg-normalize.ts` `stripPaint` option), and an invalid value in any
|
|
366
|
+
painted key is refused by name rather than emitted or dropped (the #303
|
|
367
|
+
class, for every family at once). `property-invariance-source.test.ts`:
|
|
368
|
+
inserting `%%` comments and blank lines leaves SVG byte-identical, and a
|
|
369
|
+
chained flowchart edge equals its split form in facts, layout, and bytes.
|
|
370
|
+
- **Model-based editing** — `property-er-model.test.ts` drives the typed ER
|
|
371
|
+
edit operations with `fc.commands` against a simple model, including invalid
|
|
372
|
+
commands whose error code the model predicts.
|
|
200
373
|
|
|
201
374
|
**Runs:** every PR.
|
|
202
375
|
**Does not prove:** cross-architecture equality (x86_64 hash vs ARM64 hash
|
|
@@ -216,47 +389,131 @@ mutating process-global configuration).
|
|
|
216
389
|
|
|
217
390
|
- Reproduce a specific roll: `AM_FC_SEED=<int> bun test <file>`.
|
|
218
391
|
- Finder mode (deliberate randomness): `AM_FC_SEED=random bun run test`.
|
|
219
|
-
-
|
|
220
|
-
|
|
221
|
-
process-global
|
|
222
|
-
|
|
392
|
+
- A suite that needs its own regression seed passes it to `fc.assert`
|
|
393
|
+
options through `fcParameters(...)` from `src/__tests__/helpers/fc-parameters.ts`;
|
|
394
|
+
process-global configuration belongs to the preload alone. The helper keeps
|
|
395
|
+
local pins in ordinary gates, lets explicit `AM_FC_SEED` replay/finder controls
|
|
396
|
+
override them, and applies `AM_FC_NUM_RUNS` as a minimum without lowering a
|
|
397
|
+
stronger local case count. Use it for explicit `fc.assert`/`fc.check` options
|
|
398
|
+
and exploratory `fc.sample` calls. No-options runners inherit the preload
|
|
399
|
+
directly. A calibrated fixed-corpus ratchet must retain its exact seed and
|
|
400
|
+
cardinality: its finding budget is not a universal property. The hard-metric
|
|
401
|
+
properties beside the layout-rubric ratchets remain eligible for finders.
|
|
223
402
|
|
|
224
403
|
Pinning is for *holding* known ground; randomness is for *finding* new
|
|
225
404
|
counterexamples ("an invariant enforced by a random property is a lottery,
|
|
226
405
|
not a gate" — `docs/contributing/lessons-learned.md`). Rolling seeds belong in
|
|
227
|
-
finder lanes: the deep-fuzz scripts
|
|
228
|
-
`AM_FC_SEED=random` sweeps.
|
|
406
|
+
finder lanes: the weekly `contract-discovery.yml` workflow, the deep-fuzz scripts
|
|
407
|
+
under `eval/`, or deliberate `AM_FC_SEED=random` sweeps.
|
|
408
|
+
|
|
409
|
+
The weekly **Contract discovery** workflow is a single read-only job capped at
|
|
410
|
+
ten runner-minutes, including setup. It first rolls one recorded seed through
|
|
411
|
+
the existing Flowchart and ER shadow-model command properties and the valid
|
|
412
|
+
Architecture round-trip property. Valid model generators construct legal grammar
|
|
413
|
+
contexts; reserved/malformed identifiers have separate source-preservation,
|
|
414
|
+
diagnostic and mutation-refusal tests. The normal pinned gate remains deterministic.
|
|
415
|
+
|
|
416
|
+
A finder-only fast-check reporter writes structured seed/path, counterexample,
|
|
417
|
+
callsite, run/shrink counts and failure details. Bun's JUnit result supplies the
|
|
418
|
+
owning named test and setup errors. Capturing a property failure still throws;
|
|
419
|
+
recording a failure cannot turn it into a pass. There is no display-log scraper,
|
|
420
|
+
property-title suppression list or GitHub issue-writing permission. Model failure
|
|
421
|
+
stops further search for that run and retains the replay evidence.
|
|
422
|
+
|
|
423
|
+
The grammar stage uses a seed-selected corpus sample (at most eight short inputs
|
|
424
|
+
per native family), 100 text mutations per family, two workers, at most two
|
|
425
|
+
retained candidates per contract/family and eight reduction checks. These are
|
|
426
|
+
bounded discovery settings, not a claim of exhaustive grammar coverage. It keeps
|
|
427
|
+
portable-write, native reload/meaning and source-diagnostic candidates separately
|
|
428
|
+
from raw reference token/action/model differences. A reduction must retain the
|
|
429
|
+
same candidate contract violation; otherwise the original witness remains. Partial
|
|
430
|
+
summaries and the last source survive an interrupted search. Expensive native/
|
|
431
|
+
reference instrumentation is a diagnostic; parser disagreement alone is not a bug.
|
|
432
|
+
|
|
433
|
+
Canonical CI still replays the reviewed corpus in
|
|
434
|
+
`eval/mermaid-modern-compat/corpus/grammar-finder-494.json` with `--check` and runs
|
|
435
|
+
the required pinned semantic and packed-consumer gates. The historical filename
|
|
436
|
+
retains provenance; it is not an issue-notification channel. Review-pin changes
|
|
437
|
+
invalidate reporting matches. A repaired input may improve: the corpus never
|
|
438
|
+
requires a known defect to persist.
|
|
439
|
+
|
|
440
|
+
Discovery emits JSON, a step summary and retained artifacts for human review;
|
|
441
|
+
it never creates or comments on issues. A failed run must be classified as a
|
|
442
|
+
product contract violation, test-domain/oracle mistake, reference/setup failure,
|
|
443
|
+
or interrupted search before assigning finite work. Replay on the current pin
|
|
444
|
+
and main; retain a minimal original/model counterexample in the existing owning
|
|
445
|
+
property and fix the failure class. Review existing finite grammar issues before
|
|
446
|
+
opening additional work. Useful yield is reproducible confirmed failure classes
|
|
447
|
+
per runner/review hour, with replay completeness and triage time alongside it;
|
|
448
|
+
mutation, disagreement and ticket counts do not measure correctness.
|
|
449
|
+
Pause recurring discovery while confirmed findings await repair or its oracle
|
|
450
|
+
needs correction; replay those finite inputs before spending another search budget.
|
|
451
|
+
|
|
452
|
+
The former nightly workflow and #362 collector are retired. Historical runs and
|
|
453
|
+
counterexamples remain evidence. Their open-ended notification infrastructure is
|
|
454
|
+
not needed to keep valid regression coverage. Larger grammar or order searches
|
|
455
|
+
remain explicit manual commands for targeted changes and reference upgrades.
|
|
456
|
+
|
|
457
|
+
Before the pin was frozen, every unpinned suite was
|
|
229
458
|
swept across 48/24/12 seeds (scaled by runtime; 1,368 suite-runs total) with
|
|
230
459
|
zero failures — the pin does not freeze a known-bad ticket, and the sweep is
|
|
231
460
|
repeatable from the same knob.
|
|
232
461
|
|
|
462
|
+
### Applying Hegel guidance with fast-check
|
|
463
|
+
|
|
464
|
+
Keep fast-check; use the upstream [Hegel skill](https://github.com/hegeldev/hegel-skill/tree/main/skills/hegel)
|
|
465
|
+
and [review checklist](https://github.com/hegeldev/hegel-skill/blob/main/skills/hegel-review/SKILL.md)
|
|
466
|
+
to improve properties, not to require a library migration. Derive expectations
|
|
467
|
+
from public contracts or an independent model, and check exact values as well
|
|
468
|
+
as validity. Cover valid inputs and near-valid rejection separately; preserve
|
|
469
|
+
the source when an agent parser deliberately falls back to opaque.
|
|
470
|
+
|
|
471
|
+
`fc.string()` defaults to printable ASCII. Choose `unit: 'grapheme'` for
|
|
472
|
+
printable Unicode, `unit: 'binary'` for Unicode scalars including controls, or
|
|
473
|
+
an explicit UTF-16 code-unit arbitrary for helpers accepting arbitrary JS
|
|
474
|
+
strings. Keep hostile tokens alongside broad generators. Construct valid
|
|
475
|
+
grammar contexts instead of filtering out failures; an explicit `examples`
|
|
476
|
+
entry bypasses the generator, including its maps and filters.
|
|
477
|
+
|
|
478
|
+
For cheap string/parser properties, run thousands of cases. Bound expensive
|
|
479
|
+
render materialization deliberately, vary relevant configuration, and add a
|
|
480
|
+
separate scale probe without a machine-specific timing threshold. Independent
|
|
481
|
+
XML parsing proves well-formedness; finding `<svg` and `</svg>` does not.
|
|
482
|
+
Use `fc.assert(fc.property(...))` for per-input invariants so failures shrink;
|
|
483
|
+
reserve `fc.sample` for aggregate/distribution measurements.
|
|
484
|
+
|
|
485
|
+
When applying the skill, have a separate reviewer derive missing properties
|
|
486
|
+
from implementation and contracts without seeing the tests. Record every
|
|
487
|
+
observed failure as either a reduced product finding or a corrected test
|
|
488
|
+
mistake. Do not silently trim a generator or relax an assertion after it fails.
|
|
489
|
+
|
|
233
490
|
## 5. Pseudo-oracles — do selected seeded faults make the suite fail?
|
|
234
491
|
|
|
235
|
-
Tests can be green while missing faults.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
- **
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
adequacy signal — coverage is not strongly correlated with fault detection
|
|
492
|
+
Tests can be green while missing faults. The red-green-refactor cycle is the
|
|
493
|
+
defence: write the test, watch it fail for the right reason, then fix.
|
|
494
|
+
|
|
495
|
+
- **Red → green** (`scripts/ci/red-green.ts`, the `red-green` CI job) — when a
|
|
496
|
+
pull request changes production source and tests, at least one changed test
|
|
497
|
+
must produce an assertion failure attributed to a test location against base
|
|
498
|
+
production. Missing imports, non-assertion setup errors, unlocated suite-hook
|
|
499
|
+
assertions, timeouts and aborted runners are not
|
|
500
|
+
behavioral evidence; the gate reads the pinned Bun runner's JUnit report.
|
|
501
|
+
Unexpected production exceptions need an explicit `toThrow` / `not.toThrow`
|
|
502
|
+
assertion. This mechanically
|
|
503
|
+
checks the "tests that fail when the fix is reverted" rule for every PR,
|
|
504
|
+
instead of a hand-written probe per fix. Pure refactors opt out with the
|
|
505
|
+
`no-red-green` label. Like `payload-growth-approved`, it approves only the
|
|
506
|
+
head it was applied to (`scripts/ci/label-approval.ts`): CI ignores a label
|
|
507
|
+
applied before the latest push and removes it when new commits arrive.
|
|
508
|
+
Bun's JUnit report cannot distinguish located per-test hook assertions from
|
|
509
|
+
test-body assertions. Review their meaning: this gate is fault evidence, not
|
|
510
|
+
a substitute for auditing whether each assertion exercises production behavior.
|
|
511
|
+
|
|
512
|
+
**Why this matters:** line coverage is collected weekly and on manual dispatch
|
|
513
|
+
by `coverage.yml`, as one merged LCOV artifact assembled from three unit shards.
|
|
514
|
+
Locally, `bun run test:coverage` collects the same diagnostic. The required
|
|
515
|
+
`bun run test` suite runs every assertion without coverage instrumentation.
|
|
516
|
+
Coverage is a weak adequacy signal — coverage is not strongly correlated with fault detection
|
|
260
517
|
once suite size is controlled (Inozemtseva & Holmes, ICSE 2014), whereas
|
|
261
518
|
mutant detection *is* correlated with real-fault detection (Just et al.,
|
|
262
519
|
FSE 2014). That supports focused mutation as one useful instrument, not mutation
|
|
@@ -276,14 +533,24 @@ This is where we approximate aesthetics deterministically:
|
|
|
276
533
|
- **layout rubric / visual-rubric** — hard violations (must be 0) plus soft
|
|
277
534
|
thresholds (crossings, bends, port-anchored rate).
|
|
278
535
|
- **heuristic-tracker** — baseline-comparison of routing metrics with
|
|
279
|
-
improvement/regression deltas
|
|
280
|
-
|
|
281
|
-
|
|
536
|
+
improvement/regression deltas. `heuristic-tracker.test.ts` gates the
|
|
537
|
+
portable part per PR: every tracked example scores without error and hard
|
|
538
|
+
violations stay 0. The soft-metric comparison (bends, crossings, straight
|
|
539
|
+
counts) is not gated, because those integers come from floating-point ELK
|
|
540
|
+
geometry that differs across machines; run
|
|
541
|
+
`bun run eval/heuristic-tracker/run.ts` to see soft deltas when tuning
|
|
542
|
+
routing.
|
|
282
543
|
- **route-contract tripwires** — `ROUTE_*` codes that must stay 0; any hit
|
|
283
544
|
means the layout pipeline regressed, not the diagram.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
545
|
+
- **chart-honesty pixel oracle** (`chart-honesty-text-*.test.ts`,
|
|
546
|
+
`property-chart-honesty.test.ts`) — every text of every family, in every
|
|
547
|
+
registered style, rasterized by resvg: WCAG contrast against the pixels
|
|
548
|
+
around its glyphs, glyphs on the canvas, authored text drawn or reported by
|
|
549
|
+
`verify`, and the same reading in every style
|
|
550
|
+
([`design/system/chart-honesty.md`](design/system/chart-honesty.md)).
|
|
551
|
+
|
|
552
|
+
**Runs:** `measureQuality`, ugly-detector, the layout rubric, the
|
|
553
|
+
heuristic-tracker ratchet, and the chart-honesty oracle all gate per PR.
|
|
287
554
|
**Bound provenance (Move 6):** each `QualityBounds` band now carries an
|
|
288
555
|
explicit basis — `edgeCrossings` is `evidence` (the one aesthetic with strong
|
|
289
556
|
human-subject support: Purchase 1997/2002), `labelLegibility` is `derived`
|
|
@@ -306,21 +573,15 @@ match a human designer's eye; they catch the worst regressions"
|
|
|
306
573
|
layout/rendering changes (`contributing/visual-review-evidence.md`).
|
|
307
574
|
|
|
308
575
|
**Runs:** the real LLM judge is **periodic / pre-release only** — model
|
|
309
|
-
spend plus nondeterminism make it unfit for a per-PR gate
|
|
310
|
-
|
|
311
|
-
**Protocol hardening (Move 1):** the readability/aesthetics axes of the CI
|
|
312
|
-
mock are still derived from the perceptual metrics (it is a wiring stub), but
|
|
313
|
-
the **faithfulness** axis now comes from `independentFaithfulness()` — a
|
|
576
|
+
spend plus nondeterminism make it unfit for a per-PR gate, and it has no CI
|
|
577
|
+
stand-in. Its **faithfulness** axis comes from `independentFaithfulness()` — a
|
|
314
578
|
structural parse → serialize → re-parse count check that does *not* consult
|
|
315
|
-
`measureQuality
|
|
579
|
+
`measureQuality`. The judge has
|
|
316
580
|
primitives for the documented LLM-judge biases (Zheng et al., NeurIPS 2023):
|
|
317
581
|
`judgePairwiseDebiased` scores both orders and trusts only an agreeing verdict
|
|
318
582
|
(position bias), `assertJudgeIndependence` refuses a judge from the same model
|
|
319
583
|
family that authored the diagram (self-enhancement), and `JudgeReference`
|
|
320
584
|
threads a golden anchor (reference-guided scoring).
|
|
321
|
-
**Known limitation:** the mock's readability/aesthetics axes remain
|
|
322
|
-
metric-derived, so they cannot independently validate those metrics — only a
|
|
323
|
-
real judge run can.
|
|
324
585
|
|
|
325
586
|
## What runs where
|
|
326
587
|
|
|
@@ -331,16 +592,228 @@ table here, which would drift. In broad strokes:
|
|
|
331
592
|
Tier-1 verify, goldens, the differential + faithfulness + metamorphic gates,
|
|
332
593
|
`measureQuality`/whole-corpus ugly-detector/layout-rubric, the heuristic-tracker ratchet,
|
|
333
594
|
the corpus/seqbench/upstream benches — plus the high/critical dependency audit,
|
|
334
|
-
type check, the hero check, the
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
595
|
+
type check, the hero check, the parallel browser/CLI/binary/fuzz e2e matrix (whose
|
|
596
|
+
browser lane checks route payload budgets and, on pull requests, the gzip
|
|
597
|
+
delta against the base branch built on the same runner), and the
|
|
598
|
+
red → green changed-test check. Each unit shard runs its files with
|
|
599
|
+
`--parallel=2` (isolated worker processes), so a test file cannot depend on
|
|
600
|
+
another file's imports. CI prepares the shared website fixture in a separate
|
|
601
|
+
two-minute step before starting those workers, so parallel consumers reuse
|
|
602
|
+
a completed build instead of competing to generate it. A final `CI complete` job waits for the required
|
|
603
|
+
test aggregate, every E2E matrix job and red → green, providing one
|
|
604
|
+
protectable result that cannot turn green early.
|
|
605
|
+
- **Weekly (`contract-discovery.yml`):** one bounded model/grammar discovery job;
|
|
606
|
+
findings remain replay artifacts for human triage, without automated issues.
|
|
607
|
+
- **Per deploy (`deploy-cloudflare.yml`, release to-do):** when the deploy
|
|
608
|
+
skips because `package.json` names a version that is not on npm, it opens
|
|
609
|
+
one `release-todo` issue for that version, and a verified deploy of the
|
|
610
|
+
version closes it (`scripts/ci/release-todo.ts`, tested with a fake `gh` in
|
|
611
|
+
`release-todo.test.ts`). It adds no schedule and never fails a run. **Does
|
|
612
|
+
not prove:** what production serves; it only reports the skip.
|
|
613
|
+
- **Local performance campaigns:** benchmark suites are excluded from CI,
|
|
614
|
+
scheduled workflows, hosted manual Actions and publication dependencies.
|
|
615
|
+
`bun run bench:release` retains the matched Node corpus, scaling, agent edit,
|
|
616
|
+
allocation and memory diagnostics; `bun run bench:release:browser` compares
|
|
617
|
+
the exact packed candidate with pinned browser peers. Run them on an owned
|
|
618
|
+
local host and retain candidate/baseline identities and raw results. Controller
|
|
619
|
+
tests live in [Trident](https://github.com/adewale/trident) and run through `bun run bench:test`.
|
|
620
|
+
Normal product correctness, distribution and pinned-Mermaid semantic tests
|
|
621
|
+
remain CI gates. See [Trident](https://github.com/adewale/trident/blob/main/README.md), its
|
|
622
|
+
[unified runner](https://github.com/adewale/trident/blob/main/unified/README.md) and [the launcher](../eval/trident/README.md) for invocation coverage,
|
|
623
|
+
project updates and explicit gaps.
|
|
624
|
+
- **Normal local benchmarks:** `bun run bench` runs the bounded unified smoke
|
|
625
|
+
profile; `bun run bench:all` selects the full maintained catalog.
|
|
626
|
+
`bun run bench:samples` runs the website SVG/terminal samples;
|
|
627
|
+
`bun run bench:dave` runs just the full browser comparison (three rounds,
|
|
628
|
+
the same first 30 warm-up attempts, all 1,095 pinned fence occurrences
|
|
629
|
+
including duplicates and unsupported families). It builds and packs the
|
|
630
|
+
checkout, then reuses the publication scorecard against pinned Pele 1.9.0
|
|
631
|
+
and Mermaid 12.2.0. Chromium and initial npm access are required;
|
|
632
|
+
`--executable /path/to/chromium`, `--out DIR`, `--rounds N` and
|
|
633
|
+
`--case occurrence-id,...` are forwarded to the browser runner. A case
|
|
634
|
+
filter is a partial diagnostic, not a full-corpus result. Results go to
|
|
635
|
+
gitignored `bench-report/dave/`; competitor ratios remain advisory.
|
|
636
|
+
The local release browser scorecard retains its full-corpus warm-up by
|
|
637
|
+
default; `--warmup 30` selects Dave's
|
|
638
|
+
warm-up policy. Both disable AM's ELK result cache before loading the
|
|
639
|
+
library, so duplicate sources measure layout rather than memo lookup.
|
|
640
|
+
Timing is source through SVG return, not visual/semantic fidelity or
|
|
641
|
+
paint. The post does not specify its warm-up selection; choosing the
|
|
642
|
+
first 30 is an explicit adaptation. Generated reports are not committed.
|
|
643
|
+
To include Bezel's Rust renderer, install Rust's `wasm32-unknown-unknown`
|
|
644
|
+
target and `wasm-bindgen-cli` 0.2.104, then run:
|
|
645
|
+
|
|
646
|
+
```sh
|
|
647
|
+
(cd ../trident && bun run bezel-wasm/build.ts --checkout ../bezel --out /tmp/bezel-bench)
|
|
648
|
+
bun run bench:dave --bezel-dir /tmp/bezel-bench --executable /path/to/chromium
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
The adapter compiles an unmodified, clean Bezel checkout at `opt-level=3`
|
|
652
|
+
with LTO. Its manifest records the revision, compiler, dependency lock and
|
|
653
|
+
wrapper/WASM byte identities. Instantiation is outside the render timer;
|
|
654
|
+
timed calls use `render(source, &Options::default(), &Metrics).svg`. Reported
|
|
655
|
+
bundle size includes the WASM embedded in its JS wrapper. This measures
|
|
656
|
+
standalone browser rendering, not Bezel's GPUI gallery or native execution.
|
|
657
|
+
WASM memory is outside the separate V8 JS-memory diagnostic.
|
|
658
|
+
`bun run bench --profile full --suites editor-preview` complements that
|
|
659
|
+
render-only score with actual editor input through verified DOM and two
|
|
660
|
+
animation frames. It changes the root label in 5/50/150-node trees, keeps
|
|
661
|
+
default cache behavior and adaptive debounce, and records a 5 ms main-thread
|
|
662
|
+
heartbeat. Run baseline and candidate builds sequentially on an otherwise
|
|
663
|
+
idle runner. These targeted UI samples are separate from the full corpus.
|
|
664
|
+
The standalone editor embeds one module used by both the main thread and
|
|
665
|
+
its Blob worker; it does not embed separate copies of the rendering engine.
|
|
666
|
+
The real-browser standalone contract also caps the complete generated HTML
|
|
667
|
+
at 4,100,000 raw / 1,264,000 gzip bytes and checks worker crash recovery,
|
|
668
|
+
text output and the actual Canvas PNG download. The hosted editor retains
|
|
669
|
+
its separate, lazy worker asset and existing route payload budgets.
|
|
670
|
+
|
|
671
|
+
Two optional investigations expand these diagnostics without adding timing
|
|
672
|
+
gates:
|
|
673
|
+
|
|
674
|
+
```sh
|
|
675
|
+
# AGENTIC_ROOT contains package.json and the actual dist/browser.global.js.
|
|
676
|
+
bun run bench --profile full --suites renderer-profile --package-root /path/to/extracted/package --bezel-dir /tmp/bezel-bench
|
|
677
|
+
bun run bench --profile full --suites editor-session
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
The renderer investigation records family-level SVG acceptance, differential
|
|
681
|
+
inputs/errors and paired timing over the complete occurrence inventory. Its
|
|
682
|
+
separate source-build pass attributes stages over distinct sources after
|
|
683
|
+
warmup, both through SVG return and fully consumed receipts; layout includes
|
|
684
|
+
ELK, so those stage totals must not be added together. Chrome CPU profiles
|
|
685
|
+
cover the slowest shared-success example in eight families. Source profiles
|
|
686
|
+
retain function names; only the packaged pass establishes competitor ratios.
|
|
687
|
+
`--timing-report /path/to/renderer-profile.json` can reuse a completed timing
|
|
688
|
+
pass with identical artifact hashes/rounds and a complete adjacent
|
|
689
|
+
`samples.json`; it still reruns stage attribution and profiling.
|
|
690
|
+
|
|
691
|
+
The editor session runner covers trees, nested crosslinks, sequence, class,
|
|
692
|
+
ER, state, mindmap, Gantt and pie. Defaults are five fresh browser contexts,
|
|
693
|
+
20 warm edits, 60 subsequent edits and a 30-edit burst requesting 80 ms intervals per
|
|
694
|
+
case. It records median/p95 latency, heartbeat gaps, receipt invalidation,
|
|
695
|
+
visible final labels, worker concurrency and forced-GC JS heaps in both
|
|
696
|
+
realms. Fresh contexts do not clear browser-process or OS caches; localhost
|
|
697
|
+
transfer is uncompressed and unshaped. Heap figures exclude native/DOM/Blob
|
|
698
|
+
backing allocations and process RSS. Use `--case tree-150` for longer focused
|
|
699
|
+
sessions, `--memory-every 100` for periodic retained-heap checkpoints outside
|
|
700
|
+
timed edits, and `--entry /original.html` for standalone builds served in a site
|
|
701
|
+
directory alongside its `capabilities.json` and fonts. Baseline/candidate
|
|
702
|
+
runs must remain sequential on an otherwise idle runner.
|
|
703
|
+
|
|
704
|
+
The editor's persistent worker owns preview/verification, ASCII/Unicode and
|
|
705
|
+
PNG projection/validation. A PNG operation invokes the existing main-thread
|
|
706
|
+
font/Canvas callback and transfers an allocation-bounded copy of its bytes
|
|
707
|
+
back for canonical PNG validation. Callback buffers are never detached.
|
|
708
|
+
One operation is active, with one replaceable preview and four queued exports;
|
|
709
|
+
source/config changes cancel stale work, including a PNG awaiting font/Canvas
|
|
710
|
+
I/O, so a new preview can proceed. Timeouts and crashes reject all waiters and
|
|
711
|
+
the next operation starts a fresh worker.
|
|
712
|
+
|
|
713
|
+
`editor-ownership-bench.ts --site /path/to/site --out bench-report/ownership
|
|
714
|
+
--executable /path/to/chromium` compares frozen `original.html` and current
|
|
715
|
+
`candidate.html` in alternating fresh contexts. Serve their fonts alongside
|
|
716
|
+
them. It separately measures the empty shell, first preview, ASCII/Unicode
|
|
717
|
+
and a real Canvas PNG, with heap checkpoints before/after preview and exports.
|
|
718
|
+
`--case tree-5,tree-50,tree-150,nested-crosslinks,sequence-40,class-20,er-20,state-25,mindmap-30,gantt-20,pie-12`
|
|
719
|
+
expands it to the full editor portfolio; `--style hand-drawn` measures a seeded
|
|
720
|
+
alternate backend. The runner attempts every format even after a render
|
|
721
|
+
rejection, retains incremental samples and reports per-format acceptance.
|
|
722
|
+
Successful SVG/ASCII/Unicode/PNG bytes and request identities must match
|
|
723
|
+
across variants and repetitions; rejected outputs must have matching errors.
|
|
724
|
+
Report rejected attempts separately from successful-operation latency.
|
|
725
|
+
- **Manual / periodic:** `layout-compare` before/after, the benchmark vs competitors,
|
|
726
|
+
`bun run bench:micro` (per-stage hotspot timings, allocation per call under
|
|
727
|
+
`--runtime node`, and `--baseline <ref>` for interleaved revision ratios;
|
|
728
|
+
advisory, never a gate). Filter `^source-edit:` for opaque Class/Flowchart
|
|
729
|
+
edits at 32, 256 and 2,048 nodes, including ten-edit chains and exact label
|
|
730
|
+
no-ops. These start from a warm parsed input and time complete result JSON
|
|
731
|
+
materialization; they exclude verification, layout and rendering. Reports
|
|
732
|
+
retain source/output byte counts and growth. Node allocation estimates cover
|
|
733
|
+
V8, not native memory or peak RSS. Compare with `--baseline <source-edit-ref>`
|
|
734
|
+
and calibrate timing noise with `--aa`; an unavailable baseline API is not a
|
|
735
|
+
fast successful edit. `bun run bench:peers` (the built package against
|
|
736
|
+
the pinned browserless and terminal peers in `eval/fork-graph/`, with output checks outside timing/allocation and label
|
|
737
|
+
checks before timing; includes the native Go Sketch worker, requiring Go >=1.25).
|
|
738
|
+
`bench:peers --corpus` attempts every official fence occurrence, including
|
|
739
|
+
unsupported families, with one warmup and three single-call samples per
|
|
740
|
+
successful input per round. This mode checks output presence rather than
|
|
741
|
+
labels or semantic/visual fidelity; the ordinary calibrated workloads keep
|
|
742
|
+
their label assertions. `bun run check:output-identity --baseline <ref>`
|
|
743
|
+
(byte identity of the distinct corpus inputs across SVG backends, SVG
|
|
744
|
+
post-passes, ASCII, Unicode and verify, for refactors that must not change
|
|
745
|
+
output), the real LLM-as-judge run, and the production freshness check
|
|
746
|
+
(`scripts/ci/production-freshness.ts`, in `docs/contributing/releasing.md`).
|
|
747
|
+
That check compares the build agentic-mermaid.dev serves with the `main`
|
|
748
|
+
commit it is given (the tip of `main`, in the documented command) and fails
|
|
749
|
+
once `main` has held undeployed commits for more than three days. A deploy run proves only the deploys that
|
|
750
|
+
ran; this proves deploys are still reaching production. **Does not prove:**
|
|
751
|
+
that the served build works (the deploy's candidate probes do that).
|
|
752
|
+
|
|
753
|
+
## Contract review and completion
|
|
754
|
+
|
|
755
|
+
Before implementing a cross-surface change, put a short contract/evidence table
|
|
756
|
+
in the PR description. For a small change, use a sentence. Each contract states
|
|
757
|
+
observable behavior, its owning producer and consumers, and what could falsify
|
|
758
|
+
it. Choose expectations from public behavior or independent source evidence
|
|
759
|
+
before examining existing assertions. Reuse existing tests and probes; this is
|
|
760
|
+
a review method, not another generated manifest or test-presence gate.
|
|
761
|
+
|
|
762
|
+
Preserve distinctions until the component that owns the decision can resolve
|
|
763
|
+
them. Examples from PR #470 show why this matters:
|
|
764
|
+
|
|
765
|
+
| Contract | Distinction to preserve | Evidence at the owning boundary |
|
|
766
|
+
| --- | --- | --- |
|
|
767
|
+
| Worker recovery | An obsolete operation can still report a broken worker; deferred loading differs from an optional rendering failure | Cancel an export while its import fails, then exercise the queued preview and first retry; compare cold and warm receipts. |
|
|
768
|
+
| Deployment recovery | A temporary network failure differs from an old document requesting retired asset URLs | Serve two actual asset generations and preserve the latest draft/settings across explicit reload, including storage/encoding failure. |
|
|
769
|
+
| Benchmark identity | A rendered SVG or equal input count does not establish the requested theme or measured source | Assert active/restored theme identity and exact input/module/config identity; reject invalid resume before overwriting evidence. |
|
|
770
|
+
| Repository matching | Missing metadata differs from explicit unsupported, malformed or conflicting metadata | Enter through raw repository normalization and matching together; include URI ports and scp-style addresses. |
|
|
771
|
+
| Responsibility categories | A known member and valid labels do not establish complete source review | Cite pinned public APIs/authoring flows for assigned roles; leave unreviewed responsibilities explicit. |
|
|
772
|
+
|
|
773
|
+
Review purposeful transitions and interacting boundaries, rather than every
|
|
774
|
+
combination. Where the change applies, consider cold/warm state, cancellation
|
|
775
|
+
and failure ordering, representation changes, multiple consumers/platforms and
|
|
776
|
+
deployment generations. State exclusions instead of treating untested cases as
|
|
777
|
+
passed. Tests should still protect one contract at its owning boundary; do not
|
|
778
|
+
combine unrelated UI, persistence and export contracts into one test.
|
|
779
|
+
|
|
780
|
+
For each confirmed finding, identify the failed assumption and trace it from
|
|
781
|
+
raw input through all affected consumers. Distinguish a pre-existing defect
|
|
782
|
+
from one introduced by a repair. Review adjacent paths that share that
|
|
783
|
+
assumption, extend an existing behavioral test where possible, and demonstrate
|
|
784
|
+
red → green for the bug. If only the example is fixed, keep the broader gap
|
|
785
|
+
open. If exhaustive review is infeasible, narrow the claim and state the gap.
|
|
786
|
+
|
|
787
|
+
When multiple reviewers are requested, assign independently falsifiable
|
|
788
|
+
hypotheses and explicit ownership of interactions, not just folders. One review
|
|
789
|
+
must connect the changed producers to their consumers. Ask reviewers to derive
|
|
790
|
+
expected behavior before reading existing tests; permit no finding and require
|
|
791
|
+
a reproduction for actionable defects. The change author reconciles findings
|
|
792
|
+
against the combined candidate. A severity label or number of agents does not
|
|
793
|
+
replace that reconciliation.
|
|
794
|
+
|
|
795
|
+
Completion requires resolved confirmed in-scope defects, evidence for the
|
|
796
|
+
declared contracts, disclosed remaining limitations, and successful required CI
|
|
797
|
+
for the exact final head. Record the base/head and dependency revision, link
|
|
798
|
+
the CI run, wait for terminal results, then recheck the current base and PR head.
|
|
799
|
+
Read the base branch's live remote ref: the PR's recorded base commit and the
|
|
800
|
+
workflow event's base SHA can be stale. Inspect the actual CI checkout and its
|
|
801
|
+
parents to confirm which base/head combination ran; the workflow run's head SHA
|
|
802
|
+
alone does not identify its merge checkout.
|
|
803
|
+
After a push, follow the new run. A base update requires a fresh check of the
|
|
804
|
+
combined candidate; after code/dependency changes, requalify affected contracts.
|
|
805
|
+
Retained measurements may apply when their shipped/input bytes are unchanged;
|
|
806
|
+
keep their original revision, date and limits. Never report a pending run as
|
|
807
|
+
ready. The hygiene script reports heuristics, not this completion decision.
|
|
808
|
+
|
|
809
|
+
Repeat an audit to answer a named unresolved question or examine a material
|
|
810
|
+
change to a contract. Repeating the same prompt until no reviewer finds
|
|
811
|
+
anything is not a stopping rule. New discoveries can reopen an affected
|
|
812
|
+
contract; a clean audit alone neither proves completeness nor invalidates
|
|
813
|
+
sound evidence for other contracts. Do not create more gates or approval
|
|
814
|
+
artifacts merely to certify that the review procedure was followed.
|
|
815
|
+
|
|
816
|
+
### Boundary-contract matrix — lessons applied from the 2026-07 agent audit
|
|
344
817
|
|
|
345
818
|
The PR #162 audit exposed a blind spot that family/layout coverage did not
|
|
346
819
|
address: a contract could be correct in one helper and false at another public
|
|
@@ -373,6 +846,90 @@ lowest honest tier and one shipped-boundary proof where packaging, transport,
|
|
|
373
846
|
or generation can change the result. A test that silently returns because its
|
|
374
847
|
environment is unavailable is not evidence for a CI-required capability.
|
|
375
848
|
|
|
849
|
+
## What makes a good test
|
|
850
|
+
|
|
851
|
+
The sections above say which oracles the suite uses. This one is the standard
|
|
852
|
+
each test is held to. A good test catches a real regression, for the right
|
|
853
|
+
reason, cheaply, and says clearly what broke.
|
|
854
|
+
|
|
855
|
+
1. **It can fail.** Breaking the behaviour it names turns it red. Check this
|
|
856
|
+
by mutating the code under test, not by reading the assertion. The common
|
|
857
|
+
failures are an assertion something else always satisfies (`toContain('v')`
|
|
858
|
+
when a label contains a `v`; a marker id that every SVG defines in
|
|
859
|
+
`<defs>`), and a fixture that never reaches the code (suppressing a warning
|
|
860
|
+
the input never raises).
|
|
861
|
+
2. **It tests behaviour through a stable seam**: the API, CLI, MCP tool,
|
|
862
|
+
rendered output or a documented contract. It does not grep source text,
|
|
863
|
+
compare `Function.prototype.toString()`, or pin private names.
|
|
864
|
+
3. **Its expectation comes from outside the code**: a specification, pinned
|
|
865
|
+
upstream Mermaid, a metamorphic relation, a property, or a reviewed golden
|
|
866
|
+
whose meaning is stated. A value harvested from our own output and pasted
|
|
867
|
+
back is not an oracle. The upstream bench's self-harvested labels once
|
|
868
|
+
pinned a wrong ellipse label as correct.
|
|
869
|
+
4. **It has one reason to fail and a readable failure.** The name states the
|
|
870
|
+
behaviour; the assertion is object-shaped and carries the case, not a bare
|
|
871
|
+
`toBe(true)` over a conjunction.
|
|
872
|
+
5. **It is deterministic and hermetic.** Pinned seeds, no wall clock, no
|
|
873
|
+
sleeps, no network, no dependence on file order, no leaked temp files or
|
|
874
|
+
environment variables.
|
|
875
|
+
6. **It asserts something it did not set.** No assertion on a value the test
|
|
876
|
+
just assigned, on a mock's configured return, or on a `Record` completeness
|
|
877
|
+
that `tsc` already enforces. An early `return` or an `if (x) expect(…)`
|
|
878
|
+
that can skip every assertion is a missing assertion: assert the
|
|
879
|
+
precondition, or use `test.skipIf` with a reason. A property whose success
|
|
880
|
+
branch can go unexercised counts how often it ran and fails at zero.
|
|
881
|
+
7. **It is not redundant**, and it does not make a doc or a second list copy
|
|
882
|
+
data the code owns; iterate the registry instead of a hand list of
|
|
883
|
+
families.
|
|
884
|
+
8. **Its label is honest.** A test that pins a known bug says so and names
|
|
885
|
+
the `TODO.md` entry. A regression guard that cannot discriminate says so.
|
|
886
|
+
9. **Its cost is proportionate.** Expensive work (renders, layouts, PNG
|
|
887
|
+
rasterization, a website build) is done once per file and shared.
|
|
888
|
+
10. **It reads as arrange, act, assert**, with many cases as a table.
|
|
889
|
+
|
|
890
|
+
Shared helpers carry the common arrangements: `src/__tests__/helpers/temp-dir.ts`
|
|
891
|
+
for temporary directories that are removed after the file,
|
|
892
|
+
`src/__tests__/helpers/cli-capture.ts` for in-process CLI output, and
|
|
893
|
+
`src/__tests__/helpers/complexity.ts` for growth checks in place of wall-clock
|
|
894
|
+
ceilings.
|
|
895
|
+
|
|
896
|
+
A test protects observable behaviour or an independent public contract
|
|
897
|
+
(API, package contents, security, protocol, config, shipped bytes, and the
|
|
898
|
+
agent-facing runtime docs: `llms.txt`, CLI help, MCP instructions,
|
|
899
|
+
`am --agent-instructions`). There are no tests of tests: no lint over test
|
|
900
|
+
source, no grep over production source, no check that a doc's prose or a
|
|
901
|
+
second list matches the code, and no test of an eval or CI helper for its own
|
|
902
|
+
sake. Determinism is proven on output (`agent-determinism.test.ts`,
|
|
903
|
+
`ascii-determinism.test.ts`), not by banning tokens in source.
|
|
904
|
+
|
|
905
|
+
Files worth copying: `src/__tests__/property-upstream-flowchart.test.ts`
|
|
906
|
+
(grammar-generated differential against pinned upstream),
|
|
907
|
+
`src/__tests__/property-er-model.test.ts` (model-based test with a shadow
|
|
908
|
+
model), `src/__tests__/release-publish-steps.test.ts` (runs workflow shell
|
|
909
|
+
steps with stub tools), `src/__tests__/theme-color-admission.test.ts`
|
|
910
|
+
(table-driven across output routes), and
|
|
911
|
+
`src/__tests__/property-validator-surface-fuzz.test.ts` (the non-vacuity
|
|
912
|
+
counter).
|
|
913
|
+
|
|
914
|
+
`section-a-family-descriptor-conformance.test.ts` exercises built-in layout,
|
|
915
|
+
Scene lowering and terminal hooks through public operations, then inspects emitted
|
|
916
|
+
Scene roles, primitives and marker resources. Public dispatch and authored meaning
|
|
917
|
+
are checked by `characterization-families.test.ts` and
|
|
918
|
+
`diagram-family-citizenship.test.ts`. These executable witnesses also protect the
|
|
919
|
+
shared style, security and certification integration boundary.
|
|
920
|
+
Layout pass tests exercise production enforcement and resulting geometry; a
|
|
921
|
+
particular pass name or decomposition is not a rendering contract.
|
|
922
|
+
|
|
923
|
+
Call counts need an observable reason. Retain them for work admission (for
|
|
924
|
+
example, refusing oversized input before ELK or text measurement), deferred
|
|
925
|
+
optional graphical work, lazy terminal certification, and the single
|
|
926
|
+
positioned-artifact extension protocol.
|
|
927
|
+
Do not require an internal serializer or evidence enumerator to run exactly once
|
|
928
|
+
when the output, ownership and certificate are the actual contract. Default
|
|
929
|
+
pathfinder tie order and sequence spacing constants are likewise implementation
|
|
930
|
+
choices; test repeatability, valid routes and painted clearance, and use reviewed
|
|
931
|
+
goldens for intentional appearance baselines.
|
|
932
|
+
|
|
376
933
|
## Why the suite is shaped this way
|
|
377
934
|
|
|
378
935
|
- **Cheap-and-deterministic gates per PR; expensive-and-noisy gates
|
|
@@ -396,23 +953,24 @@ These are real today and are the natural targets for *enhancing* existing
|
|
|
396
953
|
gates rather than adding new machinery:
|
|
397
954
|
|
|
398
955
|
1. The per-PR aesthetic signal is still the weakest gate; the metrics are
|
|
399
|
-
admittedly rough
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
3.
|
|
408
|
-
|
|
956
|
+
admittedly rough, and nothing per-PR validates them independently — only a
|
|
957
|
+
real periodic judge run can.
|
|
958
|
+
2. There is no automatic mutation lane in the current PR workflow. Red → green
|
|
959
|
+
proves an assertion in a changed test file discriminates the base; it does not
|
|
960
|
+
prove every changed behavior is protected. Focused isolated faults can audit
|
|
961
|
+
weak oracles locally. The diff-scoped mutation proposal #355 was closed
|
|
962
|
+
`not_planned`; it is not an active implementation commitment. Line coverage
|
|
963
|
+
remains a finder, not an adequacy score.
|
|
964
|
+
3. Performance comparisons are local campaigns and do not run in CI or gate
|
|
965
|
+
publication. Their recorded results require an explicit update. Product
|
|
966
|
+
browser/screenshot e2e and the heuristic-tracker ratchet remain on the PR gate.
|
|
409
967
|
4. Determinism is proven Bun↔Node on one architecture; cross-architecture
|
|
410
968
|
byte equality is not asserted.
|
|
411
969
|
5. `QualityBounds` thresholds are now provenance-tagged, but the `chosen`
|
|
412
970
|
bands are still not validated against human-perception evidence.
|
|
413
|
-
6. Golden movement
|
|
414
|
-
|
|
415
|
-
|
|
971
|
+
6. Golden movement needs human judgment: each PR description lists every changed
|
|
972
|
+
golden and why it changed. Passing snapshot tests proves consistency with the
|
|
973
|
+
committed baseline, not that a changed baseline improves visual quality.
|
|
416
974
|
|
|
417
975
|
The deepest gap is structural, and `project/lessons-learned.md` (Loop 13)
|
|
418
976
|
names it: every quality signal here is self-generated. The portfolio above
|