chiltepin 0.47.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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +249 -0
  3. package/dist/bin.js +3582 -0
  4. package/dist/bin.js.map +1 -0
  5. package/package.json +93 -0
  6. package/templates/chiltepin.config.json +5 -0
  7. package/templates/demo.md +2161 -0
  8. package/templates/docs/getting-started.md +155 -0
  9. package/templates/docs/tutorial.md +559 -0
  10. package/templates/skill/SKILL.md +172 -0
  11. package/templates/skill/reference/blocks/INDEX.md +141 -0
  12. package/templates/skill/reference/blocks/agentic.md +63 -0
  13. package/templates/skill/reference/blocks/algorithms.md +49 -0
  14. package/templates/skill/reference/blocks/api.md +40 -0
  15. package/templates/skill/reference/blocks/architecture.md +94 -0
  16. package/templates/skill/reference/blocks/business.md +70 -0
  17. package/templates/skill/reference/blocks/charts-overviews.md +74 -0
  18. package/templates/skill/reference/blocks/data-model.md +34 -0
  19. package/templates/skill/reference/blocks/design-system.md +50 -0
  20. package/templates/skill/reference/blocks/flows.md +74 -0
  21. package/templates/skill/reference/blocks/narrative.md +65 -0
  22. package/templates/skill/reference/blocks/planning.md +74 -0
  23. package/templates/skill/reference/blocks/quality.md +43 -0
  24. package/templates/skill/reference/blocks/tables-data.md +55 -0
  25. package/templates/skill/reference/check.md +62 -0
  26. package/templates/skill/reference/decks.md +198 -0
  27. package/templates/skill/reference/exemplars/adr.md +87 -0
  28. package/templates/skill/reference/exemplars/agent-system.md +113 -0
  29. package/templates/skill/reference/exemplars/api-reference.md +110 -0
  30. package/templates/skill/reference/exemplars/backend-arch.md +117 -0
  31. package/templates/skill/reference/exemplars/data-pipeline.md +107 -0
  32. package/templates/skill/reference/exemplars/frontend-arch.md +93 -0
  33. package/templates/skill/reference/exemplars/incident-postmortem.md +93 -0
  34. package/templates/skill/reference/exemplars/migration-plan.md +95 -0
  35. package/templates/skill/reference/exemplars/onboarding.md +78 -0
  36. package/templates/skill/reference/exemplars/product-spec.md +81 -0
  37. package/templates/skill/reference/intake.md +140 -0
  38. package/templates/skill/reference/mermaid.md +216 -0
  39. package/templates/skill/reference/organizing.md +118 -0
  40. package/templates/skill/reference/patterns-design.md +59 -0
  41. package/templates/skill/reference/patterns.md +167 -0
  42. package/templates/skill/reference/recipes.md +153 -0
  43. package/templates/skill/reference/style-ste.md +119 -0
  44. package/templates/skill/reference/system-design.md +161 -0
  45. package/templates/skill/reference/writing.md +132 -0
@@ -0,0 +1,2161 @@
1
+ ```meta
2
+ title: Chiltepin — all blocks
3
+ subtitle: One rendered example of every block type the renderer supports.
4
+ tag: DEMO · v1
5
+ ```
6
+
7
+ ## Welcome
8
+
9
+ Each section renders one block type from a typed YAML fence in this file.
10
+ Copy a fence into your own doc as a starting point.
11
+
12
+ ```callout
13
+ tone: tip
14
+ title: Source of truth
15
+ body: Every diagram on this page comes from a YAML block. There is no
16
+ hand-written HTML or SVG — change the YAML to change the picture.
17
+ ```
18
+
19
+ ```prose
20
+ title: Structured prose
21
+ lede: "Use the prose block when prose must travel inside a structured layout: headings, paragraphs, lists, and quotes become typed data."
22
+ blocks:
23
+ - { type: h, text: Why structured prose }
24
+ - { type: p, text: It plays nicely with the section-head wrapper and keeps content uniform across docs. }
25
+ - { type: ul, items: [Predictable spacing, Consistent fonts, Easier diffs] }
26
+ - { type: quote, text: A document degrades gracefully — opens in any editor with no tooling. }
27
+ ```
28
+
29
+ ```glossary
30
+ title: A few terms
31
+ terms:
32
+ - { term: Idempotent, def: A call that produces the same outcome on a replay. }
33
+ - { term: SLO, def: A service-level objective the team commits to., avoid: [uptime target, service promise] }
34
+ - { term: Saga, def: A long-running transaction split across services. }
35
+ ```
36
+
37
+ ```proscons
38
+ title: Sync vs async writes
39
+ prosLabel: Synchronous
40
+ consLabel: Asynchronous
41
+ pros:
42
+ - One transaction, easy to reason about
43
+ - Errors surface at call time
44
+ - Latency budget is predictable
45
+ cons:
46
+ - Caller waits for downstream
47
+ - Failure mode is "everything stops"
48
+ - Hard to scale horizontally
49
+ ```
50
+
51
+ ```cvt
52
+ title: Migration plan
53
+ current:
54
+ label: Today (monolith)
55
+ items: [Single deployable, Shared Postgres, Manual releases]
56
+ target:
57
+ label: Target (services)
58
+ items: [Per-service deploys, Per-service stores, Continuous releases]
59
+ note: Migrate one service per quarter; freeze new monolith features.
60
+ ```
61
+
62
+ ```stats
63
+ title: This quarter
64
+ stats:
65
+ - { value: 12.4k, label: Active users, delta: "+18%", trend: up }
66
+ - { value: 99.95%, label: Uptime, delta: "0", trend: flat }
67
+ - { value: 142ms, label: p95 latency, delta: "-22ms", trend: up }
68
+ - { value: $84k, label: MRR, delta: "+$6.1k", trend: up }
69
+ ```
70
+
71
+ ```code
72
+ title: Reference snippets
73
+ blocks:
74
+ - title: order-handler.ts
75
+ lang: TypeScript
76
+ code: |
77
+ export async function placeOrder(req: OrderRequest): Promise<Order> {
78
+ const order = await db.tx(async (t) => {
79
+ const inserted = await t.orders.insert({ ...req, status: 'PENDING' });
80
+ await payments.authorize(inserted.id, req.token);
81
+ return t.orders.update(inserted.id, { status: 'CONFIRMED' });
82
+ });
83
+ return order;
84
+ }
85
+ - title: schema.sql
86
+ lang: PostgreSQL
87
+ code: |
88
+ CREATE TABLE orders (
89
+ id uuid PRIMARY KEY,
90
+ user_id uuid NOT NULL REFERENCES users(id),
91
+ amount_cents integer NOT NULL,
92
+ status text NOT NULL DEFAULT 'PENDING'
93
+ );
94
+ ```
95
+
96
+ ```agenda
97
+ title: Tuesday standup
98
+ items:
99
+ - { time: "09:00", duration: 5m, title: Round-robin, owner: Host }
100
+ - { time: "09:05", duration: 20m, title: Status updates, desc: Each team for 5 minutes }
101
+ - { time: "09:25", duration: 30m, title: Tech deep-dive, owner: API team, desc: Walk-through of the new orders service }
102
+ - { time: "09:55", duration: 5m, title: Action items + wrap }
103
+ ```
104
+
105
+ ```tree
106
+ title: Repo layout
107
+ nodes:
108
+ - { id: root, label: chiltepin }
109
+ - { id: packages, parent: root, label: packages }
110
+ - { id: core, parent: packages, label: 'chiltepin-core', note: pure model }
111
+ - { id: render, parent: packages, label: 'chiltepin-render', note: HTML out }
112
+ - { id: studio, parent: packages, label: 'chiltepin-studio', note: visual editor }
113
+ - { id: cli, parent: packages, label: 'chiltepin', note: chiltepin binary }
114
+ - { id: resources, parent: root, label: resources, note: fixtures + reference renderer }
115
+ - { id: docs, parent: root, label: docs, note: the documents }
116
+ ```
117
+
118
+ ```pyramid
119
+ title: Engineering priorities
120
+ levels:
121
+ - { label: Vision, desc: Documentation as a navigable typed model }
122
+ - { label: Strategy, desc: Files on disk are the source of truth }
123
+ - { label: This quarter, desc: "107 blocks, one look, agent skill" }
124
+ - { label: This week, desc: Phase 2 blocks shipped }
125
+ ```
126
+
127
+ ```flow
128
+ title: Decision flow
129
+ description: The flow decides whether to accept a payment; the error path ends in a rejection. An invalid token never reaches the charge step.
130
+ nodes:
131
+ - { id: start, col: 1, row: 1, kind: start, label: Start }
132
+ - { id: check, col: 2, row: 1, kind: decision, label: Token valid? }
133
+ - { id: charge, col: 3, row: 1, kind: process, label: Charge card }
134
+ - { id: reject, col: 2, row: 2, kind: end, label: Reject }
135
+ - { id: done, col: 3, row: 2, kind: end, label: Done }
136
+ edges:
137
+ - start -> check
138
+ - check -> charge: "yes"
139
+ - check -x-> reject: "no"
140
+ - charge -> done
141
+ ```
142
+
143
+ ```state
144
+ title: Order lifecycle
145
+ description: PENDING is the only state visible inside the txn; CONFIRMED is the only post-commit state.
146
+ states:
147
+ - { id: s0, col: 1, row: 1, kind: start }
148
+ - { id: pending, col: 2, row: 1, kind: wait, name: PENDING }
149
+ - { id: confirmed, col: 3, row: 1, kind: active, name: CONFIRMED }
150
+ - { id: cancelled, col: 3, row: 2, kind: wait, name: CANCELLED }
151
+ - { id: end, col: 4, row: 1, kind: terminal }
152
+ transitions:
153
+ - { from: s0, to: pending, event: create }
154
+ - { from: pending, to: confirmed, event: authorize_ok }
155
+ - { from: pending, to: cancelled, event: authorize_fail }
156
+ - { from: confirmed, to: end, event: ship }
157
+ ```
158
+
159
+ ```dfd
160
+ title: Order placement data flow
161
+ nodes:
162
+ - { id: client, col: 1, row: 1, kind: external, name: Client }
163
+ - { id: orders, col: 2, row: 1, kind: process, name: Place order, num: 1 }
164
+ - { id: pay, col: 3, row: 1, kind: external, name: Payment GW }
165
+ - { id: db, col: 2, row: 2, kind: store, name: orders }
166
+ edges:
167
+ - { from: client, to: orders, label: POST /orders }
168
+ - { from: orders, to: pay, label: authorize }
169
+ - { from: orders, to: db, label: INSERT }
170
+ ```
171
+
172
+ ```journey
173
+ title: Onboarding journey
174
+ stages:
175
+ - { label: Discover }
176
+ - { label: Sign up }
177
+ - { label: Activate }
178
+ - { label: Pay }
179
+ rows:
180
+ - { label: Touchpoint, cells: [Landing, Form, Email, Checkout] }
181
+ - { label: Time, cells: [30s, 90s, 24h, 60s] }
182
+ - { label: Friction, cells: [Low, Medium, Low, Medium] }
183
+ emotion: [0.75, 0.40, 0.60, 0.85]
184
+ ```
185
+
186
+ ```gantt
187
+ title: Quarterly plan
188
+ periods: [Q1, Q2, Q3, Q4]
189
+ tasks:
190
+ - { label: Discovery, start: 0, span: 1, kind: done }
191
+ - { label: Core build, start: 1, span: 2, kind: active }
192
+ - { label: Beta, start: 2, span: 1 }
193
+ - { label: GA, start: 3, span: 1, kind: milestone }
194
+ - { label: Support hand-off, start: 3, span: 1 }
195
+ ```
196
+
197
+ ```graph
198
+ title: Service dependency graph
199
+ nodes:
200
+ - { id: web, col: 1, row: 1, label: web, group: 0 }
201
+ - { id: api, col: 2, row: 1, label: api, group: 1 }
202
+ - { id: pay, col: 3, row: 1, label: payment, group: 2 }
203
+ - { id: db, col: 2, row: 2, label: postgres, group: 3 }
204
+ - { id: cache, col: 1, row: 2, label: redis, group: 4 }
205
+ edges:
206
+ - web -> api
207
+ - api -> pay
208
+ - api -> db
209
+ - { from: api, to: cache, dir: undirected }
210
+ ```
211
+
212
+ ```quadrant
213
+ title: Effort vs impact
214
+ description: The skill ships first — the most impact for the least effort. Quick wins sit top-left, big bets top-right.
215
+ xAxis: { label: Effort, low: Low, high: High }
216
+ yAxis: { label: Impact, low: Low, high: High }
217
+ items:
218
+ - { x: 0.18, y: 0.82, label: Ship the skill }
219
+ - { x: 0.80, y: 0.90, label: MCP server }
220
+ - { x: 0.22, y: 0.30, label: README polish }
221
+ - { x: 0.75, y: 0.22, label: VS Code ext }
222
+ - { x: 0.55, y: 0.65, label: Hosted preview }
223
+ ```
224
+
225
+ ```swimlane
226
+ title: Cross-functional handoff
227
+ lanes: [Customer, Sales, Engineering, Ops]
228
+ phases:
229
+ - { label: Intake, from: 1, to: 2 }
230
+ - { label: Build, from: 3, to: 4 }
231
+ - { label: Ship, from: 5 }
232
+ steps:
233
+ - req: Submit request · Customer · start
234
+ - triage: Qualify? · Sales · decision
235
+ - scope: Scope work · Engineering
236
+ - build: Build · Engineering
237
+ - { id: deploy, lane: Ops, label: Deploy, note: blue/green, accent: true }
238
+ - done: Receive · Customer · end
239
+ links:
240
+ - req -> triage
241
+ - triage -> scope: approved
242
+ - scope -> build
243
+ - build -> deploy
244
+ - deploy --> done: notified
245
+ ```
246
+
247
+ ```gitgraph
248
+ title: Release model
249
+ description: "Release branches are short-lived: cut, ship, merge back."
250
+ branches:
251
+ - { name: main, accent: navy }
252
+ - { name: release, accent: teal }
253
+ commits:
254
+ - { label: baseline }
255
+ - { label: feature A }
256
+ - { branch: release, label: cut 1.2 }
257
+ - { merge: release, label: ship, tag: v1.2.0, kind: release }
258
+ ```
259
+
260
+
261
+ ```c4
262
+ title: System context
263
+ description: Who uses ShopCo and which external systems it depends on.
264
+ level: container
265
+ boundary: { label: ShopCo platform }
266
+ nodes:
267
+ - { id: shopper, col: 1, row: 1, kind: person, name: Shopper, desc: A customer placing an order from web or mobile. }
268
+ - { id: web, col: 2, row: 1, kind: container, family: client, name: Web app, tech: Next.js, desc: Server-rendered React. }
269
+ - { id: api, col: 3, row: 1, kind: container, family: service, name: Orders API, tech: Go, desc: "Authorises, persists, emits events." }
270
+ - { id: pg, col: 3, row: 2, kind: store, name: Orders DB, tech: Postgres 16, desc: Single source of truth for orders. }
271
+ - { id: pay, col: 4, row: 1, kind: external, name: Payment GW, desc: Stripe authorisation. }
272
+ edges:
273
+ - { from: shopper, to: web, label: places order }
274
+ - { from: web, to: api, label: POST /orders }
275
+ - { from: api, to: pg, label: writes }
276
+ - { from: api, to: pay, label: authorises }
277
+ ```
278
+
279
+ ```uml
280
+ title: Domain classes
281
+ description: Order owns its items by composition — an OrderItem cannot outlive its Order.
282
+ classes:
283
+ - id: order
284
+ col: 1
285
+ row: 1
286
+ name: Order
287
+ attrs: ["id: UUID", "status: Status", "total: Money", "items: OrderItem[]"]
288
+ methods: ["place()", "confirm()", "cancel()"]
289
+ - id: item
290
+ col: 2
291
+ row: 1
292
+ name: OrderItem
293
+ attrs: ["id: UUID", "sku: String", "qty: int", "price: Money"]
294
+ - id: status
295
+ col: 1
296
+ row: 2
297
+ name: Status
298
+ stereotype: enumeration
299
+ attrs: ["PENDING", "CONFIRMED", "CANCELLED"]
300
+ - id: shopper
301
+ col: 2
302
+ row: 2
303
+ name: Shopper
304
+ attrs: ["id: UUID", "email: String"]
305
+ rels:
306
+ - { from: order, to: item, kind: composition, label: contains }
307
+ - { from: order, to: status, kind: association, label: has }
308
+ - { from: shopper, to: order, kind: association, label: places }
309
+ ```
310
+
311
+ ```tree
312
+ variant: issue
313
+ title: Why are conversions down?
314
+ description: A MECE breakdown of plausible causes. Each leaf is a claim we can test before spending on a fix.
315
+ nodes:
316
+ - { id: root, label: Lower conversion this quarter }
317
+ - { id: traffic, parent: root, label: Traffic quality }
318
+ - { id: friction, parent: root, label: Funnel friction }
319
+ - { id: pricing, parent: root, label: Pricing / offer }
320
+ - { id: t1, parent: traffic, label: Wrong audience }
321
+ - { id: t2, parent: traffic, label: Ad fatigue, note: paid creative is stale }
322
+ - { id: f1, parent: friction, label: Slow checkout, note: p95 over 4s on mobile }
323
+ - { id: f2, parent: friction, label: Mobile bugs }
324
+ - { id: f3, parent: friction, label: Required signup }
325
+ - { id: p1, parent: pricing, label: Competitor undercut }
326
+ - { id: p2, parent: pricing, label: Shipping fee surprise }
327
+ ```
328
+
329
+ ```tree
330
+ variant: org
331
+ title: Platform group
332
+ description: "The same tree block as an org chart: parents center over their children, role under the name."
333
+ nodes:
334
+ - { id: dana, label: Dana Reyes, role: VP Engineering }
335
+ - { id: sam, parent: dana, label: Sam Ortiz, role: "Manager, Core" }
336
+ - { id: kim, parent: dana, label: Kim Lau, role: "Manager, Infra" }
337
+ - { id: ada, parent: sam, label: Ada Boone, role: Frontend lead }
338
+ - { id: raj, parent: sam, label: Raj Patel, role: Backend lead }
339
+ - { id: mei, parent: kim, label: Mei Tanaka, role: SRE lead }
340
+ ```
341
+
342
+ ```frontend
343
+ title: React component tree
344
+ description: "In the orders app, state lives in two places only: the cart store and the useOrders hook."
345
+ nodes:
346
+ - { id: app, kind: root, name: App }
347
+ - { id: auth, parent: app, kind: provider, name: AuthProvider }
348
+ - { id: theme, parent: app, kind: provider, name: ThemeProvider }
349
+ - { id: layout, parent: auth, kind: layout, name: AppLayout }
350
+ - { id: home, parent: layout, kind: page, name: Home }
351
+ - { id: orders, parent: layout, kind: page, name: OrdersPage }
352
+ - { id: list, parent: orders, kind: component, name: OrderList }
353
+ - { id: card, parent: list, kind: component, name: OrderCard }
354
+ - { id: badge, parent: card, kind: leaf, name: StatusBadge }
355
+ - { id: hook, parent: orders, kind: hook, name: useOrders }
356
+ - { id: cart, parent: app, kind: store, name: cartStore, note: Zustand }
357
+ ```
358
+
359
+ ```cluster
360
+ title: Production cluster
361
+ description: Two namespaces (api and data) with replicas; cross-namespace edges run from the API services to their backing stores. Only the orders service touches all three stores — it is the blast radius to watch.
362
+ clusters:
363
+ - { id: api, label: api namespace, kind: namespace }
364
+ - { id: data, label: data namespace, kind: namespace }
365
+ services:
366
+ - { id: web, cluster: api, label: web, kind: service, tech: Next.js, replicas: 3 }
367
+ - { id: orders, cluster: api, label: orders, kind: service, tech: Go 1.22, replicas: 4 }
368
+ - { id: payments, cluster: api, label: payments, kind: service, tech: Node 20, replicas: 2 }
369
+ - { id: pg, cluster: data, label: postgres, kind: store, tech: Postgres 16, replicas: 1 }
370
+ - { id: redis, cluster: data, label: redis, kind: cache, tech: Redis 7, replicas: 2 }
371
+ - { id: bus, cluster: data, label: events, kind: queue, tech: NATS, replicas: 3 }
372
+ edges:
373
+ - { from: web, to: orders }
374
+ - { from: orders, to: pg }
375
+ - { from: orders, to: redis }
376
+ - { from: orders, to: bus, kind: dashed }
377
+ - { from: payments, to: pg }
378
+ ```
379
+
380
+ ```block
381
+ title: Layered architecture
382
+ description: "Clients call the gateway, which fans out to the microservices, each backed by the data layer. The gateway is the single entry point: cross-cutting concerns live there, not in each service."
383
+ systemLabel: E-COMMERCE PLATFORM
384
+ layers:
385
+ - { label: Client layer }
386
+ - { label: API gateway }
387
+ - { label: Microservices }
388
+ - { label: Data layer }
389
+ nodes:
390
+ - { id: web, layer: 0, kind: client, name: Web app, tech: React }
391
+ - { id: mob, layer: 0, kind: client, name: Mobile, tech: iOS / Android }
392
+ - { id: gw, layer: 1, kind: gateway, name: API Gateway, tech: Kong }
393
+ - { id: orders, layer: 2, kind: microservice, name: Orders, tech: Go }
394
+ - { id: catalog, layer: 2, kind: microservice, name: Catalog, tech: Node }
395
+ - { id: payments, layer: 2, kind: microservice, name: Payments, tech: Java }
396
+ - { id: ordersdb, layer: 3, kind: db, name: Orders DB, tech: Postgres }
397
+ - { id: catalogdb, layer: 3, kind: db, name: Catalog DB, tech: MongoDB }
398
+ - { id: cache, layer: 3, kind: cache, name: Cache, tech: Redis }
399
+ edges:
400
+ - web -> gw
401
+ - mob -> gw
402
+ - gw -> orders
403
+ - gw -> catalog
404
+ - gw -> payments
405
+ - orders -> ordersdb
406
+ - catalog -> catalogdb
407
+ - catalog --> cache
408
+ - payments -> ordersdb
409
+ ```
410
+
411
+ ```block
412
+ preset: infra
413
+ title: Cloud deployment
414
+ description: "Edge → gateway → containers, backed by a database, object storage, a cache, and a queue worker. Two nested groups mark the cloud account and the private network inside it. The queue decouples the API from the worker: a slow job never blocks a request."
415
+ groups:
416
+ - { id: cloud, label: Cloud account, col: 1, row: 1, cols: 4, rows: 2, color: "#374151" }
417
+ - { id: net, label: Private network, col: 2, row: 1, cols: 3, rows: 2, color: "#0e54a1" }
418
+ nodes:
419
+ - { id: cdn, col: 1, row: 1, kind: cdn, name: CDN, tech: edge cache }
420
+ - { id: gw, col: 2, row: 1, kind: gateway, name: API Gateway, tech: load balancer }
421
+ - { id: svc, col: 3, row: 1, kind: compute, name: API, tech: containers }
422
+ - { id: db, col: 4, row: 1, kind: db, name: Database, tech: managed SQL }
423
+ - { id: bucket, col: 4, row: 2, kind: bucket, name: Object storage, tech: blobs / files }
424
+ - { id: cache, col: 3, row: 2, kind: cache, name: Cache, tech: in-memory }
425
+ - { id: q, col: 2, row: 2, kind: queue, name: Queue, tech: messages }
426
+ - { id: wk, col: 1, row: 2, kind: function, name: Worker, tech: async jobs }
427
+ edges:
428
+ - cdn -> gw: HTTPS
429
+ - gw -> svc: routes
430
+ - svc -> db: SQL
431
+ - svc --> bucket: reads
432
+ - svc --> cache: cache
433
+ - svc --> q: publish
434
+ - q --> wk: consume
435
+ ```
436
+
437
+ ```block
438
+ preset: event
439
+ title: Order events
440
+ description: Producers publish to topics and consumers subscribe. Producers never know their consumers — Analytics subscribed without a change to the Orders API.
441
+ nodes:
442
+ - { id: api, col: 1, row: 1, kind: producer, name: Orders API, tech: publishes }
443
+ - { id: pays, col: 1, row: 2, kind: producer, name: Payments, tech: publishes }
444
+ - { id: t1, col: 2, row: 1, kind: topic, name: order.created, tech: topic }
445
+ - { id: t2, col: 2, row: 2, kind: topic, name: payment.captured, tech: topic }
446
+ - { id: email, col: 3, row: 1, kind: consumer, name: Email worker, tech: subscribes }
447
+ - { id: ship, col: 3, row: 2, kind: consumer, name: Fulfilment, tech: subscribes }
448
+ - { id: an, col: 3, row: 3, kind: consumer, name: Analytics, tech: subscribes }
449
+ edges:
450
+ - api -> t1: publish
451
+ - pays -> t2: publish
452
+ - t1 --> email
453
+ - t1 --> ship
454
+ - t1 --> an
455
+ - t2 --> ship
456
+ ```
457
+
458
+ ```block
459
+ preset: ddd
460
+ title: Context map
461
+ description: "Sales is upstream of Billing and Shipping: its model changes ripple downstream, never the reverse."
462
+ nodes:
463
+ - { id: sales, col: 1, row: 1, kind: context, name: Sales, tech: core }
464
+ - { id: billing, col: 2, row: 1, kind: context, name: Billing, tech: supporting }
465
+ - { id: ship, col: 2, row: 2, kind: context, name: Shipping, tech: supporting }
466
+ - { id: catalog, col: 1, row: 2, kind: context, name: Catalog, tech: generic }
467
+ edges:
468
+ - sales -> billing: U → D
469
+ - sales -> ship: U → D · ACL
470
+ - catalog --> sales: shared kernel
471
+ ```
472
+
473
+ ```block
474
+ preset: network
475
+ title: Network zones
476
+ description: Trust boundaries run from edge to data. The load balancer must never reach the database directly — the red "no direct" edge marks the forbidden connection and makes the rule reviewable.
477
+ groups:
478
+ - { id: z1, label: DMZ, col: 1, row: 1, cols: 1, rows: 2, color: "#f7952c" }
479
+ - { id: z2, label: Private subnet, col: 2, row: 1, cols: 1, rows: 2, color: "#0e54a1" }
480
+ - { id: z3, label: Data subnet, col: 3, row: 1, cols: 1, rows: 2, color: "#991b1b" }
481
+ nodes:
482
+ - { id: lb, col: 1, row: 1, kind: gateway, name: Load balancer, tech: public }
483
+ - { id: waf, col: 1, row: 2, kind: firewall, name: Firewall, tech: WAF }
484
+ - { id: web, col: 2, row: 1, kind: compute, name: App servers, tech: private }
485
+ - { id: cache, col: 2, row: 2, kind: cache, name: Cache, tech: private }
486
+ - { id: db, col: 3, row: 1, kind: db, name: Database, tech: restricted }
487
+ edges:
488
+ - lb -> waf: filter
489
+ - waf -> web: "443"
490
+ - web -> cache: "6379"
491
+ - web -> db: "5432"
492
+ - { from: lb, to: db, label: no direct, kind: forbidden }
493
+ ```
494
+
495
+ ```felogic
496
+ title: Frontend logic — strategy + engine
497
+ description: The checkout UI drives a pricing engine that selects a DiscountStrategy implementation; the API client egresses over HTTPS to the backend. Discount rules hide behind one interface — a new promotion is a new strategy class, not an engine change.
498
+ groups:
499
+ - { id: app, label: App (browser), col: 1, row: 1, cols: 3, rows: 3, color: "#0e54a1" }
500
+ - { id: net, label: Egress · network, col: 4, row: 1, cols: 1, rows: 1, color: "#6b7280" }
501
+ nodes:
502
+ - { id: ui, col: 1, row: 1, kind: component, name: Checkout UI, note: renders form }
503
+ - { id: engine, col: 2, row: 1, kind: engine, name: PricingEngine, note: computes total }
504
+ - { id: api, col: 3, row: 1, kind: service, name: ApiClient, note: fetch wrapper }
505
+ - { id: backend, col: 4, row: 1, kind: external, name: Orders API, note: REST /orders }
506
+ - { id: cart, col: 1, row: 2, kind: hook, name: useCart(), note: state }
507
+ - { id: iface, col: 2, row: 2, kind: interface, name: DiscountStrategy, note: calculate() }
508
+ - { id: s1, col: 1, row: 3, kind: strategy, name: PercentOff, note: "% off" }
509
+ - { id: s2, col: 2, row: 3, kind: strategy, name: BuyXGetY, note: bundle }
510
+ - { id: s3, col: 3, row: 3, kind: strategy, name: NoDiscount, note: default }
511
+ edges:
512
+ - { from: ui, to: engine, label: uses, kind: uses }
513
+ - { from: ui, to: cart, label: reads, kind: reads }
514
+ - { from: engine, to: iface, label: selects, kind: uses }
515
+ - { from: s1, to: iface, kind: implements }
516
+ - { from: s2, to: iface, kind: implements }
517
+ - { from: s3, to: iface, kind: implements }
518
+ - { from: engine, to: api, label: calls, kind: uses }
519
+ - { from: api, to: backend, label: HTTPS, kind: egress }
520
+ ```
521
+
522
+ ```felogic
523
+ variant: be
524
+ title: Backend logic — gateway + repository
525
+ description: The controller calls OrderService, which loads through OrderRepository and charges through the PaymentGateway interface (Stripe and Adyen adapters). Writes go to Postgres, the event bus, and the external gateways. One interface per provider, so a Stripe outage is a config change.
526
+ groups:
527
+ - { id: svc, label: Service boundary, col: 1, row: 1, cols: 3, rows: 3, color: "#0e54a1" }
528
+ - { id: infra, label: Infrastructure · egress, col: 4, row: 1, cols: 1, rows: 3, color: "#6b7280" }
529
+ nodes:
530
+ - { id: ctrl, col: 1, row: 1, kind: controller, name: OrdersController, note: HTTP /orders }
531
+ - { id: service, col: 2, row: 1, kind: service, name: OrderService, note: use case }
532
+ - { id: stripe, col: 3, row: 1, kind: adapter, name: StripeAdapter, note: implements }
533
+ - { id: queue, col: 4, row: 1, kind: queue, name: EventBus, note: order.created }
534
+ - { id: repo, col: 1, row: 2, kind: repository, name: OrderRepository, note: data access }
535
+ - { id: iface, col: 2, row: 2, kind: interface, name: PaymentGateway, note: charge() }
536
+ - { id: adyen, col: 3, row: 2, kind: adapter, name: AdyenAdapter, note: implements }
537
+ - { id: db, col: 4, row: 2, kind: db, name: postgres, note: orders table }
538
+ - { id: model, col: 1, row: 3, kind: model, name: Order, note: entity }
539
+ - { id: ext1, col: 4, row: 3, kind: external, name: Stripe API, note: HTTPS }
540
+ edges:
541
+ - { from: ctrl, to: service, label: handles, kind: uses }
542
+ - { from: service, to: repo, label: loads, kind: uses }
543
+ - { from: repo, to: model, label: reads, kind: reads }
544
+ - { from: repo, to: db, label: SQL, kind: egress }
545
+ - { from: service, to: iface, label: charges, kind: uses }
546
+ - { from: stripe, to: iface, kind: implements }
547
+ - { from: adyen, to: iface, kind: implements }
548
+ - { from: stripe, to: ext1, label: HTTPS, kind: egress }
549
+ - { from: service, to: queue, label: publishes, kind: uses }
550
+ ```
551
+
552
+ ```flow
553
+ variant: dag
554
+ title: Build pipeline
555
+ description: "Lint and unit tests run in parallel; both gate the build. The w: 2 span lets Deploy cover two columns."
556
+ nodes:
557
+ - { id: src, col: 1, row: 1, kind: start, label: Checkout }
558
+ - { id: lint, col: 2, row: 1, kind: process, label: Lint }
559
+ - { id: test, col: 2, row: 2, kind: process, label: Unit tests }
560
+ - { id: build, col: 3, row: 1, kind: process, label: Build }
561
+ - { id: deploy, col: 4, row: 1, w: 2, kind: end, label: Deploy }
562
+ edges:
563
+ - src -> lint
564
+ - src -> test
565
+ - lint -> build
566
+ - test -> build
567
+ - build -> deploy
568
+ ```
569
+
570
+ ## Saga
571
+
572
+ Each service owns its own database, so no single transaction covers an order.
573
+ The order service issues every compensation itself, and a customer can see the
574
+ stock reservation before the refund lands.
575
+
576
+ ```saga
577
+ title: Place order
578
+ mode: orchestration
579
+ coordinator: Order service
580
+ steps:
581
+ - reserve: Reserve stock · inventory · release stock
582
+ - coupon: Redeem coupon · promotions · restore coupon
583
+ - charge: Charge card · payments · refund card
584
+ - ship: Book shipment · shipping · cancel shipment
585
+ - notify: Send confirmation · notifications
586
+ failAt: ship
587
+ ```
588
+
589
+ ## Incident loop
590
+
591
+ Every incident feeds the next one: the review only closes when a guardrail
592
+ lands in code. A loop that ends at the write-up is the one that repeats.
593
+
594
+ ```cycle
595
+ title: How an incident closes
596
+ steps:
597
+ - { label: Detect, desc: An SLO burn alert pages the on-call engineer }
598
+ - { label: Mitigate, desc: "Stop the bleeding first — roll back or shed load" }
599
+ - { label: Review, desc: Write the timeline while the details are fresh }
600
+ - { label: Guardrail, desc: "Ship the alert, test, or limit that catches it next time" }
601
+ center: every page
602
+ ```
603
+
604
+ ## Architecture map
605
+
606
+ ```archmap
607
+ title: Retail platform — target architecture
608
+ description: The legacy ESB retires once the event bus carries its traffic.
609
+ cols: 3
610
+ areas:
611
+ - label: Customer channels
612
+ accent: blue
613
+ items:
614
+ - Web storefront
615
+ - { name: Mobile app, status: target }
616
+ - Contact centre
617
+ - label: Commerce
618
+ accent: teal
619
+ items:
620
+ - Catalog
621
+ - Checkout
622
+ - { name: Promotions, status: gap }
623
+ - { name: Subscriptions, status: new }
624
+ - label: Fulfilment
625
+ accent: green
626
+ items:
627
+ - Warehouse mgmt
628
+ - { name: Carrier gateway, status: target }
629
+ - label: Data & analytics
630
+ accent: amber
631
+ items:
632
+ - Reporting
633
+ - { name: Customer 360, status: target }
634
+ - { name: ML forecasting, status: gap }
635
+ - label: Platform services
636
+ accent: purple
637
+ desc: Shared capabilities every domain builds on.
638
+ items:
639
+ - Identity
640
+ - { name: Event bus, status: new }
641
+ - { name: Legacy ESB, status: deprecated }
642
+ - label: Integration
643
+ accent: navy
644
+ items:
645
+ - API gateway
646
+ - { name: Partner APIs, status: target }
647
+ ```
648
+
649
+ ## Table
650
+
651
+ ```table
652
+ title: Plan comparison
653
+ columns:
654
+ - { label: Plan }
655
+ - { label: Price, align: r }
656
+ - { label: Seats, align: r, highlight: true }
657
+ rows:
658
+ - [ Free, "$0", "1" ]
659
+ - [ Pro, "$20", "10" ]
660
+ - [ Team, { v: "$80", tone: pos }, "50" ]
661
+ ```
662
+
663
+ ## Benchmark
664
+
665
+ ```benchmark
666
+ title: Retrieval engines, measured
667
+ description: "The best number in each row is derived, not authored — `better: low` flips it for latency and cost."
668
+ metricLabel: Benchmark
669
+ subjects:
670
+ - { label: Ours, sub: v2.1, featured: true }
671
+ - { label: Vendor A }
672
+ - { label: Vendor B, tone: muted }
673
+ rows:
674
+ - { label: Answer accuracy, sub: internal QA set, cells: ["82.4%", "79.1%", "74.8%"] }
675
+ - { label: Citations correct, sub: 500 sampled answers, cells: ["91.0%", "88.2%", "83.4%"] }
676
+ - { label: p95 latency, sub: 500 rps soak, better: low, cells: ["310 ms", "420 ms", "290 ms"] }
677
+ - label: Cost per 1k queries
678
+ variants: [cached, cold]
679
+ better: low
680
+ cells:
681
+ - ["$0.14", "$0.90"]
682
+ - ["$0.21", "$1.10"]
683
+ - ["$0.18", "—"]
684
+ - { label: Index size, sub: 40M docs, better: none, cells: ["112 GB", "98 GB", "150 GB"] }
685
+ note: Single region, same corpus, October run. Vendor B declined the cold-cache test.
686
+ ```
687
+
688
+ ## Sequence
689
+
690
+ ```sequence
691
+ id: sw-seq-checkout
692
+ title: Place order
693
+ endpoint: { method: POST, path: /orders }
694
+ actors:
695
+ - { id: client, name: Client }
696
+ - { id: api, name: Orders API }
697
+ - { id: db, name: Postgres, external: true }
698
+ messages:
699
+ - client -> api: POST /orders
700
+ - { from: api, to: db, label: INSERT order, kind: async }
701
+ - api --> client: 201 Created
702
+ ```
703
+
704
+ ## Trace waterfall
705
+
706
+ A trace holds one sampled request, not an average. A dependency that retries
707
+ only sometimes costs a real user the full time here, which a percentile chart
708
+ hides.
709
+
710
+ ```spans
711
+ title: GET /orders/{id}
712
+ description: One sampled request, 2026-08-28. The payments call was retried once.
713
+ unit: ms
714
+ spans:
715
+ - { id: get, service: api, name: "GET /orders/{id}", start: 0, duration: 138, kind: server }
716
+ - api/auth: verify token · 3 · 9 · get
717
+ - db/orders: SELECT orders · 14 · 38 · get
718
+ - { id: cat, service: catalogue, name: "GET /skus", start: 55, duration: 62, parent: get, kind: client }
719
+ - { id: sku, service: cache, name: "GET sku:A1", start: 58, duration: 4, parent: cat, kind: cache }
720
+ - { id: pay, service: payments, name: "GET /payments/ord_123", start: 120, duration: 16, parent: get, kind: client, error: true, attrs: { http.status: 502 }, note: The first call returned 502 and the retry succeeded. }
721
+ ```
722
+
723
+ ## ERD
724
+
725
+ ```erd
726
+ title: Shop schema
727
+ entities:
728
+ - name: users
729
+ columns:
730
+ - { name: id, type: uuid, pk: true }
731
+ - { name: email, type: text }
732
+ - name: orders
733
+ columns:
734
+ - { name: id, type: uuid, pk: true }
735
+ - { name: user_id, type: uuid, fk: true }
736
+ - { name: total, type: numeric }
737
+ relations:
738
+ - orders }o--|| users: placed by
739
+ ```
740
+
741
+ ## User story
742
+
743
+ ```userstory
744
+ id: sw-us-1
745
+ role: shopper
746
+ want: pay in one step
747
+ soThat: I can check out quickly
748
+ priority: High
749
+ points: 3
750
+ criteria:
751
+ - { given: a saved card, when: I confirm, then: the order is placed }
752
+ links:
753
+ - { ref: '#sw-seq-checkout', label: Checkout flow }
754
+ ```
755
+
756
+ ## Timeline
757
+
758
+ ```timeline
759
+ title: Roadmap
760
+ items:
761
+ - "[done] Q1 · MVP"
762
+ - "[current] Q2 · Beta"
763
+ - "[next] Q3 · GA"
764
+ ```
765
+
766
+ ## Kanban
767
+
768
+ ```kanban
769
+ title: Sprint board
770
+ columns:
771
+ - { label: To do, cards: [ { title: Auth, tag: backend }, { title: Login UI } ] }
772
+ - { label: Doing, cards: [ { title: Checkout, tag: api } ] }
773
+ - { label: Done, cards: [ { title: DB schema } ] }
774
+ ```
775
+
776
+ ## Rollout
777
+
778
+ A gate compares the new version against the old one on the same traffic, not
779
+ against last week. A stage that fails its gate holds; nothing reverts until a
780
+ person or the rollback line says so.
781
+
782
+ ```rollout
783
+ title: Orders API v2
784
+ strategy: canary
785
+ stages:
786
+ - "[done] 1% · Smoke · 15m — no 5xx"
787
+ - "[current] 10% · Canary · 30m — error rate < 0.5%"
788
+ - "[next] 50% · Half · 2h — p95 < 300 ms"
789
+ - { name: Full, traffic: 100, status: next, note: Delete the v1 deployment after 24 h. }
790
+ rollback: Flip the orders-v2 flag off; v1 keeps serving without a deploy.
791
+ ```
792
+
793
+ ## Story map
794
+
795
+ ```storymap
796
+ title: Checkout story map
797
+ description: "The backbone of activities across the top; each release slice holds the cards that ship under each step."
798
+ backbone:
799
+ - { label: Browse, note: Find the product }
800
+ - { label: Decide, note: Trust the price }
801
+ - { label: Pay }
802
+ - { label: Confirm }
803
+ slices:
804
+ - label: MVP
805
+ cells:
806
+ - [Search box]
807
+ - ["Product page", "Price incl. tax"]
808
+ - [{ title: Card payment, tag: risky }]
809
+ - [Order email]
810
+ - label: Later
811
+ cells:
812
+ - ["Filters", "Saved carts"]
813
+ - [Reviews]
814
+ - [{ title: Wallet pay, tag: spike }]
815
+ - []
816
+ ```
817
+
818
+ ## Task tracker
819
+
820
+ ```statustable
821
+ variant: tracker
822
+ title: Tasks
823
+ items:
824
+ - { task: Set up CI, status: done, priority: high, owner: Ana }
825
+ - { task: Payment flow, status: doing, priority: high, owner: Lee, due: Fri }
826
+ - { task: Write docs, status: todo, priority: med }
827
+ - { task: Rate limiting, status: blocked, priority: low }
828
+ ```
829
+
830
+ ## Status table
831
+
832
+ ```statustable
833
+ title: Launch workstreams
834
+ description: Weekly status roll-up; statuses use our own vocabulary.
835
+ columns: [Workstream, Latest update]
836
+ statuses:
837
+ - { label: on track, color: green }
838
+ - { label: at risk, color: amber }
839
+ - { label: blocked, color: error }
840
+ - { label: in review, color: purple }
841
+ rows:
842
+ - { cells: [Checkout revamp, A/B test at 50%; conversion up 0.3pp], status: on track }
843
+ - cells: [Vendor SSO, Contract countersigned; sandbox creds due this week]
844
+ status: at risk
845
+ subtasks:
846
+ - { cells: [SAML metadata exchange, Our metadata sent Tuesday], status: on track }
847
+ - { cells: [Provisioning sync, Waiting on sandbox credentials], status: blocked }
848
+ - { cells: [Rate-limit rework, PR up for second review], status: in review }
849
+ - { cells: [Docs refresh, Draft complete], status: done }
850
+ ```
851
+
852
+ ## Risk register
853
+
854
+ ```risk
855
+ title: Launch risks
856
+ description: Reviewed weekly until GA.
857
+ items:
858
+ - { risk: Key dependency ships late, likelihood: high, impact: high, mitigation: Feature-flag the integration and keep the old path., owner: PM, status: open }
859
+ - { risk: Traffic spike overwhelms the API, likelihood: med, impact: high, mitigation: Autoscaling + load-shedding at the gateway., owner: Platform, status: mitigating }
860
+ - { risk: Docs lag the release, likelihood: med, impact: low, status: accepted }
861
+ - { risk: Beta feedback arrives after freeze, likelihood: low, impact: low, mitigation: Weekly beta digest to the team., owner: DevRel, status: closed }
862
+ ```
863
+
864
+ ## Wireframe
865
+
866
+ ```wireframe
867
+ title: Checkout screen
868
+ screens:
869
+ - device: phone
870
+ title: Checkout
871
+ elements:
872
+ - { type: header, label: Checkout }
873
+ - { type: input, label: Card number }
874
+ - { type: input, label: Expiry }
875
+ - { type: button, label: Pay now, tone: accent }
876
+ - { type: text, label: Secure payment, align: c, tone: muted }
877
+ ```
878
+
879
+ ## API endpoint
880
+
881
+ ```endpoint
882
+ method: POST
883
+ path: /orders/{cartId}
884
+ title: Create an order
885
+ description: Convert a cart into an order and start fulfilment.
886
+ auth: Bearer <token>
887
+ params:
888
+ - { name: cartId, in: path, type: uuid, required: true, desc: Cart to convert }
889
+ - { name: dry-run, in: query, type: boolean, desc: Validate without persisting }
890
+ body:
891
+ - { name: items, type: "Item[]", required: true, desc: Line items }
892
+ - { name: coupon, type: string, desc: Optional discount code }
893
+ responses:
894
+ - { status: 201, desc: Order created }
895
+ - { status: 400, desc: Invalid cart }
896
+ - { status: 401, desc: Missing or invalid token }
897
+ request: |
898
+ { "items": [{ "sku": "A1", "qty": 2 }], "coupon": "SAVE10" }
899
+ response: |
900
+ { "id": "ord_123", "status": "pending", "total": 42.00 }
901
+ ```
902
+
903
+ ```packet
904
+ title: Wire format of the request header
905
+ width: 32
906
+ fields:
907
+ - { label: Version, bits: 4, value: "1" }
908
+ - { label: Flags, bits: 4 }
909
+ - { label: Total length, bits: 24 }
910
+ - { label: Request id, bits: 32, accent: teal }
911
+ ```
912
+
913
+ ## Event contract
914
+
915
+ Payments emits this event and never waits for a reply, so the endpoint contract
916
+ above does not apply to it. Delivery is at-least-once: a consumer that is not
917
+ idempotent will ship the same order twice.
918
+
919
+ ```eventcontract
920
+ name: order.paid
921
+ version: v2
922
+ channel: orders
923
+ summary: Payment for an order was captured, so fulfilment may start.
924
+ producers: [payments]
925
+ consumers: [fulfilment, billing, analytics]
926
+ delivery: at-least-once
927
+ ordering: per-key
928
+ key: order_id
929
+ retention: 7d
930
+ schema:
931
+ - order_id uuid required — The order the payment belongs to
932
+ - payment_id uuid required — The capture in the payment provider
933
+ - amount money required — Captured amount, as a decimal string with currency
934
+ - method string required — One of card, wallet, or invoice
935
+ - captured_at timestamp required — When the provider confirmed the capture
936
+ headers:
937
+ - trace_id string required — W3C trace id of the checkout request
938
+ example: |
939
+ { "order_id": "ord_123", "payment_id": "pay_77", "amount": "42.00 EUR", "method": "card" }
940
+ errors:
941
+ - DuplicateCapture — the same payment_id arrived twice; drop the event
942
+ note: Fulfilment must be idempotent on order_id.
943
+ ```
944
+
945
+ ## Pull quote
946
+
947
+ ```pullquote
948
+ text: Site group = read at that plant. Role group = extra actions on top.
949
+ attribution: The taxonomy in one line
950
+ ```
951
+
952
+ ## Access in three layers
953
+
954
+ ```layers
955
+ items:
956
+ - { kicker: L1, title: Identity, source: IdP JWT, question: "Are you a signed-in user?", body: Validate the token and resolve groups. }
957
+ - { kicker: L2, title: Site scope, source: JWT + lookup, question: "Which sites may you see?", body: Confirm the site is in the user's set. }
958
+ - { kicker: L3, title: Permission, source: App DB, question: "What may you do here?", body: Resolve persona permissions from the matrix. }
959
+ ```
960
+
961
+ ## Success callout
962
+
963
+ ```callout
964
+ tone: success
965
+ title: Why this scales
966
+ body: Site and role are separate group types, so they grow on independent axes.
967
+ ```
968
+
969
+ ## Capability matrix
970
+
971
+ ```matrix
972
+ title: Who can do what
973
+ corner: Role / App
974
+ cols: [Billing, Reports, Admin]
975
+ rows:
976
+ - { label: Owner, cells: [Full, Full, Full] }
977
+ - { label: Manager, cells: [Full, Read, "—"] }
978
+ - { label: Viewer, cells: [Read, Read, "—"] }
979
+ ```
980
+
981
+ ## Anatomy of a permission
982
+
983
+ ```anatomy
984
+ separator: ":"
985
+ parts:
986
+ - { label: App, value: meridian, note: Which product. }
987
+ - { label: Feature, value: billing, note: The area within the app. }
988
+ - { label: Action, value: invoices.read, note: The specific capability. }
989
+ ```
990
+
991
+ ## Composition
992
+
993
+ ```composition
994
+ title: How access is decided
995
+ result: May read invoices
996
+ gates:
997
+ - { label: Identity, desc: A valid signed-in user. }
998
+ - { label: Scope, desc: The request is in range. }
999
+ - { label: Permission, desc: The action is granted. }
1000
+ ```
1001
+
1002
+ ## Drivers
1003
+
1004
+ ```drivers
1005
+ title: What guided the design
1006
+ items:
1007
+ - { title: Single sign-on, body: One login carries the user everywhere., tag: "HOW: token", icon: lock, accent: purple }
1008
+ - { title: Read per site, body: "Access is scoped to the user's sites.", tag: "WHERE: site group", icon: location, accent: green }
1009
+ - { title: Governed roles, body: "An IGA requests, approves, certifies.", tag: "WHO: role groups", icon: shield, accent: blue }
1010
+ - { title: Per-app permissions, body: The same role differs per app., tag: "WHAT: matrix", icon: grid, accent: amber }
1011
+ ```
1012
+
1013
+ ## Options
1014
+
1015
+ ```options
1016
+ title: Approaches explored
1017
+ items:
1018
+ - { kicker: Option 1, title: App-managed roles, how: Roles in our own DB., pros: [Full control], cons: ["Second source of truth"], verdict: "REJECTED", tone: rejected }
1019
+ - { kicker: Option 2, title: Global role groups, how: One global group per role., pros: [Fewest groups], cons: ["Applies at every site"], verdict: "VIABLE", tone: viable }
1020
+ - { kicker: Option 3, title: Per-site role groups, how: One group per persona per site., pros: [Least privilege], cons: [Most groups], verdict: "CHOSEN", tone: chosen }
1021
+ ```
1022
+
1023
+ ## Decision scorecard
1024
+
1025
+ ```scorecard
1026
+ title: Queue technology choice
1027
+ description: "Weighted 0-5 scoring across the four criteria that mattered. Throughput and operational cost carry double weight; SQS wins on the weighted total."
1028
+ criteria:
1029
+ - { label: Throughput, weight: 2 }
1030
+ - { label: Operational cost, weight: 2 }
1031
+ - { label: Team familiarity }
1032
+ - { label: Ecosystem }
1033
+ options:
1034
+ - { label: Kafka, scores: [5, 2, 3, 5], note: self-hosted }
1035
+ - { label: SQS, scores: [3, 5, 4, 3], note: managed }
1036
+ - { label: RabbitMQ, scores: [3, 3, 4, 4] }
1037
+ ```
1038
+
1039
+ ## Spec
1040
+
1041
+ ```spec
1042
+ title: Per-site role groups
1043
+ accent: green
1044
+ rows:
1045
+ - { label: Groups, value: "SiteN-Users (read) + SiteN-<Persona> per staffed plant." }
1046
+ - { label: Roles, value: "Each group reads as (site, role); the token carries the scope." }
1047
+ - { label: Resolution, steps: [Decode token, "Read (site, role)", Check matrix] }
1048
+ ```
1049
+
1050
+ ## Fancy list
1051
+
1052
+ ```list
1053
+ title: Why documentation-as-code
1054
+ style: accent
1055
+ items:
1056
+ - { lead: Typed blocks, text: "76 strict schemas, validated by chiltepin check.", accent: blue }
1057
+ - { lead: One source of truth, text: Diagrams live in the .md file., accent: green }
1058
+ - { lead: Many outputs, text: "HTML, slides, and PDF from one file.", accent: amber }
1059
+ ```
1060
+
1061
+ ## Story backlog
1062
+
1063
+ ```stories
1064
+ title: Sprint backlog
1065
+ items:
1066
+ - { id: US-1, title: One-step checkout, role: shopper, want: pay in one step, soThat: I finish faster, priority: High, points: 5, tags: [checkout], open: true, criteria: [{ given: items in cart, when: I pay, then: an order is created }] }
1067
+ - { id: US-2, title: Save payment method, role: returning shopper, want: store a card, soThat: I skip re-entry, priority: Med, points: 3 }
1068
+ ```
1069
+
1070
+ ## Design pattern
1071
+
1072
+ ```pattern
1073
+ name: Repository
1074
+ category: Backend
1075
+ intent: Hide persistence behind a collection-like interface so the domain never sees the database.
1076
+ forces: [Swap the data store, Unit-test without a DB, No query leaks into the domain]
1077
+ participants:
1078
+ - { name: OrderRepository, role: interface the service depends on }
1079
+ - { name: PgOrderRepository, role: Postgres implementation }
1080
+ - { name: OrderService, role: caller (domain logic) }
1081
+ consequences:
1082
+ pros: [Swappable storage, Testable with a fake]
1083
+ cons: [Another layer, Risk of anemic pass-through]
1084
+ ```
1085
+
1086
+ ## Bug gallery
1087
+
1088
+ ```gallery
1089
+ cols: 2
1090
+ items:
1091
+ - { title: "N+1 query", lang: JavaScript, accent: red, caption: "1000 users = 1001 queries.", code: "users.forEach(async u =>\n await q('...user_id=?', u.id));" }
1092
+ - { title: "Off-by-one", lang: JavaScript, accent: amber, caption: "arr[len] is undefined.", code: "for (let i=0; i<=arr.length; i++)\n process(arr[i]);" }
1093
+ - { title: "Open redirect", lang: JavaScript, accent: red, caption: "Allowlist destinations.", code: "res.redirect(req.query.url);" }
1094
+ - { title: "Secrets in code", lang: JavaScript, accent: red, caption: "Use env vars + a scanner.", code: "const KEY = 'sk-live-abc123';" }
1095
+ ```
1096
+
1097
+ ## Gallery — diagram comparison
1098
+
1099
+ ```gallery
1100
+ title: Compare architectures
1101
+ cols: 3
1102
+ items:
1103
+ - title: Monolith
1104
+ caption: One deployable unit.
1105
+ block:
1106
+ type: c4
1107
+ level: container
1108
+ nodes:
1109
+ - { id: u, col: 1, row: 1, kind: person, name: User }
1110
+ - { id: app, col: 2, row: 1, kind: container, family: service, name: App }
1111
+ - { id: db, col: 2, row: 2, kind: store, name: DB }
1112
+ edges:
1113
+ - { from: u, to: app }
1114
+ - { from: app, to: db }
1115
+ - title: Microservices
1116
+ caption: Independent services.
1117
+ block:
1118
+ type: c4
1119
+ level: container
1120
+ nodes:
1121
+ - { id: gw, col: 1, row: 1, kind: container, family: service, name: Gateway }
1122
+ - { id: a, col: 2, row: 1, kind: container, family: service, name: Orders }
1123
+ - { id: b, col: 2, row: 2, kind: container, family: service, name: Billing }
1124
+ edges:
1125
+ - { from: gw, to: a }
1126
+ - { from: gw, to: b }
1127
+ - title: Event-driven
1128
+ caption: Async via a broker.
1129
+ block:
1130
+ type: block
1131
+ nodes:
1132
+ - { id: p, col: 1, row: 1, kind: producer, name: Producer }
1133
+ - { id: bus, col: 2, row: 1, kind: topic, name: Bus }
1134
+ - { id: c, col: 3, row: 1, kind: consumer, name: Consumer }
1135
+ edges:
1136
+ - { from: p, to: bus }
1137
+ - { from: bus, to: c }
1138
+ ```
1139
+
1140
+ ## Data charts
1141
+
1142
+ ```chart
1143
+ title: p95 latency by week
1144
+ kind: line
1145
+ unit: ms
1146
+ labels: [W1, W2, W3, W4, W5, W6]
1147
+ series:
1148
+ - { label: /orders, accent: navy, values: [240, 226, 215, 188, 164, 150] }
1149
+ - { label: /search, accent: teal, values: [310, 295, 288, 262, 246, 231] }
1150
+ ```
1151
+
1152
+ ```chart
1153
+ title: Monthly cost by service
1154
+ kind: bar
1155
+ unit: k
1156
+ labels: [API, Workers, Postgres, Cache]
1157
+ series:
1158
+ - { label: March, accent: navy, values: [8.2, 4.6, 3.1, 1.2] }
1159
+ - { label: April, accent: amber, values: [7.4, 5.1, 3.3, 1.1] }
1160
+ ```
1161
+
1162
+ ```chart
1163
+ title: Traffic by client
1164
+ kind: donut
1165
+ unit: "%"
1166
+ items:
1167
+ - { label: Web, value: 62, accent: navy }
1168
+ - { label: iOS, value: 23, accent: teal }
1169
+ - { label: Android, value: 15, accent: amber }
1170
+ ```
1171
+
1172
+ ```chart
1173
+ title: Migration progress
1174
+ description: "A gauge answers how far along one number is; max is the full sweep (default 100)."
1175
+ kind: gauge
1176
+ unit: "%"
1177
+ items:
1178
+ - { label: Services migrated, value: 68, desc: of 42 services }
1179
+ - { label: Traffic cut over, value: 41, accent: teal }
1180
+ ```
1181
+
1182
+ ```chart
1183
+ title: Incident causes last quarter
1184
+ description: "A pie is the donut with the centre filled — use it when there is no total worth printing."
1185
+ kind: pie
1186
+ unit: "%"
1187
+ items:
1188
+ - { label: Config change, value: 41 }
1189
+ - { label: Deploy, value: 27 }
1190
+ - { label: Capacity, value: 18, accent: teal }
1191
+ - { label: Third party, value: 14 }
1192
+ ```
1193
+
1194
+ ```chart
1195
+ title: Checkout latency distribution
1196
+ description: "Sampled requests, binned by the renderer (Sturges); the dashed rule is the mean."
1197
+ kind: histogram
1198
+ unit: ms
1199
+ values: [112, 118, 121, 124, 127, 129, 131, 133, 134, 136, 138, 139, 141, 142, 143, 145,
1200
+ 146, 148, 149, 151, 152, 154, 155, 157, 158, 160, 162, 164, 166, 168, 171, 174,
1201
+ 177, 181, 185, 189, 194, 199, 205, 212, 220, 231, 244, 258, 275, 296, 322, 358]
1202
+ ```
1203
+
1204
+ ```chart
1205
+ title: Response time against the SLO
1206
+ description: "Where the p95 target sits on the fitted curve — the z-score under each marker says how far out it is."
1207
+ kind: bell
1208
+ unit: ms
1209
+ mean: 180
1210
+ sd: 35
1211
+ markers:
1212
+ - { at: 250, label: SLO p95, accent: amber }
1213
+ - { at: 120, label: Cache hit }
1214
+ ```
1215
+
1216
+ ```chart
1217
+ title: Build time by pipeline
1218
+ description: "Five-number summaries over the last 200 runs; the accent box is the pipeline under repair."
1219
+ kind: boxplot
1220
+ unit: min
1221
+ boxes:
1222
+ - { label: Web, min: 4.1, q1: 5.2, median: 5.9, q3: 6.8, max: 8.3, outliers: [11.4] }
1223
+ - { label: API, min: 2.8, q1: 3.4, median: 3.9, q3: 4.6, max: 5.7 }
1224
+ - { label: Mobile, min: 9.5, q1: 12.1, median: 14.2, q3: 16.8, max: 21, outliers: [26.5, 28.1], accent: amber }
1225
+ - { label: Data, min: 6, q1: 7.7, median: 8.4, q3: 9.9, max: 12.2 }
1226
+ ```
1227
+
1228
+ ```chart
1229
+ title: Support tickets by root cause
1230
+ description: "The accent bars are the vital few — fix those and 80% of the volume is gone."
1231
+ kind: pareto
1232
+ items:
1233
+ - { label: Login, value: 142 }
1234
+ - { label: Billing, value: 96 }
1235
+ - { label: Export, value: 41 }
1236
+ - { label: Search, value: 23 }
1237
+ - { label: Mobile, value: 14 }
1238
+ - { label: Other, value: 9 }
1239
+ ```
1240
+
1241
+ ```chart
1242
+ title: Q3 engineering targets
1243
+ description: "Measure against target inside poor / ok / good ranges, one row per metric."
1244
+ kind: bullet
1245
+ unit: "%"
1246
+ bullets:
1247
+ - { label: Uptime, value: 99.7, target: 99.9, ranges: [99, 99.5, 100] }
1248
+ - { label: Test coverage, value: 72, target: 80, ranges: [50, 70, 100] }
1249
+ - { label: Cache hit rate, value: 91, target: 85, ranges: [60, 80, 100] }
1250
+ - { label: Error budget used, value: 64, target: 50, ranges: [50, 80, 100], accent: red }
1251
+ ```
1252
+
1253
+ ```sankey
1254
+ title: Where the cloud bill goes
1255
+ description: "Node height and ribbon thickness are the same scale — the widest ribbon is where the money actually goes."
1256
+ unit: k
1257
+ links:
1258
+ - { from: Bill, to: Compute, value: 62 }
1259
+ - { from: Bill, to: Storage, value: 28 }
1260
+ - { from: Bill, to: Network, value: 10 }
1261
+ - { from: Compute, to: Serving, value: 38 }
1262
+ - { from: Compute, to: Batch, value: 24 }
1263
+ - { from: Storage, to: Hot, value: 19 }
1264
+ - { from: Storage, to: Archive, value: 9 }
1265
+ ```
1266
+
1267
+ ```treemap
1268
+ title: Cloud spend by service
1269
+ description: "Area is the value — a treemap keeps working where a donut gives up at six slices."
1270
+ unit: k
1271
+ items:
1272
+ - { label: Compute, value: 62, desc: EC2 + Lambda }
1273
+ - { label: Storage, value: 28, desc: S3 and snapshots }
1274
+ - { label: Databases, value: 24 }
1275
+ - { label: Network, value: 16 }
1276
+ - { label: Observability, value: 11, accent: amber }
1277
+ - { label: CI runners, value: 9 }
1278
+ ```
1279
+
1280
+ ```venn
1281
+ title: Who owns the release process
1282
+ sets:
1283
+ - { label: Platform, desc: runtime and CI }
1284
+ - { label: Product, desc: features and UX }
1285
+ shared:
1286
+ - { sets: [Platform, Product], label: Release process }
1287
+ ```
1288
+
1289
+ ```fishbone
1290
+ title: Why checkout latency rose
1291
+ description: "One effect at the head, cause categories as bones, specific causes along each bone."
1292
+ effect: p95 checkout over 2s
1293
+ causes:
1294
+ - { label: Code, items: [Sync capture call, N+1 cart query] }
1295
+ - { label: Infrastructure, items: [Undersized DB pool, No read replica] }
1296
+ - { label: Traffic, items: [Flash-sale spikes] }
1297
+ - { label: Process, items: [No load test before release] }
1298
+ ```
1299
+
1300
+ ```chart
1301
+ title: Queue vendors at a glance
1302
+ kind: radar
1303
+ labels: [Throughput, Latency, Cost, Ops burden, Ecosystem]
1304
+ series:
1305
+ - { label: Kafka, accent: navy, values: [5, 4, 2, 2, 5] }
1306
+ - { label: SQS, accent: amber, values: [3, 3, 5, 5, 3] }
1307
+ ```
1308
+
1309
+ ```chart
1310
+ title: Fix candidates by effort and impact
1311
+ description: "Bubble area is the affected traffic share; the dashed guides cut the plot into four quadrants."
1312
+ kind: scatter
1313
+ xLabel: Effort (weeks)
1314
+ yLabel: Impact
1315
+ points:
1316
+ - { x: 1, y: 8, size: 30, label: Cache headers }
1317
+ - { x: 3, y: 9, size: 80, label: Read replica }
1318
+ - { x: 2.5, y: 4, size: 15, label: Retry budget }
1319
+ - { x: 6, y: 3, size: 20, label: Full rewrite }
1320
+ - { x: 2, y: 2, label: New font }
1321
+ guides:
1322
+ x: 4
1323
+ y: 5
1324
+ quadrants: [Do first, Plan well, Fill in, Avoid]
1325
+ ```
1326
+
1327
+ ```slopegraph
1328
+ title: Support volume by channel
1329
+ description: "Each line is one channel between two years; the slope is the message, and the accented line carries the story."
1330
+ left: "2023"
1331
+ right: "2025"
1332
+ unit: "%"
1333
+ items:
1334
+ - { label: Email, from: 48, to: 22 }
1335
+ - { label: Chat, from: 20, to: 45, accent: teal }
1336
+ - { label: Phone, from: 32, to: 33 }
1337
+ - { label: Self-serve, from: 0, to: 12 }
1338
+ ```
1339
+
1340
+ ## Latency budget
1341
+
1342
+ ```chart
1343
+ kind: waterfall
1344
+ description: Where the checkout API's 250 ms budget goes, hop by hop.
1345
+ unit: ms
1346
+ budget: 250
1347
+ items:
1348
+ - { label: DNS + TLS, value: 35 }
1349
+ - { label: Gateway, value: 20, desc: auth + routing }
1350
+ - { label: Orders service, value: 90 }
1351
+ - { label: Database, value: 70 }
1352
+ - { label: Serialization, value: 15 }
1353
+ ```
1354
+
1355
+ ## Heatmap
1356
+
1357
+ ```heatmap
1358
+ title: p95 latency by region × hour
1359
+ description: UTC hours, last 7 days.
1360
+ unit: ms
1361
+ xLabels: ["00", "04", "08", "12", "16", "20"]
1362
+ rows:
1363
+ - { label: us-east-1, values: [122, 118, 145, 210, 265, 190] }
1364
+ - { label: eu-west-1, values: [110, 105, 168, 240, 195, 150] }
1365
+ - { label: ap-south-1, values: [180, 210, 310, 285, 240, 205] }
1366
+ ```
1367
+
1368
+ ## Figure
1369
+
1370
+ ```figure
1371
+ src: https://chiltepin.dev/logo.png
1372
+ alt: The Chiltepin logo
1373
+ caption: "The Chiltepin logo, capped at 420 px."
1374
+ width: 420
1375
+ ```
1376
+
1377
+ ## Unified diff
1378
+
1379
+ ```code
1380
+ kind: diff
1381
+ title: "fix: clamp retry backoff"
1382
+ lang: TypeScript
1383
+ code: |
1384
+ @@ -12,7 +12,7 @@
1385
+ function backoff(attempt: number): number {
1386
+ - return 100 * attempt ** 2;
1387
+ + return Math.min(30_000, 100 * attempt ** 2);
1388
+ }
1389
+ ```
1390
+
1391
+ ## Before / after
1392
+
1393
+ ```code
1394
+ kind: compare
1395
+ lines: true
1396
+ caption: Backoff grows without bound on the left; the right caps it at 30 s.
1397
+ blocks:
1398
+ - lang: TypeScript
1399
+ highlight: "2"
1400
+ code: |
1401
+ function backoff(attempt: number): number {
1402
+ return 100 * attempt ** 2;
1403
+ }
1404
+ - lang: TypeScript
1405
+ highlight: "2"
1406
+ code: |
1407
+ function backoff(attempt: number): number {
1408
+ return Math.min(30_000, 100 * attempt ** 2);
1409
+ }
1410
+ ```
1411
+
1412
+ ## Runbook steps
1413
+
1414
+ ```steps
1415
+ title: Deploy a hotfix
1416
+ description: The fast path for a production fix — branch, ship, tag.
1417
+ items:
1418
+ - title: Branch from main
1419
+ body: Hotfixes always branch from the latest main.
1420
+ code: git checkout -b hotfix/fix-retry main
1421
+ lang: bash
1422
+ - title: Ship the fix
1423
+ body: Commit and push; CI runs the full suite.
1424
+ code: git push -u origin hotfix/fix-retry
1425
+ lang: bash
1426
+ note: CI must be green before the next step.
1427
+ - title: Tag and deploy
1428
+ code: git tag v1.4.1 && git push --tags
1429
+ lang: bash
1430
+ ```
1431
+
1432
+ ## FAQ
1433
+
1434
+ ```faq
1435
+ title: Common questions
1436
+ items:
1437
+ - q: Where does the content live?
1438
+ a: "In the .md files on disk — they are the single source of truth. Every diagram on this page is a typed YAML block."
1439
+ open: true
1440
+ - q: Do diagrams need a drawing tool?
1441
+ a: "No. Change the YAML and rerun chiltepin html — the SVG updates."
1442
+ - q: How do I validate a doc?
1443
+ a: Run chiltepin check and fix every diagnostic it reports.
1444
+ ```
1445
+
1446
+ ## Capacity math
1447
+
1448
+ ```envelope
1449
+ title: Order-write capacity
1450
+ description: The estimate that sizes the write path.
1451
+ assumptions:
1452
+ - { label: Daily active users, value: 2M }
1453
+ - { label: Orders / user / day, value: "0.5" }
1454
+ - { label: Payload per order, value: 2 KB }
1455
+ - { label: Retention, value: 5 years }
1456
+ steps:
1457
+ - { label: Orders per day, calc: "2M × 0.5", result: 1M/day }
1458
+ - { label: Write QPS, calc: "1M / 86,400 s", result: "≈ 12 rps" }
1459
+ - { label: Peak QPS, calc: "12 × 3 (peak factor)", result: "≈ 36 rps" }
1460
+ - { label: Storage per year, calc: "1M × 2 KB × 365", result: "≈ 730 GB/yr" }
1461
+ result: { label: Provision for, value: "~75 rps write peak · ~4 TB over retention" }
1462
+ ```
1463
+
1464
+ ## Service objectives
1465
+
1466
+ ```slo
1467
+ title: Orders API — SLOs
1468
+ items:
1469
+ - { name: Availability, sli: Successful requests / total requests, target: 99.9%, current: 99.98%, window: 30d, budget: 0.15 }
1470
+ - { name: Latency, sli: Requests served under 400 ms (p99), target: 99%, current: 98.8%, window: 30d, budget: 0.6 }
1471
+ - { name: Freshness, sli: Order events indexed within 60 s, target: 99.5%, current: 97.9%, window: 7d, budget: 1.0 }
1472
+ ```
1473
+
1474
+ ## Terminal session
1475
+
1476
+ ```code
1477
+ kind: terminal
1478
+ title: deploy — production
1479
+ session: |
1480
+ $ kubectl rollout status deploy/orders-api
1481
+ # wait for the rollout to settle before tagging
1482
+ Waiting for deployment "orders-api" rollout to finish: 2 of 4 updated replicas are available...
1483
+ deployment "orders-api" successfully rolled out
1484
+ $ kubectl get pods -l app=orders-api
1485
+ NAME READY STATUS RESTARTS AGE
1486
+ orders-api-7d4b9c6f5d-2xkqp 1/1 Running 0 52s
1487
+ orders-api-7d4b9c6f5d-9mwlt 1/1 Running 0 48s
1488
+ $ git tag v2.3.0 && git push --tags
1489
+ ```
1490
+
1491
+ ## SWOT
1492
+
1493
+ ```swot
1494
+ title: Taking Chiltepin to the enterprise
1495
+ description: Where we stand before the enterprise push.
1496
+ strengths:
1497
+ - Docs-as-code fits existing review workflows
1498
+ - 107 typed blocks cover most technical stories
1499
+ - Renders to HTML, slides, and PDF from one file
1500
+ weaknesses:
1501
+ - No SSO / SCIM integration yet
1502
+ - Small team — support hours are limited
1503
+ opportunities:
1504
+ - Compliance push makes auditable docs attractive
1505
+ - AI agents author blocks natively via the skill
1506
+ threats:
1507
+ - Incumbent wikis bundle "good enough" diagrams
1508
+ - Long procurement cycles slow adoption
1509
+ ```
1510
+
1511
+ ```scqa
1512
+ title: Why this quarter goes to checkout
1513
+ lede: The one decision this review needs.
1514
+ situation: We process 12k orders a day across three regions.
1515
+ complication: p95 checkout crossed 2s in March and conversion fell 3.1pp with it.
1516
+ question: Where does the next quarter of platform work go?
1517
+ answer: Move payment capture off the request path — it returns 1.8s of the 2.4s.
1518
+ because:
1519
+ - Capture is 74% of p95 and is fully async-able
1520
+ - No schema change, so it ships inside one quarter
1521
+ ```
1522
+
1523
+ ```scenarios
1524
+ title: Three ways next year goes
1525
+ description: The three cases span $13M of FY27 revenue.
1526
+ drivers: [Capture moved async, Conversion recovery, Volume growth]
1527
+ outcomeLabel: FY27 revenue
1528
+ cases:
1529
+ - { label: Downside, values: ["Q4 slip", "+0.8pp", "5%"], outcome: "$18M", tone: neg }
1530
+ - { label: Base, values: ["Q3", "+2.1pp", "8%"], outcome: "$24M", tone: base }
1531
+ - { label: Upside, values: ["Q3", "+3.4pp", "15%"], outcome: "$31M", tone: pos }
1532
+ ```
1533
+
1534
+ ```harvey
1535
+ title: Queue vendor fit
1536
+ description: "Ratings are judgements, 0-4; the WEIGHTED row is computed, so the recommendation and the arithmetic agree."
1537
+ columns: [Kafka, SQS, RabbitMQ]
1538
+ scale: [poor, excellent]
1539
+ rows:
1540
+ - { label: Throughput, ratings: [4, 2, 3], weight: 2, note: sustained messages per second }
1541
+ - { label: Operational burden, ratings: [1, 4, 3], weight: 2 }
1542
+ - { label: Team familiarity, ratings: [2, 4, 3] }
1543
+ - { label: Ecosystem, ratings: [4, 3, 3] }
1544
+ recommend: SQS
1545
+ ```
1546
+
1547
+ ```wardley
1548
+ title: Where to build, where to buy
1549
+ description: "Build the scoring model, buy the warehouse — only the model is still evolving."
1550
+ components:
1551
+ - { id: analyst, label: Analyst, x: 0.72, y: 0.96, kind: user }
1552
+ - { id: reports, label: Reporting UI, x: 0.42, y: 0.74 }
1553
+ - { id: model, label: Scoring model, x: 0.22, y: 0.54, kind: build, movement: 0.18 }
1554
+ - { id: warehouse, label: Warehouse, x: 0.78, y: 0.32, kind: commodity }
1555
+ links:
1556
+ - { from: analyst, to: reports }
1557
+ - { from: reports, to: model }
1558
+ - { from: model, to: warehouse }
1559
+ ```
1560
+
1561
+
1562
+ ## Conversion funnel
1563
+
1564
+ ```chart
1565
+ kind: funnel
1566
+ title: Signup → paid conversion
1567
+ description: Last 90 days, all channels.
1568
+ unit: users
1569
+ items:
1570
+ - { label: Visited landing page, value: 48000 }
1571
+ - { label: Started signup, value: 9600, desc: email + password }
1572
+ - { label: Activated, value: 4300, desc: created a first doc }
1573
+ - { label: Upgraded to paid, value: 860 }
1574
+ ```
1575
+
1576
+ ## OKRs
1577
+
1578
+ ```okr
1579
+ title: Q3 objectives
1580
+ description: Two objectives, reviewed monthly.
1581
+ items:
1582
+ - objective: Make onboarding effortless
1583
+ owner: Growth
1584
+ krs:
1585
+ - { kr: Time-to-first-doc under 5 minutes, progress: 0.7, status: on-track }
1586
+ - { kr: Activation rate from 45% to 60%, progress: 0.4, status: at-risk }
1587
+ - { kr: Ship 10 quick-start templates, progress: 1, status: done }
1588
+ - objective: Earn enterprise trust
1589
+ owner: Platform
1590
+ krs:
1591
+ - { kr: Ship SSO + audit log, progress: 0.85, status: on-track }
1592
+ - { kr: SOC 2 Type II report issued, progress: 0.2, status: off-track }
1593
+ ```
1594
+
1595
+ ## Personas
1596
+
1597
+ ```persona
1598
+ title: Who we build for
1599
+ personas:
1600
+ - name: Maya Chen
1601
+ role: Staff engineer
1602
+ quote: I want the diagram in the PR diff, not in a wiki.
1603
+ goals: [Docs that live with the code, Reviewable architecture changes]
1604
+ frustrations: [Stale wiki pages, Screenshots of whiteboards]
1605
+ tools: [VS Code, GitHub, Mermaid]
1606
+ accent: blue
1607
+ - name: Priya Patel
1608
+ role: Engineering manager
1609
+ quote: Every reorg breaks our onboarding docs.
1610
+ goals: [One source of truth per system, New joiners productive in week one]
1611
+ frustrations: ["Docs no one owns", Tribal knowledge in DMs]
1612
+ tools: [Linear, Notion, Slack]
1613
+ accent: teal
1614
+ ```
1615
+
1616
+ ## Changelog
1617
+
1618
+ ```changelog
1619
+ title: Release history
1620
+ releases:
1621
+ - version: 2.0.0
1622
+ date: 2026-06-24
1623
+ tag: breaking
1624
+ items:
1625
+ - { type: changed, text: "Config moved from .chiltepinrc to chiltepin.config.json" }
1626
+ - { type: removed, text: Dropped Node 18 support }
1627
+ - { type: security, text: Bumped yaml to patch CVE-2026-1234 }
1628
+ - version: 1.4.0
1629
+ date: 2026-05-12
1630
+ tag: minor
1631
+ items:
1632
+ - { type: added, text: Dark theme + custom theme files }
1633
+ - { type: fixed, text: Slide overflow on long tables }
1634
+ - version: 1.3.2
1635
+ date: 2026-04-03
1636
+ tag: patch
1637
+ items:
1638
+ - { type: fixed, text: Windows path handling in chiltepin check }
1639
+ ```
1640
+
1641
+ ## Team
1642
+
1643
+ ```team
1644
+ title: Who owns what
1645
+ members:
1646
+ - { name: Ana Ruiz, role: Tech lead, focus: Rendering pipeline, accent: navy }
1647
+ - { name: Sam Okafor, role: Backend, focus: Sync + integrations, accent: teal }
1648
+ - { name: Lena Fischer, role: Design, focus: Themes and house style, accent: purple }
1649
+ - { name: Tom Alvarez, role: CLI, focus: chiltepin commands and DX, accent: green }
1650
+ - { name: DevRel, initials: DR, role: Advocacy, focus: Docs and community, accent: amber }
1651
+ ```
1652
+
1653
+ ## Design tokens
1654
+
1655
+ ```palette
1656
+ title: Brand palette
1657
+ description: Core color tokens — reference by name, never by raw hex.
1658
+ cols: 4
1659
+ colors:
1660
+ - { name: Primary, value: "#0E54A1", usage: "Buttons, links, focus rings" }
1661
+ - { name: Ink, value: "#1F2937", usage: Body text and headings }
1662
+ - { name: Surface, value: "#F6F8FB", usage: Card and panel backgrounds }
1663
+ - { name: Positive, value: "#1F9747", usage: Success states }
1664
+ - { name: Warning, value: "#B45309", usage: Caution banners }
1665
+ - { name: Negative, value: "#B3261E", usage: Errors and destructive actions }
1666
+ - { name: Accent, value: "#5B4A8A", usage: Charts and highlights }
1667
+ - { name: Muted, value: "#8A8475", usage: Secondary text }
1668
+ ```
1669
+
1670
+ ## Type scale
1671
+
1672
+ ```typescale
1673
+ description: The ramp from display headings down to code.
1674
+ items:
1675
+ - { name: Display, size: 40, weight: 700, font: display, lineHeight: 1.1, note: hero headings }
1676
+ - { name: H1, size: 28, weight: 700, font: display, lineHeight: 1.2 }
1677
+ - { name: Body, size: 15, lineHeight: 1.6 }
1678
+ - { name: Caption, size: 12, weight: 500, note: secondary text }
1679
+ - { name: Code, size: 13, font: mono }
1680
+ ```
1681
+
1682
+ ## Usage guidelines
1683
+
1684
+ ```dodont
1685
+ title: Button usage
1686
+ description: How to place and label buttons.
1687
+ dos:
1688
+ - { text: Use one primary button per view }
1689
+ - { text: Write labels as verbs, example: "Save changes" }
1690
+ - { text: Pair a destructive action with a confirm step }
1691
+ donts:
1692
+ - { text: Stack two primary buttons side by side }
1693
+ - { text: Disable a button without explaining why, example: "tooltip: Add a line item first" }
1694
+ ```
1695
+
1696
+ ## Component inventory
1697
+
1698
+ ```inventory
1699
+ title: Component status
1700
+ description: Maturity of the shared component library.
1701
+ items:
1702
+ - { name: Button, status: stable, tag: v2 }
1703
+ - { name: Data table, status: beta, note: Column-resize API may change before GA }
1704
+ - { name: Date picker, status: experimental }
1705
+ - { name: Modal (legacy), status: deprecated, note: Use Dialog instead }
1706
+ - { name: Charts, status: planned, note: Targeted for next quarter }
1707
+ ```
1708
+
1709
+ ## Array walkthrough
1710
+
1711
+ ```array
1712
+ title: Binary search for 27 — step 2
1713
+ description: mid lands on 19, so the search space halves to the right.
1714
+ items:
1715
+ - { value: "3", tone: muted }
1716
+ - { value: "7", tone: muted }
1717
+ - { value: "12", label: lo }
1718
+ - { value: "19", tone: active, label: mid }
1719
+ - { value: "27", tone: target }
1720
+ - { value: "41", label: hi }
1721
+ window: { from: 2, to: 5, label: search space }
1722
+ ```
1723
+
1724
+ ## Linked list
1725
+
1726
+ ```linkedlist
1727
+ title: Reversing a list — step 2
1728
+ description: prev trails curr; each step flips one next pointer.
1729
+ nodes:
1730
+ - { value: "9", tone: visited, label: prev }
1731
+ - { value: "4", tone: active, label: curr }
1732
+ - { value: "7", label: next }
1733
+ - { value: "1" }
1734
+ ```
1735
+
1736
+ ## Binary tree
1737
+
1738
+ ```bintree
1739
+ title: BST search for 27
1740
+ description: The tinted chain is the comparison path down to the target.
1741
+ nodes:
1742
+ - { id: root, value: "19", tone: visited }
1743
+ - { id: l, value: "8", parent: root, side: left }
1744
+ - { id: ll, value: "4", parent: l, side: left }
1745
+ - { id: lr, value: "12", parent: l, side: right }
1746
+ - { id: r, value: "31", parent: root, side: right, tone: active }
1747
+ - { id: rl, value: "27", parent: r, side: left, tone: target }
1748
+ - { id: rr, value: "40", parent: r, side: right }
1749
+ ```
1750
+
1751
+ ## Hash table
1752
+
1753
+ ```hashmap
1754
+ description: "Chained buckets — hash(key) % 8; plum and grape collide in bucket 2."
1755
+ buckets: 8
1756
+ entries:
1757
+ - { key: apple, value: "3", bucket: 0 }
1758
+ - { key: plum, value: "9", bucket: 2, tone: active }
1759
+ - { key: grape, value: "1", bucket: 2 }
1760
+ - { key: fig, value: "7", bucket: 5, tone: muted }
1761
+ ```
1762
+
1763
+ ## Agent loop
1764
+
1765
+ ```agentloop
1766
+ title: Support triage agent
1767
+ description: "One loop turn — the agent reads the ticket, calls tools, and replies or escalates. The loop ends only two ways: a reply is sent or a human gets the ticket."
1768
+ agent:
1769
+ name: Triage agent
1770
+ model: claude-sonnet-4-6
1771
+ note: Routes each ticket to a fix or a human.
1772
+ env: Customer
1773
+ tools:
1774
+ - { name: search_kb, desc: Search help-center articles }
1775
+ - { name: get_account, desc: Look up plan and billing state }
1776
+ - { name: create_ticket, desc: Escalate to a human queue }
1777
+ memory:
1778
+ - conversation history
1779
+ - customer profile
1780
+ stop: reply sent or ticket escalated
1781
+ ```
1782
+
1783
+ ## Execution trace
1784
+
1785
+ ```trace
1786
+ title: Password reset — one episode
1787
+ description: "One real episode: the agent checked delivery logs before blaming spam."
1788
+ turns:
1789
+ - role: user
1790
+ text: I never get the reset email.
1791
+ - role: assistant
1792
+ thinking: Could be a bounce — check delivery logs before blaming spam.
1793
+ text: Let me check our email logs.
1794
+ - role: tool
1795
+ tool: email_logs.search
1796
+ args: '{ "to": "sam@example.com", "type": "password_reset" }'
1797
+ result: "1 result: bounced (mailbox full)"
1798
+ - role: assistant
1799
+ text: Your mailbox rejected the email — free up space and I will resend it.
1800
+ ```
1801
+
1802
+ ## Prompt anatomy
1803
+
1804
+ ```prompt
1805
+ title: Support reply template
1806
+ description: The system + user template behind every triage turn.
1807
+ segments:
1808
+ - kind: system
1809
+ label: role + guardrails
1810
+ text: "You are a support agent for {{product}}. Answer from the docs only."
1811
+ - kind: user
1812
+ text: "Customer ({{plan}} plan) asks: {{question}}"
1813
+ vars:
1814
+ - { name: product, desc: Product name from config }
1815
+ - { name: plan, desc: Plan tier of the signed-in customer }
1816
+ - { name: question, desc: The inbound message }
1817
+ ```
1818
+
1819
+ ## Context budget
1820
+
1821
+ ```context
1822
+ title: Where the 200k window goes
1823
+ description: Steady-state budget for one triage turn.
1824
+ window: 200000
1825
+ segments:
1826
+ - { label: system prompt, tokens: 6000, accent: navy }
1827
+ - { label: tool schemas, tokens: 14000, accent: teal }
1828
+ - { label: retrieval, tokens: 60000, accent: amber, desc: top-8 chunks }
1829
+ - { label: history, tokens: 70000, accent: purple }
1830
+ ```
1831
+
1832
+ ## Section divider
1833
+
1834
+ ```divider
1835
+ kicker: PART 2
1836
+ title: What we change
1837
+ subtitle: The three fixes, in the order we ship them.
1838
+ accent: navy
1839
+ ```
1840
+
1841
+ ## Big number
1842
+
1843
+ ```bignumber
1844
+ value: "-75%"
1845
+ label: Checkout p95 after moving capture off the request path
1846
+ context: "2.4s → 600ms, measured over four weeks of production traffic"
1847
+ delta: "-1.8s"
1848
+ trend: down
1849
+ accent: green
1850
+ ```
1851
+
1852
+ ## Takeaways
1853
+
1854
+ ```takeaways
1855
+ items:
1856
+ - text: The synchronous capture call was the bottleneck
1857
+ detail: It accounted for 71% of the 2.4s checkout p95.
1858
+ - text: Moving it to a queue cut p95 by 75%
1859
+ detail: No other change shipped in the window.
1860
+ - text: Conversion recovered within two weeks
1861
+ detail: "+0.4pp against the pre-regression baseline."
1862
+ - text: The pattern generalises
1863
+ detail: Audit every synchronous third-party call on the hot path.
1864
+ ```
1865
+
1866
+ ## Quality, UML, ML, and deck shapes
1867
+
1868
+ Thirteen blocks added in the September coverage sweep. Each is the example `chiltepin block <type>` prints.
1869
+
1870
+ ### Audit findings
1871
+
1872
+ What a review found, worst first, with the evidence and the fix.
1873
+
1874
+ ```audit
1875
+ title: Security review — payments service
1876
+ scope: payments-api, payments-worker
1877
+ date: 2026-09-01
1878
+ auditor: AppSec
1879
+ findings:
1880
+ - { id: F1, title: Refund endpoint has no rate limit, severity: high, area: API, evidence: "POST /refunds accepted 500 req/s in the load test", fix: Add the shared limiter at 20 req/min per key, owner: payments, status: fixing }
1881
+ - { id: F2, title: Card BIN logged at INFO, severity: critical, area: Logging, evidence: "worker.log line 2231", fix: Mask to first 2 digits; add the log-scrub test, owner: payments, status: open }
1882
+ - { id: F3, title: Dependency openssl 3.0.8 has a known CVE, severity: medium, area: Supply chain, fix: Bump to 3.0.14, owner: platform, status: fixed }
1883
+ - { id: F4, title: Health endpoint leaks build SHA, severity: info, area: API, status: accepted }
1884
+ ```
1885
+
1886
+ ### Readiness checklist
1887
+
1888
+ A standard applied once: each item a verdict with its proof, the pass rate derived.
1889
+
1890
+ ```checklist
1891
+ title: Production readiness — search-indexer
1892
+ standard: PRR v4
1893
+ groups:
1894
+ - label: Observability
1895
+ items:
1896
+ - "[pass] Dashboards for the four golden signals — grafana/search-indexer"
1897
+ - "[pass] Alerts route to the on-call — pagerduty svc P4"
1898
+ - "[partial] Traces sampled at 10% — target is 100% on errors"
1899
+ - label: Resilience
1900
+ items:
1901
+ - "[fail] Load test at 2× peak — not run since the Kafka move"
1902
+ - "[na] Multi-region failover — single-region service by design"
1903
+ ```
1904
+
1905
+ ### Performance budget
1906
+
1907
+ Measured against budget; over, near, and ok are derived, not typed.
1908
+
1909
+ ```perfbudget
1910
+ title: Product page — web vitals
1911
+ context: p75, mobile, 4G, 30-day field data
1912
+ metrics:
1913
+ - { metric: LCP, budget: 2500, measured: 2140, unit: ms }
1914
+ - { metric: INP, budget: 200, measured: 260, unit: ms }
1915
+ - { metric: CLS, budget: 0.1, measured: 0.04 }
1916
+ - { metric: JS transferred, budget: 300, measured: 285, unit: KB }
1917
+ - { metric: Lighthouse perf, budget: 90, measured: 84, lowerIsBetter: false }
1918
+ ```
1919
+
1920
+ ### Latency percentiles
1921
+
1922
+ The tail per endpoint on one axis, with the SLO drawn.
1923
+
1924
+ ```percentiles
1925
+ title: Checkout API latency — last 7 days
1926
+ unit: ms
1927
+ slo: 300
1928
+ rows:
1929
+ - { label: POST /checkout, p50: 120, p90: 210, p95: 260, p99: 420, max: 1900 }
1930
+ - { label: GET /cart, p50: 18, p90: 35, p95: 48, p99: 90, max: 410 }
1931
+ - { label: POST /payments, p50: 240, p90: 380, p95: 470, p99: 900, max: 3100, accent: red }
1932
+ ```
1933
+
1934
+ ### Threat model
1935
+
1936
+ STRIDE over a data flow with trust boundaries and the mitigations in a table.
1937
+
1938
+ ```threatmodel
1939
+ title: Login — STRIDE
1940
+ boundaries:
1941
+ - { id: inet, col: 1, row: 1, cols: 1, rows: 1, label: Internet }
1942
+ - { id: dmz, col: 2, row: 1, cols: 2, rows: 1, label: Trusted network }
1943
+ nodes:
1944
+ - { id: browser, col: 1, row: 1, name: Browser, kind: external }
1945
+ - { id: auth, col: 2, row: 1, name: Auth service }
1946
+ - { id: users, col: 3, row: 1, name: Users DB, kind: store }
1947
+ edges:
1948
+ - { from: browser, to: auth, label: "POST /login", channel: tls }
1949
+ - { from: auth, to: users, label: SELECT by email, channel: internal }
1950
+ threats:
1951
+ - { id: T1, target: browser, category: S, threat: Credential stuffing, mitigation: Rate limit + breached-password check, severity: high, status: mitigated }
1952
+ - { id: T2, target: auth, category: I, threat: Verbose error reveals whether the email exists, mitigation: One generic message, severity: medium, status: open }
1953
+ - { id: T3, target: users, category: T, threat: Password hash column altered by an admin, mitigation: Audit log + Argon2id, severity: high, status: accepted }
1954
+ ```
1955
+
1956
+ ### Use cases
1957
+
1958
+ Who uses the system for what, and which cases include or extend others.
1959
+
1960
+ ```usecase
1961
+ system: Ticketing
1962
+ actors:
1963
+ - { id: cust, name: Customer }
1964
+ - { id: agent, name: Support agent }
1965
+ - { id: pay, name: Payment gateway, kind: system, side: right }
1966
+ cases:
1967
+ - { id: buy, name: Buy ticket }
1968
+ - { id: pay1, name: Pay by card }
1969
+ - { id: refund, name: Request refund }
1970
+ - { id: approve, name: Approve refund }
1971
+ links:
1972
+ - cust -> buy
1973
+ - cust -> refund
1974
+ - agent -> approve
1975
+ - pay -> pay1
1976
+ relations:
1977
+ - { from: buy, to: pay1, kind: include }
1978
+ - { from: refund, to: approve, kind: extend }
1979
+ ```
1980
+
1981
+ ### Package diagram
1982
+
1983
+ Which module may depend on which.
1984
+
1985
+ ```pkg
1986
+ title: Backend module layout
1987
+ packages:
1988
+ - { id: api, col: 1, row: 1, name: api, contains: [routes, middleware] }
1989
+ - { id: domain, col: 2, row: 1, name: domain, contains: [orders, payments, inventory] }
1990
+ - { id: infra, col: 3, row: 1, name: infra, contains: [postgres, kafka, stripe] }
1991
+ - { id: shared, col: 2, row: 2, name: shared, contains: [ids, money, clock] }
1992
+ deps:
1993
+ - { from: api, to: domain, kind: use }
1994
+ - { from: domain, to: infra, kind: import, label: ports only }
1995
+ - { from: domain, to: shared }
1996
+ - { from: infra, to: shared }
1997
+ ```
1998
+
1999
+ ### Timing diagram
2000
+
2001
+ Two lifelines stepping through states over the same sixty seconds.
2002
+
2003
+ ```timing
2004
+ title: Circuit breaker under a downstream outage
2005
+ unit: s
2006
+ lanes:
2007
+ - label: Breaker
2008
+ states:
2009
+ - { state: closed, from: 0, to: 12 }
2010
+ - { state: open, from: 12, to: 42, accent: red }
2011
+ - { state: half-open, from: 42, to: 46, accent: amber }
2012
+ - { state: closed, from: 46, to: 60 }
2013
+ - label: Downstream
2014
+ states:
2015
+ - { state: healthy, from: 0, to: 10 }
2016
+ - { state: down, from: 10, to: 44, accent: red }
2017
+ - { state: healthy, from: 44, to: 60 }
2018
+ events:
2019
+ - { at: 12, label: 5 failures in 10 s }
2020
+ - { at: 46, label: probe ok }
2021
+ constraints:
2022
+ - { from: 12, to: 42, label: open 30 s }
2023
+ ```
2024
+
2025
+ ### Neural network
2026
+
2027
+ The shape of a model, one column per layer.
2028
+
2029
+ ```neuralnet
2030
+ title: Digit classifier
2031
+ params: 1.2M
2032
+ layers:
2033
+ - { label: Input, units: 784, kind: input, note: 28×28 pixels }
2034
+ - { label: Conv 3×3, units: 32, kind: conv, activation: ReLU }
2035
+ - { label: Max pool, units: 32, kind: pool }
2036
+ - { label: Dense, units: 128, kind: dense, activation: ReLU }
2037
+ - { label: Dropout 0.3, units: 128, kind: dropout }
2038
+ - { label: Output, units: 10, kind: output, activation: softmax }
2039
+ ```
2040
+
2041
+ ### Model card
2042
+
2043
+ The handoff card for a deployed model.
2044
+
2045
+ ```modelcard
2046
+ name: support-intent-v3
2047
+ version: 3.2.0
2048
+ task: Text classification (support ticket intent)
2049
+ architecture: DistilBERT fine-tune, 6 layers
2050
+ params: 66M
2051
+ owner: ML platform
2052
+ license: Internal
2053
+ intendedUse:
2054
+ - Route inbound tickets to one of 14 queues
2055
+ - Suggest a queue to an agent; never auto-close
2056
+ outOfScope:
2057
+ - Any language other than English and Spanish
2058
+ trainingData:
2059
+ - 410k tickets, 2024-01 to 2025-06, PII scrubbed
2060
+ metrics:
2061
+ - { name: Macro F1, value: 0.91, split: test }
2062
+ - { name: Latency p95, value: 38 ms, split: prod, note: CPU, batch 1 }
2063
+ limitations:
2064
+ - Confuses billing and refund intents on short tickets
2065
+ ```
2066
+
2067
+ ### Mind map
2068
+
2069
+ Unordered ideas around one centre.
2070
+
2071
+ ```mindmap
2072
+ center: Onboarding v2
2073
+ nodes:
2074
+ - { id: acct, label: Account, accent: blue }
2075
+ - { id: sso, parent: acct, label: SSO first }
2076
+ - { id: invite, parent: acct, label: Team invites }
2077
+ - { id: data, label: Data import, accent: teal }
2078
+ - { id: csv, parent: data, label: CSV }
2079
+ - { id: api, parent: data, label: API sync }
2080
+ - { id: learn, label: Learning, accent: amber }
2081
+ - { id: tour, parent: learn, label: Product tour }
2082
+ - { id: tmpl, parent: learn, label: Templates }
2083
+ ```
2084
+
2085
+ ### Process chevrons
2086
+
2087
+ The phases of a process and where we are.
2088
+
2089
+ ```chevrons
2090
+ title: Incident lifecycle
2091
+ current: 3
2092
+ steps:
2093
+ - { label: Detect, desc: alert fires }
2094
+ - { label: Triage, desc: severity + owner }
2095
+ - { label: Mitigate, desc: stop the bleeding }
2096
+ - { label: Resolve, desc: root cause fixed }
2097
+ - { label: Review, desc: postmortem in 5 days }
2098
+ ```
2099
+
2100
+ ### Roadmap
2101
+
2102
+ Themes by quarter with a now rule.
2103
+
2104
+ ```roadmap
2105
+ title: Platform roadmap 2026
2106
+ periods: [Q1, Q2, Q3, Q4]
2107
+ now: Q3
2108
+ themes: [Reliability, Developer experience, Cost]
2109
+ items:
2110
+ - { label: Multi-region Postgres, theme: Reliability, from: Q1, to: Q2, status: done }
2111
+ - { label: Chaos game days, theme: Reliability, from: Q3, status: current }
2112
+ - { label: Preview envs per PR, theme: Developer experience, from: Q2, to: Q3, status: current }
2113
+ - { label: Golden-path templates, theme: Developer experience, from: Q4, status: next }
2114
+ - { label: Spot instances for batch, theme: Cost, from: Q2, status: done }
2115
+ - { label: Egress cut 30%, theme: Cost, from: Q3, to: Q4, status: risk }
2116
+ ```
2117
+
2118
+ ## Older spellings still work
2119
+
2120
+ Twelve old block types merged into canonical blocks; their fence tags remain
2121
+ permanent aliases. They parse, validate, and render as before — `chiltepin check`
2122
+ notes the mapping with a `W_ALIAS_TYPE` warning. The four fences below use the
2123
+ old spellings on purpose:
2124
+
2125
+ ```waterfall
2126
+ title: "The old waterfall tag — now chart (kind: waterfall)"
2127
+ unit: ms
2128
+ items:
2129
+ - { label: Gateway, value: 20 }
2130
+ - { label: Service, value: 90 }
2131
+ - { label: Database, value: 70 }
2132
+ ```
2133
+
2134
+ ```infra
2135
+ title: "The old infra tag — now block (preset: infra)"
2136
+ nodes:
2137
+ - { id: cdn, col: 1, row: 1, kind: cdn, name: CDN }
2138
+ - { id: api, col: 2, row: 1, kind: compute, name: API }
2139
+ - { id: db, col: 3, row: 1, kind: db, name: Database }
2140
+ edges:
2141
+ - cdn -> api
2142
+ - api -> db
2143
+ ```
2144
+
2145
+ ```dag
2146
+ title: "The old dag tag — now flow (variant: dag)"
2147
+ nodes:
2148
+ - { id: build, col: 1, row: 1, kind: start, label: Build }
2149
+ - { id: test, col: 2, row: 1, kind: process, label: Test }
2150
+ - { id: ship, col: 3, row: 1, kind: end, label: Ship }
2151
+ edges:
2152
+ - build -> test
2153
+ - test -> ship
2154
+ ```
2155
+
2156
+ ```tracker
2157
+ title: "The old tracker tag — now statustable (variant: tracker)"
2158
+ items:
2159
+ - { task: Adopt the canonical spellings, status: doing, priority: med }
2160
+ - { task: Rewrite old fences, status: todo, priority: low, owner: nobody — they keep working }
2161
+ ```