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
|
@@ -1,655 +0,0 @@
|
|
|
1
|
-
# Abstraction recommendations — academic-literature review
|
|
2
|
-
|
|
3
|
-
Status: recommendations from academic-literature review. Drafted 2026-06-20;
|
|
4
|
-
reappraised and updated 2026-06-21 after the issue #71 implementation.
|
|
5
|
-
Companion to [`abstraction-audit.md`](./abstraction-audit.md) (the historical pre-implementation
|
|
6
|
-
snapshot and the source of issue numbers **I1–I9**, referenced throughout). Reconciled with the pre-existing
|
|
7
|
-
design docs it overlaps — [`AGENT_NATIVE.md`](../../../AGENT_NATIVE.md) (agent stack),
|
|
8
|
-
[`contributing/diagram-family-citizenship.md`](../../contributing/diagram-family-citizenship.md)
|
|
9
|
-
(family×surface CI ratchet), and [`source-preservation-ladder.md`](./source-preservation-ladder.md)
|
|
10
|
-
(structured\|opaque levels); see the audit's §5 for the agreement and the I1/I3/I7 refinements.
|
|
11
|
-
|
|
12
|
-
## 2026-06-21 reappraisal
|
|
13
|
-
|
|
14
|
-
The original issue spec was rechecked against the implemented code, the
|
|
15
|
-
`adewale/testing-best-practices` testing research, current competitor behavior, and fresh source
|
|
16
|
-
checks on the literature. The core direction still holds, but two details were improved:
|
|
17
|
-
|
|
18
|
-
1. `FamilyPlugin.layout` should be a **source-context hook**, not a `body` hook. The stronger
|
|
19
|
-
wording in the original roadmap ("layout the structured body directly") overfits L3/L4 bodies and
|
|
20
|
-
is wrong for L1 opaque bodies, accessibility directives, frontmatter, and `%%init%%` preservation.
|
|
21
|
-
The implemented contract uses `FamilyLayoutContext { source, options, renderOptions, colors }`.
|
|
22
|
-
That still removes the duplicated public SVG/ASCII switches while keeping source-preservation
|
|
23
|
-
semantics explicit.
|
|
24
|
-
2. `knownFamilies()` should not expose mutable `Map` insertion order. The reappraisal keeps the
|
|
25
|
-
keyed registry but requires deterministic iteration: built-ins follow `BUILTIN_FAMILY_METADATA`;
|
|
26
|
-
any external registrations sort lexically after the built-ins.
|
|
27
|
-
|
|
28
|
-
### Evidence Update
|
|
29
|
-
|
|
30
|
-
- **Academic architecture:** Wadler's expression-problem framing still supports a registry of
|
|
31
|
-
operations by family; TypeScript's discriminated-union/`never` exhaustiveness model supports the
|
|
32
|
-
certificate split and exhaustive proof switches. MLIR's "dialects and lowering" lesson and
|
|
33
|
-
Graphviz's attributed-graph/layout/output separation support multiple family-specific layout
|
|
34
|
-
dialects, not one universal geometry IR.
|
|
35
|
-
- **Competitive analysis:** Mermaid now documents many diagram families, frontmatter/config, and
|
|
36
|
-
evolving layout/look support; it explicitly limits layout/look support to some diagram types today
|
|
37
|
-
while expanding it. Graphviz exposes DOT, layout engines, output formats, and attributes as
|
|
38
|
-
separate concerns. PlantUML supports several layout engines and output formats, but ASCII is only
|
|
39
|
-
broadly documented for sequence diagrams. D2 documents layout-engine tradeoffs and engine-specific
|
|
40
|
-
feature gaps. The pattern across competitors is **separated surfaces and explicit layout engines**,
|
|
41
|
-
not a single geometry model for every diagram and output.
|
|
42
|
-
- **Theming practice:** Mermaid's `themeVariables` remain a compatibility requirement. The 2026
|
|
43
|
-
Design Tokens Community Group draft reinforces a named-token/alias direction, but it is explicitly
|
|
44
|
-
a preview and not a W3C standard. The best current move is therefore the implemented
|
|
45
|
-
`DiagramColors`/CSS-variable waist with semantic role slots, not importing a full design-token JSON
|
|
46
|
-
object into the public API.
|
|
47
|
-
- **Testing practice:** The testing-best-practices guidance maps directly to this refactor:
|
|
48
|
-
characterization/snapshot tests for byte-stable rendering, property tests for parser/config/layout
|
|
49
|
-
invariants, doc-sync tests for registry/docs drift, visual/pixel contracts where SVG appearance is
|
|
50
|
-
the output, and mutation lanes as adequacy checks. The implementation added direct registry dispatch
|
|
51
|
-
coverage (`render-family-hooks.test.ts`) and rides the existing 4k+ suite, property tests, visual
|
|
52
|
-
contracts, and mutation configuration.
|
|
53
|
-
|
|
54
|
-
### Updated Closure Matrix
|
|
55
|
-
|
|
56
|
-
| Issue | Original claim | Reappraisal | Implemented/spec outcome |
|
|
57
|
-
|---|---|---|---|
|
|
58
|
-
| I1 | Three dispatch mechanisms should converge on `FamilyPlugin`. | Still best. Registry iteration also needs deterministic order. | SVG and ASCII route through `layout`/`renderSvg`/`renderAscii` hooks; `knownFamilies()` is metadata-ordered. |
|
|
59
|
-
| I2 | Renderer signatures should collapse to `RenderContext`. | Still best; keep context thin. | All SVG renderers consume `{ positioned, colors, options }`. |
|
|
60
|
-
| I3 | Add a shared `PositionedDiagram` marker but do not invent a universal IR. | Still best; competitors and MLIR/Graphviz reinforce dialect-style geometry. | `PositionedDiagram` exists; family positioned types remain specialized. |
|
|
61
|
-
| I4 | Push parse/layout/render leaks down. | Mostly best; architecture legitimately needs layout metrics, not whole visual config. | Pie colors are render-time, xychart frontmatter is post-parse middleware, Gantt has a named pipeline, architecture passes layout metrics and render visual separately. |
|
|
62
|
-
| I5 | Consolidate color models onto one internal waist. | Still best; do not adopt full design-token spec yet. | `resolveDiagramColors` normalizes options/themes/themeVariables; inline style resolvers and role color slots feed families. |
|
|
63
|
-
| I6 | Split fake certificate union by what each certificate proves. | Still best. | `EdgeRouteCertificate`, `FamilyEdgeRouteCertificate`, and `RegionContainmentCertificate` are explicit; `layoutCertificateProof` exhaustively classifies them. |
|
|
64
|
-
| I7 | Prefer structured-body layout over reparsing `canonicalSource`. | Revised. Prefer registered **layout hooks over duplicated public dispatch**, but keep source context as the hook input. Body-only layout is future work only for families that can prove it is lossless. | `FamilyPlugin.layout(ctx)` owns source-to-positioned layout; structured render paths avoid stale `canonicalSource` where supported without breaking opaque bodies. |
|
|
65
|
-
| I8 | Keep ASCII geometry isolated; share only family-set/dispatch. | Still best; PlantUML/D2 reinforce output-specific geometry. | ASCII uses `renderAscii` hooks but retains grid layout/A* internals. |
|
|
66
|
-
| I9 | Delete vestigial re-export and dead parameters; normalize names opportunistically. | Still best, but broad rename churn is lower priority than behavior-preserving closure. | `src/layout.ts` is gone and unused renderer `_options` are folded into `RenderContext`; broad naming normalization remains optional churn, not issue-blocking. |
|
|
67
|
-
|
|
68
|
-
> Web access note: WebSearch/WebFetch **were available** in this environment. Every citation
|
|
69
|
-
> below was bibliographically verified against authoritative records (dblp, arXiv, official
|
|
70
|
-
> project pages, publisher catalogs). A handful of canonical landing pages return HTTP 403/402
|
|
71
|
-
> to automated fetches (ACM DL, IEEE Xplore, Wiley) — those are flagged inline and an open mirror
|
|
72
|
-
> is given where one exists. No URLs or page numbers were fabricated. See **References** for the
|
|
73
|
-
> full list with verification status.
|
|
74
|
-
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
## 0. The shape of the problem, in the literature's terms
|
|
78
|
-
|
|
79
|
-
The audit's baseline finding — the same ~12 diagram **families** were processed by ~5 **operations**
|
|
80
|
-
(parse, layout, render-SVG, render-ASCII, mutate, verify) across **three** stacks (SVG, ASCII,
|
|
81
|
-
agent IR) with **three** dispatch mechanisms — is, almost exactly, two classic problems stacked
|
|
82
|
-
on top of each other:
|
|
83
|
-
|
|
84
|
-
1. **The Expression Problem** (Wadler 1998) along the *families × operations* plane. We want to
|
|
85
|
-
add new families *and* new operations without editing everything. The agent stack's
|
|
86
|
-
`FamilyPlugin` registry is a partial solution on this plane; the SVG and ASCII `switch`
|
|
87
|
-
statements are the textbook *failing* decomposition Wadler describes.
|
|
88
|
-
2. **Two-dimensional variability** (GoF **Bridge**) along the *families × surfaces* plane. We have
|
|
89
|
-
M families that must each be expressed over N surfaces (SVG / PNG / ASCII / agent IR). A single
|
|
90
|
-
inheritance/dispatch hierarchy forces an M×N explosion; Bridge's whole motivation is collapsing
|
|
91
|
-
that product into a sum (M + N).
|
|
92
|
-
|
|
93
|
-
Two framing facts constrain every recommendation:
|
|
94
|
-
|
|
95
|
-
- **Determinism is a hard constraint** (CLAUDE.md: identical input → identical geometry). This is
|
|
96
|
-
the single biggest reason several theoretically attractive solutions (multimethods, import-order
|
|
97
|
-
registries) are *wrong here*: a mutable global registry populated at import time introduces
|
|
98
|
-
registration-order sensitivity, which is exactly the kind of hidden nondeterminism the repo
|
|
99
|
-
forbids. Any registry we lean on must have a **fixed, explicit** registration order.
|
|
100
|
-
- **The status quo is not naïve.** A discriminated union + `switch` is the **ADT pole** of Cook's
|
|
101
|
-
duality (OOPSLA 2009): operations are cheap, *variants* are costly. TypeScript's `never`-based
|
|
102
|
-
exhaustiveness check makes "I added a family" a compile error at every unhandled
|
|
103
|
-
site — a real, free safety net we should *preserve*, not trade away for runtime polymorphism.
|
|
104
|
-
|
|
105
|
-
The literature does **not** say "unify everything." Metz ("The Wrong Abstraction") and Moseley &
|
|
106
|
-
Marks ("Out of the Tar Pit") jointly warn that collapsing parallel stacks is a win only when the
|
|
107
|
-
removed duplication is *accidental*, not *essential*. The ASCII stack (I8) is the clearest case
|
|
108
|
-
where the duplication is essential and isolation is **correct as-is** (see §I8).
|
|
109
|
-
|
|
110
|
-
### Which pattern opens which axis (the cheat sheet)
|
|
111
|
-
|
|
112
|
-
| Approach | New operation | New family | Fit for this repo (deterministic, union + switch, TS) |
|
|
113
|
-
|---|---|---|---|
|
|
114
|
-
| Discriminated union + `switch` (status quo) | easy | **hard** (edit every switch) | native, deterministic, exhaustiveness-checked |
|
|
115
|
-
| Visitor (GoF) | easy | **hard** (GoF's own listed liability) | inverts our easy axis; adds ceremony — wrong direction |
|
|
116
|
-
| Object Algebras (Oliveira & Cook) | easy | easy | symmetric but boilerplate-heavy; loses inspectable data |
|
|
117
|
-
| Tagless-final (Carette/Kiselyov/Shan) | easy | easy | fights TS structural typing + breaks JSON serialization |
|
|
118
|
-
| Multimethods (Clojure/Julia) | easy | easy | non-idiomatic; global registry → **order nondeterminism** |
|
|
119
|
-
| **Plugin registry + record-of-functions** (the agent stack) | easy | easy | **best fit** — keeps unions internally, opens both axes at the seam |
|
|
120
|
-
|
|
121
|
-
The recommendation that runs through everything below: **generalize the pattern the agent stack
|
|
122
|
-
already proved** (`FamilyPlugin` as a record of per-family functions in an explicitly-ordered
|
|
123
|
-
registry), rather than importing GoF class hierarchies or FP encodings that TypeScript renders
|
|
124
|
-
awkward. This is the Microkernel/plug-in architecture (POSA1) realized in the idiom the codebase
|
|
125
|
-
already uses, and it is the concrete form of "make the waist thin" (the hourglass principle).
|
|
126
|
-
|
|
127
|
-
---
|
|
128
|
-
|
|
129
|
-
## I1 — Three dispatch mechanisms; the best one is least used
|
|
130
|
-
|
|
131
|
-
**(a) Lens.** This is the **Expression Problem** (Wadler 1998) plus the **Microkernel/plug-in**
|
|
132
|
-
architectural pattern (POSA1, Buschmann et al. 1996). The agent stack's
|
|
133
|
-
`FamilyPlugin` in `Map<DiagramKind, FamilyPlugin>` (`src/agent/families.ts`) *is* a microkernel: a
|
|
134
|
-
minimal core that owns only registration + dispatch, with each family a plug-in. At audit time, the
|
|
135
|
-
SVG and ASCII public entrypoints also had hand-written `switch(diagramType)` statements; that was the
|
|
136
|
-
decomposition Wadler shows fails — adding a family meant editing three sites that could not
|
|
137
|
-
drift-check each other.
|
|
138
|
-
|
|
139
|
-
**(b) Prescription.** Keep one core that knows only the registration/dispatch contract; deliver all
|
|
140
|
-
per-family behavior as registered plug-ins (Parnas 1972: hide the decision "which family is this?"
|
|
141
|
-
behind one module). Add the missing operations to the existing plug-in interface.
|
|
142
|
-
|
|
143
|
-
**(c) Recommendation.** Extend `FamilyPlugin` with the two operations it lacks:
|
|
144
|
-
|
|
145
|
-
```
|
|
146
|
-
renderSvg?: (ctx: RenderContext) => string // see I2 for RenderContext
|
|
147
|
-
renderAscii?: (ctx: AsciiContext) => string
|
|
148
|
-
layout?: (ctx: FamilyLayoutContext) => FamilyLayoutResult | PositionedDiagram
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
The now-implemented end state routes public SVG and ASCII rendering through keyed registry lookup
|
|
152
|
-
(`getFamily(kind)`) and the hooks above. If this pattern is repeated in another surface, keep the same
|
|
153
|
-
incremental migration rule used here: move one family at a time behind snapshot tests, then delete the
|
|
154
|
-
fallback dispatch only after every family has a hook.
|
|
155
|
-
|
|
156
|
-
**(d) Tradeoffs / determinism risk.** The registry is a `Map` populated at import in
|
|
157
|
-
`families-builtin.ts`. **Risk:** if dispatch ever iterates the registry (e.g. `knownFamilies()`
|
|
158
|
-
feeding a render order), `Map` insertion order makes output import-order-sensitive. **Mitigation:**
|
|
159
|
-
dispatch is always *keyed* (`getFamily(kind)`), never *iterated* for geometry; keep it that way, and
|
|
160
|
-
sort any iteration by the fixed `BUILTIN_FAMILY_METADATA` array order (`families.ts:77`), which is
|
|
161
|
-
source-defined and stable. With keyed lookup, determinism is unaffected — the `Map` is a lookup
|
|
162
|
-
table, not an ordering.
|
|
163
|
-
|
|
164
|
-
**(e) Where theory doesn't transfer.** Wadler's full bar (separate *compilation*, open to
|
|
165
|
-
*third-party* extension) is stronger than we need: families are in-tree and finite. The microkernel
|
|
166
|
-
"earns its keep" argument assumes numerous or third-party plug-ins; here the registry's value is not
|
|
167
|
-
extensibility-for-strangers but **drift elimination** (one dispatch site instead of three). That is
|
|
168
|
-
still decisive — I1 is the audit's "highest-leverage target" and this is **mechanical, low-risk,
|
|
169
|
-
high-value** — but justify it as *de-duplication of dispatch*, not as open extensibility we won't use.
|
|
170
|
-
|
|
171
|
-
---
|
|
172
|
-
|
|
173
|
-
## I2 — Renderer signature drift + redundant `(colors, font, transparent, options)` threading
|
|
174
|
-
|
|
175
|
-
**(a) Lens.** **Lampson's "do one thing well" / simple predictable interfaces** (Hints, 1983) and
|
|
176
|
-
**Parameter Object** discipline. The canonical `renderSvg(positioned, colors, font='Inter',
|
|
177
|
-
transparent=false, options={})` (`src/renderer.ts:37`) has drifted into 4-, 6-, and 7-arg variants
|
|
178
|
-
(`renderTimelineSvg` has 7; `renderArchitectureSvg`'s `visual` *replaces* `options`;
|
|
179
|
-
`renderPie/QuadrantSvg` accept `_options` they ignore). Three positional args are already
|
|
180
|
-
redundant: `font` is folded into `colors` (`resolveDiagramColors(options, config, font)` sets
|
|
181
|
-
`DiagramColors.font`), and `transparent` is a lone boolean.
|
|
182
|
-
|
|
183
|
-
**(b) Prescription.** Collapse the positional tail into one **capability/context object** — a single
|
|
184
|
-
predictable interface every renderer accepts (Lampson; Strategy's "one interface, many
|
|
185
|
-
implementations"). An unused `_options` parameter advertises a contract the function does not honor;
|
|
186
|
-
remove it (this also closes part of I9).
|
|
187
|
-
|
|
188
|
-
**(c) Recommendation.** Introduce
|
|
189
|
-
|
|
190
|
-
```
|
|
191
|
-
interface RenderContext { positioned: PositionedDiagram; colors: DiagramColors; options: RenderOptions }
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
with `font` read from `colors.font` and `transparent` moved into `options` (or `colors`). Family-specific
|
|
195
|
-
extras become *typed fields on a per-family options slice*, not positional args:
|
|
196
|
-
`options.timeline`, `options.xychart.interactive`, `options.architecture.visual`. Every `render*Svg`
|
|
197
|
-
becomes `(ctx: RenderContext) => string`. This is a no-op on geometry, so it is pure refactor.
|
|
198
|
-
|
|
199
|
-
**(d) Tradeoffs / determinism risk.** Essentially none for geometry — same inputs, same outputs;
|
|
200
|
-
verify with snapshot tests. Minor risk: defaulting (`font='Inter'`, `transparent=false`) must be
|
|
201
|
-
applied at the *boundary* (`resolveDiagramColors` plus the public render entrypoint's context
|
|
202
|
-
construction) so no call site silently changes a default. Make the defaults explicit in one
|
|
203
|
-
constructor, not scattered.
|
|
204
|
-
|
|
205
|
-
**(e) Where theory doesn't transfer.** A Parameter Object can become a god-bag if every family dumps
|
|
206
|
-
unrelated config into it. Keep `RenderContext` thin (3 fields) and push family-specifics into a typed,
|
|
207
|
-
optional, **per-family** sub-slice so the shared type stays a narrow waist rather than a union of
|
|
208
|
-
everything. This dovetails with I1: `FamilyPlugin.renderSvg(ctx)` is the natural consumer.
|
|
209
|
-
|
|
210
|
-
---
|
|
211
|
-
|
|
212
|
-
## I3 — No shared `Positioned*` contract; two parallel layout-output models
|
|
213
|
-
|
|
214
|
-
**(a) Lens.** This is the **single-IR vs. many-dialects** question (LLVM, CGO 2004; MLIR, arXiv
|
|
215
|
-
2002.11054) crossed with the **graph-drawing layout/render boundary** (Graphviz GN99; ELK). The 11
|
|
216
|
-
`Positioned*`/`*LayoutResult` types each re-declare `width`/`height` with no base interface
|
|
217
|
-
(`src/types.ts:91,303,…`), and the agent stack carries a *second* normalized model, `RenderedLayout`
|
|
218
|
-
(`agent/types.ts:908`), that the SVG stack never consumes. "A laid-out diagram" has no canonical type.
|
|
219
|
-
|
|
220
|
-
**(b) Prescription.** Graphviz and ELK both prescribe a clean layout→render boundary communicating
|
|
221
|
-
through *one* annotated-geometry structure: layout emits positions, renderers consume them. LLVM
|
|
222
|
-
prescribes a single shared IR at the waist. **But** MLIR's caution is the more honest fit: when the
|
|
223
|
-
levels genuinely differ, model them as distinct dialects and *lower progressively* rather than forcing
|
|
224
|
-
one universal type.
|
|
225
|
-
|
|
226
|
-
**(c) Recommendation — the calibrated version.** Do **not** attempt to merge all 11 `Positioned*`
|
|
227
|
-
types into one universal geometry IR (see (e)). Instead, two cheap, high-value moves:
|
|
228
|
-
|
|
229
|
-
1. **Introduce a marker base interface** the 11 types extend:
|
|
230
|
-
`interface PositionedDiagram { width: number; height: number }`. This is the *thin waist* — it
|
|
231
|
-
gives `RenderContext`, `FamilyPlugin.layout`, and PNG/SVG entrypoints **one** type to name without
|
|
232
|
-
forcing structural unification of the bodies. Minimal, mechanical, and it makes I2's `RenderContext`
|
|
233
|
-
well-typed.
|
|
234
|
-
2. **Make the `PositionedGraph → RenderedLayout` lowering explicit.** Per `AGENT_NATIVE.md` §1,
|
|
235
|
-
`RenderedLayout` (the layout JSON) is the *canonical determinism/equality artifact* — "two render
|
|
236
|
-
results are equal iff their layout JSON is structurally equal," pinned by the cross-process and
|
|
237
|
-
drift-sentinel tests — so it is **not** a debug view to demote. The two models sit at genuinely
|
|
238
|
-
different levels (MLIR-style dialects): `PositionedDiagram` is SVG-facing geometry, `RenderedLayout`
|
|
239
|
-
is the surface-neutral equality oracle. The fix is to make one *derive from* the other through an
|
|
240
|
-
explicit lowering (`agent/layout-to-rendered.ts`), never built in parallel, so the two cannot diverge.
|
|
241
|
-
|
|
242
|
-
**(d) Tradeoffs / determinism risk.** Adding a marker base is zero-runtime and deterministic. The real
|
|
243
|
-
risk is over-reach: a too-rich shared base (ports, edges, groups) would force every family to satisfy
|
|
244
|
-
fields it doesn't have, re-creating the I2 god-bag at the type level. Keep the base to
|
|
245
|
-
`{ width, height }` and let families add their own fields — this is structurally what they already do.
|
|
246
|
-
|
|
247
|
-
**(e) Where theory doesn't transfer (important).** LLVM's single-IR success depended on the IR being
|
|
248
|
-
**genuinely universal** across real languages and targets. Diagram `Positioned*` models may be too
|
|
249
|
-
family-specific to unify (a Gantt timeline's bars, a sequence diagram's lifelines, and a pie's wedges
|
|
250
|
-
share little beyond a bounding box). Forcing one IR here risks Metz's "wrong abstraction": a union type
|
|
251
|
-
that accretes conditionals. The marker-base + progressive-projection design captures the *real* shared
|
|
252
|
-
contract (a bounding box and a render target) without paying for unification we'd immediately special-case.
|
|
253
|
-
|
|
254
|
-
---
|
|
255
|
-
|
|
256
|
-
## I4 — Layering leaks: render/config concerns pushed up into parse and layout
|
|
257
|
-
|
|
258
|
-
**(a) Lens.** Direct hit for **Parnas (1972/1979)** information hiding and the **Graphviz/ELK
|
|
259
|
-
layout-vs-render boundary**. The leaks are decisions placed in the wrong module:
|
|
260
|
-
- Audit-time `layoutPieChart(chart, options, colors)` — layout consumed `DiagramColors` to assign slice colors.
|
|
261
|
-
- `layoutArchitectureDiagram(diagram, options, visual)` + `resolveArchitectureVisualConfig` — visual
|
|
262
|
-
config threaded through *both* layout and render, bypassing `options`.
|
|
263
|
-
- Audit-time `parseXYChart(lines, frontmatter)` — theme/frontmatter was baked in during *parsing*.
|
|
264
|
-
- Gantt is a hand-wired **4-stage** pipeline in `index.ts:404`.
|
|
265
|
-
|
|
266
|
-
ELK's prescription is unambiguous: layout is a *pure geometry service*; color and visual styling are
|
|
267
|
-
rendering concerns downstream of coordinates.
|
|
268
|
-
|
|
269
|
-
**(b) Prescription.** Push each decision down to the layer that owns it (Parnas: hide the decision in
|
|
270
|
-
one module behind a stable interface). Color/visual resolution belongs at **render**; frontmatter
|
|
271
|
-
application belongs in a **post-parse middleware** stage, not inside the parser.
|
|
272
|
-
|
|
273
|
-
**(c) Recommendation.**
|
|
274
|
-
- **Pie:** move slice-color assignment out of `layoutPieChart` into the pie renderer. Layout emits
|
|
275
|
-
*uncolored* wedge geometry (angles, radii); the renderer colors them from `ctx.colors`. Determinism
|
|
276
|
-
is preserved because color assignment is a pure function of slice index/order.
|
|
277
|
-
- **Architecture:** resolve `visual` at render (`renderArchitectureSvg` reads `ctx.options.architecture.visual`);
|
|
278
|
-
if layout genuinely needs a *metric* (e.g. icon size affects box size), pass that **one number**
|
|
279
|
-
explicitly, not the whole visual config. This is the legitimate exception — note it honestly.
|
|
280
|
-
- **XY chart:** model frontmatter as **post-parse middleware**, exactly as Gantt already does
|
|
281
|
-
(`applyGanttFrontmatterConfig`). `parseXYChart` returns the structural model; a separate
|
|
282
|
-
`applyXYChartFrontmatter` stage folds theme in. This makes the two pipelines *consistent* (I9 too).
|
|
283
|
-
- **Gantt:** the 4-stage pipeline is **not a leak — it is correct** (see (e)); formalize it as a named
|
|
284
|
-
pipeline rather than inline wiring in `index.ts:404`.
|
|
285
|
-
|
|
286
|
-
**(d) Tradeoffs / determinism risk.** Moving color assignment from layout to render must keep the
|
|
287
|
-
*same deterministic ordering* (slice order, palette index). This is the highest-determinism-risk item
|
|
288
|
-
in I4: a snapshot diff is mandatory and the palette-index function must be lifted verbatim, not
|
|
289
|
-
re-derived. Architecture's icon-size-affects-layout coupling means you cannot fully purify its layout;
|
|
290
|
-
document the residual.
|
|
291
|
-
|
|
292
|
-
**(e) Where theory doesn't transfer.** "Parsing must be pure" is too strong. Gantt's multi-stage shape
|
|
293
|
-
(`parse → applyFrontmatter → resolveSchedule → layout`) is the **textbook Sugiyama-style staged
|
|
294
|
-
pipeline** (Sugiyama/Tagawa/Toda 1981) and a Parnas "uses"-hierarchy done right — each stage consumes
|
|
295
|
-
the prior stage's output. The fix for Gantt is to *name and document* the pipeline, not flatten it.
|
|
296
|
-
Likewise, architecture's metric coupling (icon size → box size) is *essential* layout input, not a leak.
|
|
297
|
-
|
|
298
|
-
---
|
|
299
|
-
|
|
300
|
-
## I5 — Styling: five parallel color models; N ways to set one property
|
|
301
|
-
|
|
302
|
-
**(a) Lens.** **Parnas information hiding** + the **narrow-waist / hourglass** principle (Beck, CACM
|
|
303
|
-
2019) + **"Parse, don't validate"** (Alexis King 2019). Five color models
|
|
304
|
-
(`RenderOptions → DiagramColors → ResolvedColors`, plus `MermaidThemeVariables` and
|
|
305
|
-
`classDefs/nodeStyles/linkStyles`) mean **node fill is reachable 5 ways** and **group border 3 ways**
|
|
306
|
-
(audit §I5). That is five representations of one decision — the opposite of a narrow waist.
|
|
307
|
-
|
|
308
|
-
**(b) Prescription.** Pick **one internal color contract** (the waist) and *normalize every external
|
|
309
|
-
spelling into it at the boundary* (King: parse the many input dialects into one precise internal type,
|
|
310
|
-
once, so downstream code never re-resolves). Everything below the waist sees only the canonical model.
|
|
311
|
-
|
|
312
|
-
**(c) Recommendation.** Make **`DiagramColors` (+ the CSS-custom-property layer) the single internal
|
|
313
|
-
contract.** Treat `MermaidThemeVariables`, `classDefs/nodeStyles/linkStyles`, and `RenderOptions` as
|
|
314
|
-
**input dialects** that a boundary function (`resolveDiagramColors`) *parses* into `DiagramColors`
|
|
315
|
-
— after which no renderer consults the raw dialects. Concretely: the precedence rule "classDef beats
|
|
316
|
-
themeVariables beats RenderOptions" lives in **one** resolver, not scattered across families. Keep the
|
|
317
|
-
public custom-style surface to Style + Palette, and let built-in looks map into the internal style face
|
|
318
|
-
so pie/quadrant/gantt/architecture reach typography, spacing, and color through the same waist.
|
|
319
|
-
|
|
320
|
-
**(d) Tradeoffs / determinism risk.** Color resolution is already deterministic; the risk is *changing
|
|
321
|
-
precedence* during consolidation. Lock current precedence with tests *before* refactoring (golden
|
|
322
|
-
renders per input dialect), then prove the consolidated resolver reproduces them. This is **structural,
|
|
323
|
-
medium-risk** — touch one resolver, verify byte-identical output.
|
|
324
|
-
|
|
325
|
-
**(e) Where theory doesn't transfer.** Five models did not appear by accident — `MermaidThemeVariables`
|
|
326
|
-
exists for **Mermaid compatibility**, `classDefs` for **inline-directive fidelity**. The waist must
|
|
327
|
-
*absorb* these dialects at the boundary, not abolish them; users still author them. "One color model"
|
|
328
|
-
is the *internal* invariant, not a user-facing reduction. Over-collapsing (dropping classDef support to
|
|
329
|
-
simplify) would be a correctness regression, not a cleanup.
|
|
330
|
-
|
|
331
|
-
---
|
|
332
|
-
|
|
333
|
-
## I6 — "Route contracts" is two abstractions sharing one type union
|
|
334
|
-
|
|
335
|
-
**(a) Lens.** **"Making illegal states unrepresentable"** (Minsky) and **ADTs + exhaustiveness checking**.
|
|
336
|
-
At audit time, `LayoutRouteCertificate = RouteCertificate | FamilyRouteCertificate` looked unified
|
|
337
|
-
but the arms shared neither producer, consumer, nor lifecycle:
|
|
338
|
-
- `RouteCertificate` (flowchart) was keyed by `edgeIndex`, carried `invariant: 'straight' | …`, and
|
|
339
|
-
was produced in **core** (`route-contracts.ts`, attached to `PositionedEdge.routeCertificate`).
|
|
340
|
-
- The old `FamilyRouteCertificate` shape mixed edge proofs (class/ER, architecture, sequence) with
|
|
341
|
-
element/region proofs (timeline/xychart/pie/quadrant/gantt), so some members were keyed by
|
|
342
|
-
`edgeIndex` while others were keyed by `elementId`.
|
|
343
|
-
|
|
344
|
-
A union whose arms have different *keys* (`edgeIndex` vs `elementId`) and different lifecycles is a
|
|
345
|
-
*structural* union, not a *semantic* one — it permits illegal states (a "certificate" with no producer
|
|
346
|
-
on a given path).
|
|
347
|
-
|
|
348
|
-
**(b) Prescription.** Minsky: the type should make the real distinctions visible. Either (i) **split the
|
|
349
|
-
type** to reflect that there are genuinely two-or-three different certificate concepts, or (ii) **unify
|
|
350
|
-
the lifecycle** by producing family certs in the core layout path so the union becomes real.
|
|
351
|
-
|
|
352
|
-
**(c) Recommendation — split, don't fake-unify.** Rename to expose reality:
|
|
353
|
-
The implemented split names what each certificate proves:
|
|
354
|
-
`EdgeRouteCertificate = RouteCertificate | FamilyEdgeRouteCertificate` for edge-indexed route proofs,
|
|
355
|
-
and `RegionContainmentCertificate` for element/region containment proofs. The umbrella
|
|
356
|
-
`LayoutRouteCertificate` remains only as a debug-sidecar sum whose members are **named by what they
|
|
357
|
-
prove**. `layoutCertificateProof` switches exhaustively over those names so a new certificate kind is
|
|
358
|
-
a compile error, not a silent gap.
|
|
359
|
-
|
|
360
|
-
**(d) Tradeoffs / determinism risk.** This is a **type-level rename + redocument** with no geometry
|
|
361
|
-
change — low determinism risk. The discipline risk is that the agent verify path and core route path
|
|
362
|
-
must agree on which certs exist where; an exhaustive `switch` with a `never` default enforces it.
|
|
363
|
-
|
|
364
|
-
**(e) Where theory doesn't transfer.** Option (ii) — "produce family certs in core layout so the union
|
|
365
|
-
is real" — is the *theoretically cleaner* unification but likely the **wrong call**: family layouts live
|
|
366
|
-
in `agent/family-layouts.ts` precisely because the core SVG render path for families doesn't need
|
|
367
|
-
certificates to draw. Forcing the core to mint containment certs it never reads is work for symmetry's
|
|
368
|
-
sake (Metz). **Prefer the split (i).** Honesty over false unification.
|
|
369
|
-
|
|
370
|
-
---
|
|
371
|
-
|
|
372
|
-
## I7 — The agent layer is the reference design — with two seams
|
|
373
|
-
|
|
374
|
-
**(a) Lens.** **"Parse, don't validate"** (King 2019) and **"illegal states unrepresentable"** (Minsky).
|
|
375
|
-
`ValidDiagram { kind, meta, body, source, canonicalSource }` + `DiagramBody` (12 structured bodies | the
|
|
376
|
-
`{ kind: 'opaque'; family; source }` fallback, `agent/types.ts:501,521`) + `Result<T,E>`
|
|
377
|
-
(`agent/types.ts:14`) is exactly King's "parse the input into a precisely-typed value at the boundary."
|
|
378
|
-
`ValidDiagram` *is* the parsed type; the opaque arm is the honest "we recognized the family but not the
|
|
379
|
-
syntax" state — a model worth celebrating, not fixing. The two seams are real, though:
|
|
380
|
-
|
|
381
|
-
- **(seam a) Mutation ops are duck-typed:** `mutate(body, op: AnyMutationOp)` with each family
|
|
382
|
-
narrowing via `if (body.kind !== 'class') return err(...)`.
|
|
383
|
-
- **(seam b) Layout re-parses `canonicalSource`** through the core per-family parser instead of using
|
|
384
|
-
the family registry as the owner of layout dispatch — a text round-trip that can couple agent layout
|
|
385
|
-
to *serializer fidelity* for L3/L4 structured bodies.
|
|
386
|
-
|
|
387
|
-
**(b) Prescription.** Minsky: push the narrowing into the *type* so an op can only reach a body it
|
|
388
|
-
applies to. King: don't round-trip through text you already parsed — operate on the structured value.
|
|
389
|
-
|
|
390
|
-
**(c) Recommendation.**
|
|
391
|
-
- **(seam a):** keep duck-typed narrowing for now — it is *cheap and safe* (the `err(...)` is correct,
|
|
392
|
-
just verbose). If desired, route mutation through `FamilyPlugin.mutate` (already in the interface,
|
|
393
|
-
`families.ts:55`) so each family owns its narrowing in one place rather than re-checking at every op.
|
|
394
|
-
This is the I1 registry paying off again. **Low priority** — it is verbosity, not a bug.
|
|
395
|
-
- **(seam b) is the structural one — but reconciled, lower-urgency.** Give `FamilyPlugin` a
|
|
396
|
-
source-context `layout?(ctx)` hook (I1/I3) and prefer it over public-entrypoint switch statements.
|
|
397
|
-
This lets each family own the exact parse/config/layout pipeline it needs while preserving
|
|
398
|
-
frontmatter, accessibility directives, and opaque-source semantics. Per `AGENT_NATIVE.md` §3,
|
|
399
|
-
however, `canonicalSource` is the *documented* "round-trip pillar" ("structured renderers use this
|
|
400
|
-
as input") and the coupling is already guarded by round-trip identity property tests — so direct
|
|
401
|
-
**structured-body** layout is a future decoupling/perf option, not the closure requirement, and it
|
|
402
|
-
applies only to **L3/L4** structured bodies. For **L1** opaque bodies, text is the representation and
|
|
403
|
-
re-parsing is correct.
|
|
404
|
-
|
|
405
|
-
**(d) Tradeoffs / determinism risk.** The source-context hook is lower-risk than the original body-only
|
|
406
|
-
wording because it moves dispatch without changing which source dialects a family can faithfully
|
|
407
|
-
understand. A later body-direct layout path is higher-risk: it must produce *byte-identical* geometry
|
|
408
|
-
to the source-context path, or it is a behavior change. Gate any such migration per family with
|
|
409
|
-
snapshot tests; migrate only families whose body is a faithful superset of what the parser
|
|
410
|
-
reconstructs. Some families may *not* round-trip losslessly today — for those, keeping source-context
|
|
411
|
-
layout is the honest call.
|
|
412
|
-
|
|
413
|
-
**(e) Where theory doesn't transfer.** "Never round-trip through text" is too absolute. For the **opaque**
|
|
414
|
-
body, text *is* the only representation — source-context layout is correct and unavoidable. The
|
|
415
|
-
body-direct optimization applies strictly to **structured** bodies. And duck-typed narrowing (seam a)
|
|
416
|
-
is a non-issue the theory would over-engineer; resist the urge to build a typed op-dispatch matrix for
|
|
417
|
-
it.
|
|
418
|
-
|
|
419
|
-
---
|
|
420
|
-
|
|
421
|
-
## I8 — ASCII is a parallel universe — mostly justified
|
|
422
|
-
|
|
423
|
-
**(a) Lens.** **Metz, "The Wrong Abstraction"** ("duplication is far cheaper than the wrong
|
|
424
|
-
abstraction") and **Moseley & Marks, essential vs. accidental complexity**. The `ascii/` stack (~9.6k
|
|
425
|
-
lines) shares nothing large with SVG: own `AsciiGraph`/`Canvas`/`RoleCanvas`, own A* pathfinder, own
|
|
426
|
-
per-family layouts; it reuses only `NodeShape`, `EdgeStyle`, `RouteClass`, and `shared/unicode-ranges.ts`.
|
|
427
|
-
|
|
428
|
-
**(b) Prescription.** Metz: do **not** force a shared abstraction when the back-ends differ
|
|
429
|
-
*essentially*. The differences here are essential: **character-cell grid geometry** (integer snapping,
|
|
430
|
-
monospace metrics, no sub-cell positioning) versus **float vector geometry**. A unified geometry model
|
|
431
|
-
would accrete per-call special-casing — the exact tangle Metz warns about, which *raises* accidental
|
|
432
|
-
complexity while looking DRY.
|
|
433
|
-
|
|
434
|
-
**(c) Recommendation. Leave ASCII isolated.** This is the explicit "academic ideal is the wrong call
|
|
435
|
-
here" case: the theoretically-tidy move (one geometry IR for both surfaces) is **wrong**. ASCII is
|
|
436
|
-
*internally* well-abstracted (it already has the pluggable `ShapeRenderer` registry the SVG side lacks —
|
|
437
|
-
note the irony: ASCII is ahead of SVG on intra-stack abstraction). The only defensible sharing is at the
|
|
438
|
-
*topology* level, never the *geometry* level: families/`RouteClass` classification and "which families
|
|
439
|
-
exist" could flow from the I1 registry (an ASCII renderer is just another `FamilyPlugin.renderAscii`
|
|
440
|
-
hook), so the **family-set** stops being declared twice even though the **layout** stays separate.
|
|
441
|
-
|
|
442
|
-
**(d) Tradeoffs / determinism risk.** Routing ASCII through the I1 registry's `renderAscii` hook is the
|
|
443
|
-
*only* I8 change worth making, and it is low-risk (dispatch only, not geometry). The cost the audit
|
|
444
|
-
names — "shape / edge-routing / fan-in-out exist twice, so parity changes need two edits" — is **real
|
|
445
|
-
and worth accepting**: it is the price of two genuinely different geometries. Track parity with a
|
|
446
|
-
shared *test corpus*, not shared *code*.
|
|
447
|
-
|
|
448
|
-
**(e) Where theory doesn't transfer.** None needed — this is the case where the theory (Metz) *correctly*
|
|
449
|
-
says "stop." The one nuance: "essential" is a judgment that can change. If ASCII and SVG ever converge on
|
|
450
|
-
a shared *intermediate topology* (post-ELK, pre-geometry), revisit — but only when a forced change proves
|
|
451
|
-
they've actually converged, never preemptively.
|
|
452
|
-
|
|
453
|
-
---
|
|
454
|
-
|
|
455
|
-
## I9 — Vestigial / cosmetic
|
|
456
|
-
|
|
457
|
-
**(a) Lens.** **Lampson** ("do one thing well"; remove needless indirection) and **TypeScript exhaustiveness checking**.
|
|
458
|
-
At audit time, `src/layout.ts` was a one-line re-export of `layoutGraphSync`
|
|
459
|
-
(pure indirection); naming was inconsistent (`parseXDiagram` vs `parseXChart`
|
|
460
|
-
vs `parseGanttModel`; `Sync` suffix on only 3 of 11 sync layout fns);
|
|
461
|
-
`_options` params (pie/quadrant) advertised a contract not honored.
|
|
462
|
-
|
|
463
|
-
**(b/c) Prescription / recommendation.** Pure hygiene, **mechanical, lowest-risk**, do alongside the
|
|
464
|
-
structural work it touches:
|
|
465
|
-
- Issue #71 inlined `src/layout.ts`'s re-export at call sites and deleted the file (Lampson: needless indirection).
|
|
466
|
-
- Normalize naming to one convention (`parse<Family>` / `layout<Family>`); drop the `Sync` suffix
|
|
467
|
-
(all are sync — the distinction is meaningless). Do this as a **single rename commit** so blame stays
|
|
468
|
-
legible.
|
|
469
|
-
- Delete unused `_options` params — folded into the I2 `RenderContext` migration (an unused param is a
|
|
470
|
-
lie about the interface; King/Lampson both say the type should tell the truth).
|
|
471
|
-
|
|
472
|
-
**(d) Determinism risk.** Zero — renames and dead-param removal don't touch geometry. The only risk is
|
|
473
|
-
*merge churn*; sequence I9's renames **after** the structural refactors (I1–I3) so you rename the final
|
|
474
|
-
names once, not twice.
|
|
475
|
-
|
|
476
|
-
**(e) Where theory doesn't transfer.** Nothing deep here; resist gold-plating (don't invent a naming DSL).
|
|
477
|
-
|
|
478
|
-
---
|
|
479
|
-
|
|
480
|
-
## Closure Roadmap
|
|
481
|
-
|
|
482
|
-
This table supersedes the original issue roadmap. It records the implementation closure criteria after
|
|
483
|
-
the 2026-06-21 reappraisal. Every behavior-affecting row is gated by the repo's snapshot,
|
|
484
|
-
property-based, visual-contract, and determinism tests.
|
|
485
|
-
|
|
486
|
-
| # | Closure criterion | Issues | Status |
|
|
487
|
-
|---|---|---|---|
|
|
488
|
-
| 1 | `RenderContext` + marker `PositionedDiagram`; all SVG renderers use the context object. | I2, I3 | Done. |
|
|
489
|
-
| 2 | Split certificate concepts by proof type; exhaustively classify every certificate variant. | I6 | Done via `EdgeRouteCertificate`, `FamilyEdgeRouteCertificate`, `RegionContainmentCertificate`, and `layoutCertificateProof`. |
|
|
490
|
-
| 3 | Add `layout`/`renderSvg`/`renderAscii` hooks to `FamilyPlugin`; remove public SVG/ASCII switch dispatch; make registry iteration deterministic. | I1, I8 | Done; `knownFamilies()` follows metadata order. |
|
|
491
|
-
| 4 | Move I4 leaks to their owning stages: pie colors at render, xychart config post-parse, named Gantt pipeline, architecture metrics-only layout input. | I4 | Done. |
|
|
492
|
-
| 5 | Consolidate color resolution onto `DiagramColors` + CSS vars and semantic role color slots. | I5 | Done; Mermaid dialects remain accepted at the boundary. |
|
|
493
|
-
| 6 | Prefer registered source-context layout hooks over duplicated public dispatch; reserve body-direct layout for future per-family optimizations that can prove lossless parity. | I7 (seam b) | Done for closure; body-direct layout is not required for issue #71. |
|
|
494
|
-
| 7 | Delete vestigial `src/layout.ts`; remove dead renderer params; avoid broad naming churn unless it falls out naturally. | I9 | Done for blocking hygiene; global rename normalization remains optional. |
|
|
495
|
-
|
|
496
|
-
Seam (a) of I7 (duck-typed mutation) remains deliberately omitted — the registry route would not make a
|
|
497
|
-
typed op-dispatch matrix simpler, and the current public mutation surface is already narrowed by family.
|
|
498
|
-
|
|
499
|
-
---
|
|
500
|
-
|
|
501
|
-
## Where the academic ideal is the *wrong* call here
|
|
502
|
-
|
|
503
|
-
A deliberate list, so reviewers can see the adversarial check was done and not skipped:
|
|
504
|
-
|
|
505
|
-
1. **Do not unify the three stacks into one geometry IR (against a naïve reading of LLVM/MLIR).**
|
|
506
|
-
The `Positioned*` models are too family-specific; a universal IR becomes Metz's "wrong abstraction."
|
|
507
|
-
Use a **marker base** (`{width,height}`) + progressive projection, not unification (I3).
|
|
508
|
-
2. **Keep ASCII isolated (against "DRY the renderers").** Grid vs. float geometry is *essential*
|
|
509
|
-
complexity (Moseley & Marks); a shared model would accrete conditionals. Share only the *family-set*
|
|
510
|
-
via the registry, never the layout (I8).
|
|
511
|
-
3. **Split the certificate union; don't force the core to mint family certs (against symmetry).**
|
|
512
|
-
Producing containment certs the core never reads is work for tidiness' sake; split the type instead (I6).
|
|
513
|
-
4. **Don't build multimethods or a typed op-dispatch matrix in TypeScript (against Clojure/Julia).**
|
|
514
|
-
Non-idiomatic; a global multimethod registry risks **import-order nondeterminism** that violates the
|
|
515
|
-
repo's hard determinism guarantee. The keyed plug-in registry is the right amount of dynamism (I1, I7a).
|
|
516
|
-
5. **Don't purify Gantt's pipeline or parsing dogmatically (against "parse must be pure").**
|
|
517
|
-
Gantt's 4-stage shape is a correct Sugiyama-style staged pipeline (Sugiyama/Tagawa/Toda 1981);
|
|
518
|
-
*name* it, don't flatten it. The opaque body legitimately *is* text and must re-parse (I4, I7e).
|
|
519
|
-
6. **Don't tagless-final / object-algebra the families (against the Expression-Problem "solutions").**
|
|
520
|
-
Both fight TypeScript's structural typing and break the JSON-serializable, inspectable data model the
|
|
521
|
-
agent stack depends on. The registry-of-records is the pragmatic two-axis solution that survives
|
|
522
|
-
serialization and determinism (§0).
|
|
523
|
-
|
|
524
|
-
---
|
|
525
|
-
|
|
526
|
-
## References
|
|
527
|
-
|
|
528
|
-
Verification legend: **[V]** citation + URL content directly confirmed this session; **[D]** citation/DOI
|
|
529
|
-
confirmed via authoritative index (dblp/arXiv/publisher) but the canonical landing page returned 403/402
|
|
530
|
-
to automated fetch (open mirror given where available); **[C]** cited by author/edition/ISBN, page-level
|
|
531
|
-
URL not independently fetched. No URLs or page numbers were fabricated.
|
|
532
|
-
|
|
533
|
-
**Expression Problem & solution patterns**
|
|
534
|
-
- Philip Wadler, "The Expression Problem," email to the Java Genericity list, 12 Nov 1998. **[V]**
|
|
535
|
-
<https://homepages.inf.ed.ac.uk/wadler/papers/expression/expression.txt>
|
|
536
|
-
- William R. Cook, "On Understanding Data Abstraction, Revisited," OOPSLA 2009, pp. 557–572.
|
|
537
|
-
DOI 10.1145/1640089.1640133. **[D]** author PDF <https://www.cs.utexas.edu/~wcook/Drafts/2009/essay.pdf>
|
|
538
|
-
(ACM DOI page paywalled).
|
|
539
|
-
- Mads Torgersen, "The Expression Problem Revisited — Four New Solutions Using Generics," ECOOP 2004,
|
|
540
|
-
LNCS 3086, pp. 123–143. DOI 10.1007/978-3-540-24851-4_6. **[D]**
|
|
541
|
-
<https://link.springer.com/chapter/10.1007/978-3-540-24851-4_6>
|
|
542
|
-
- Bruno C. d. S. Oliveira & William R. Cook, "Extensibility for the Masses: Practical Extensibility with
|
|
543
|
-
Object Algebras," ECOOP 2012, LNCS 7313, pp. 2–27. DOI 10.1007/978-3-642-31057-7_2. **[D]**
|
|
544
|
-
author PDF <https://www.cs.utexas.edu/~wcook/Drafts/2012/ecoop2012.pdf>
|
|
545
|
-
- Jacques Carette, Oleg Kiselyov, Chung-chieh Shan, "Finally Tagless, Partially Evaluated," APLAS 2007
|
|
546
|
-
(LNCS 4807, pp. 222–238, DOI 10.1007/978-3-540-76637-7_15); journal version JFP 19(5):509–543, 2009,
|
|
547
|
-
DOI 10.1017/S0956796809007205. **[V]** <https://okmij.org/ftp/tagless-final/> · PDF
|
|
548
|
-
<https://okmij.org/ftp/tagless-final/JFP.pdf>
|
|
549
|
-
- Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, *Design Patterns: Elements of Reusable
|
|
550
|
-
Object-Oriented Software*, Addison-Wesley, 1994. ISBN 0-201-63361-2. **[C]** (Visitor pp. 331–344;
|
|
551
|
-
Bridge pp. 151–161; Strategy pp. 315–323; Abstract Factory pp. 87–95.) Bridge/Strategy/Abstract Factory
|
|
552
|
-
reference pages: <https://refactoring.guru/design-patterns/bridge> · `/strategy` · `/abstract-factory`. **[V]**
|
|
553
|
-
- Rich Hickey / Clojure, "Multimethods and Hierarchies," clojure.org reference. **[V]**
|
|
554
|
-
<https://clojure.org/reference/multimethods>
|
|
555
|
-
- Jeff Bezanson, Alan Edelman, Stefan Karpinski, Viral B. Shah, "Julia: A Fresh Approach to Numerical
|
|
556
|
-
Computing," *SIAM Review* 59(1):65–98, 2017, DOI 10.1137/141000671. **[D]** docs **[V]**
|
|
557
|
-
<https://docs.julialang.org/en/v1/manual/methods/> · paper PDF
|
|
558
|
-
<https://julialang.org/assets/research/julia-fresh-approach-BEKS.pdf>
|
|
559
|
-
|
|
560
|
-
**Compiler / IR / multi-backend architecture**
|
|
561
|
-
- Andrew W. Keep & R. Kent Dybvig, "A Nanopass Framework for Commercial Compiler Development," ICFP 2013,
|
|
562
|
-
pp. 343–350. DOI 10.1145/2500365.2500618. **[D]** author PDF <https://andykeep.com/pubs/np-preprint.pdf>
|
|
563
|
-
- Dipanwita Sarkar, Oscar Waddell, R. Kent Dybvig, "A Nanopass Infrastructure for Compiler Education,"
|
|
564
|
-
ICFP 2004, pp. 201–212. DOI 10.1145/1016850.1016878. **[D]**
|
|
565
|
-
<https://www.cs.tufts.edu/comp/150FP/archive/kent-dybvig/nanopass.pdf>
|
|
566
|
-
- Chris Lattner & Vikram Adve, "LLVM: A Compilation Framework for Lifelong Program Analysis &
|
|
567
|
-
Transformation," CGO 2004, pp. 75–88. DOI 10.1109/CGO.2004.1281665. **[V]**
|
|
568
|
-
<https://llvm.org/pubs/2004-01-30-CGO-LLVM.html>
|
|
569
|
-
- Chris Lattner, Mehdi Amini, Uday Bondhugula, Albert Cohen, Andy Davis, Jacques Pienaar, River Riddle,
|
|
570
|
-
Tatiana Shpeisman, Nicolas Vasilache, Oleksandr Zinenko, "MLIR: A Compiler Infrastructure for the End
|
|
571
|
-
of Moore's Law," arXiv:2002.11054, 2020 (CGO 2021 as "MLIR: Scaling Compiler Infrastructure for Domain
|
|
572
|
-
Specific Computation," DOI 10.1109/CGO51591.2021.9370308). **[V]** <https://arxiv.org/abs/2002.11054>
|
|
573
|
-
- Micah D. Beck, "On the Hourglass Model," *Communications of the ACM* 62(7):48–57, 2019.
|
|
574
|
-
DOI 10.1145/3274770. **[D]** open fulltext
|
|
575
|
-
<https://m-cacm.acm.org/magazines/2019/7/237714-on-the-hourglass-model/fulltext>
|
|
576
|
-
(Deering's 1998 "Watching the Waist of the Protocol Hourglass" keynote is the metaphor's origin but has
|
|
577
|
-
no stable peer-reviewed URL — **URL not verified**; Beck is the citable source.)
|
|
578
|
-
|
|
579
|
-
**Modularity & information hiding**
|
|
580
|
-
- David L. Parnas, "On the Criteria To Be Used in Decomposing Systems into Modules," *CACM* 15(12):1053–1058,
|
|
581
|
-
1972. DOI 10.1145/361598.361623. **[D]** author copy <http://sunnyday.mit.edu/16.355/parnas-criteria.html> **[V]**
|
|
582
|
-
- David L. Parnas, "Designing Software for Ease of Extension and Contraction," *IEEE TSE* SE-5(2):128–138,
|
|
583
|
-
1979. DOI 10.1109/TSE.1979.234169. **[D]** <https://ieeexplore.ieee.org/document/1702607/>
|
|
584
|
-
|
|
585
|
-
**Two-dimensional variability / plugin architecture / DIP**
|
|
586
|
-
- (Bridge / Strategy / Abstract Factory: GoF 1994, above.)
|
|
587
|
-
- Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad, Michael Stal, *Pattern-Oriented Software
|
|
588
|
-
Architecture, Volume 1: A System of Patterns* (POSA1), Wiley, 1996. ISBN 0-471-95869-7. Microkernel
|
|
589
|
-
pp. 171–192. **[C]** publisher
|
|
590
|
-
<https://www.wiley.com/en-us/Pattern+Oriented+Software+Architecture,+Volume+1,+A+System+of+Patterns-p-9780471958697> **[V]**
|
|
591
|
-
- Robert C. Martin, "The Dependency Inversion Principle," *C++ Report*, 1996; "Design Principles and
|
|
592
|
-
Design Patterns," Object Mentor, 2000. **[C]** original host defunct; cited by
|
|
593
|
-
<https://en.wikipedia.org/wiki/Dependency_inversion_principle> **[V]** and
|
|
594
|
-
<https://martinfowler.com/articles/dipInTheWild.html> **[V]**; archived PDF
|
|
595
|
-
<https://web.archive.org/web/20110714224327/http://www.objectmentor.com/resources/articles/dip.pdf>
|
|
596
|
-
(**not independently fetched**).
|
|
597
|
-
|
|
598
|
-
**Type-driven design**
|
|
599
|
-
- Yaron Minsky, "Effective ML Revisited" (incl. "Make illegal states unrepresentable"), Jane Street Tech
|
|
600
|
-
Blog (Effective ML talk, CUFP 2010). **[V]** <https://blog.janestreet.com/effective-ml-revisited/>
|
|
601
|
-
- Alexis King, "Parse, don't validate," lexi-lambda.github.io, 5 Nov 2019. **[V]**
|
|
602
|
-
<https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/>
|
|
603
|
-
- "Narrowing — Discriminated Unions and Exhaustiveness Checking," *The TypeScript Handbook*, Microsoft. **[V]**
|
|
604
|
-
<https://www.typescriptlang.org/docs/handbook/2/narrowing.html> · theory backing: Robert Harper,
|
|
605
|
-
*Practical Foundations for Programming Languages*, 2nd ed., Cambridge Univ. Press, 2016 (Sum Types). **[C]**
|
|
606
|
-
|
|
607
|
-
**Graph drawing / layout-vs-render**
|
|
608
|
-
- Kozo Sugiyama, Shojiro Tagawa, Mitsuhiko Toda, "Methods for Visual Understanding of Hierarchical System
|
|
609
|
-
Structures," *IEEE Trans. SMC* SMC-11(2):109–125, 1981. DOI 10.1109/TSMC.1981.4308636. **[D]**
|
|
610
|
-
- Emden R. Gansner & Stephen C. North, "An open graph visualization system and its applications to
|
|
611
|
-
software engineering," *Software: Practice and Experience* 30(11):1203–1233, 2000.
|
|
612
|
-
DOI 10.1002/1097-024X(200009)30:11<1203::AID-SPE338>3.0.CO;2-N. **[D]** open author PDF ("GN99")
|
|
613
|
-
<https://www.graphviz.org/documentation/GN99.pdf>
|
|
614
|
-
- Christoph Daniel Schulze, Miro Spönemann, Reinhard von Hanxleden, "Drawing layered graphs with port
|
|
615
|
-
constraints," *J. Visual Languages & Computing* 25(2):89–106, 2014. DOI 10.1016/j.jvlc.2013.11.005. **[D]**
|
|
616
|
-
- Sören Domrös, Reinhard von Hanxleden, Miro Spönemann, Ulf Rüegg, Christoph Daniel Schulze, "The Eclipse
|
|
617
|
-
Layout Kernel," arXiv:2311.00533, 2023. **[V]** <https://arxiv.org/abs/2311.00533>
|
|
618
|
-
|
|
619
|
-
**2026-06-21 competitive / industry reappraisal sources**
|
|
620
|
-
- Mermaid documentation, "Diagram Syntax" and layout/look configuration (site version 11.15.0). **[V]**
|
|
621
|
-
<https://mermaid.js.org/intro/syntax-reference.html>
|
|
622
|
-
- Mermaid documentation, "Theme Configuration" (`themeVariables`, derived colors, per-family variables).
|
|
623
|
-
**[V]** <https://mermaid.js.org/config/theming.html>
|
|
624
|
-
- Graphviz documentation, "Documentation" overview (DOT language, layout engines, output formats,
|
|
625
|
-
attributes). **[V]** <https://graphviz.org/documentation/>
|
|
626
|
-
- PlantUML home page (supported diagram families, layout engines, output formats) and ASCII-art page
|
|
627
|
-
(ASCII/Unicode documented for sequence diagrams). **[V]** <https://plantuml.com/> ·
|
|
628
|
-
<https://plantuml.com/ascii-art>
|
|
629
|
-
- D2 documentation, "Introduction", "Layouts", and "Themes" (declarative diagramming, engine tradeoffs,
|
|
630
|
-
theme overrides). **[V]** <https://d2lang.com/tour/intro/> ·
|
|
631
|
-
<https://d2lang.com/tour/layouts/> · <https://d2lang.com/tour/themes/>
|
|
632
|
-
- Design Tokens Community Group, "Design Tokens Format Module 2025.10," Draft Community Group Report,
|
|
633
|
-
13 June 2026. **[V]** Preview draft; explicitly not a W3C standard.
|
|
634
|
-
<https://www.designtokens.org/tr/drafts/format/>
|
|
635
|
-
|
|
636
|
-
**Testing practice sources used for reappraisal**
|
|
637
|
-
- `adewale/testing-best-practices` skill and references (TypeScript, golden/snapshot tests, correctness by
|
|
638
|
-
construction, mutation/testing-type decision guide). **[V]**
|
|
639
|
-
<https://github.com/adewale/testing-best-practices>
|
|
640
|
-
- Koen Claessen & John Hughes, "QuickCheck: A Lightweight Tool for Random Testing of Haskell Programs,"
|
|
641
|
-
ICFP 2000. DOI 10.1145/351240.351266. **[D]**
|
|
642
|
-
- Yue Jia & Mark Harman, "An Analysis and Survey of the Development of Mutation Testing," *IEEE TSE*
|
|
643
|
-
37(5):649-678, 2011. DOI 10.1109/TSE.2010.62. **[D]**
|
|
644
|
-
- James Somers, "What if writing tests was a joyful experience?", Jane Street Blog, 9 Jan 2023
|
|
645
|
-
(expect/snapshot tests and readable output discipline). **[V]**
|
|
646
|
-
<https://blog.janestreet.com/the-joy-of-expect-tests/>
|
|
647
|
-
|
|
648
|
-
**Complexity & cost of duplication**
|
|
649
|
-
- Ben Moseley & Peter Marks, "Out of the Tar Pit," 2006. **[V]**
|
|
650
|
-
<https://curtclifton.net/papers/MoseleyMarks06a.pdf>
|
|
651
|
-
- Butler W. Lampson, "Hints for Computer System Design," *ACM SIGOPS OSR* 17(5):33–48, SOSP 1983.
|
|
652
|
-
DOI 10.1145/773379.806614. **[D]** open author PDF
|
|
653
|
-
<https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/acrobat-17.pdf>
|
|
654
|
-
- Sandi Metz, "The Wrong Abstraction," sandimetz.com, 20 Jan 2016. **[V]**
|
|
655
|
-
<https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction>
|