@aotter/mantle 0.0.11-alpha.63 → 0.0.11-alpha.64

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 (41) hide show
  1. package/README.md +87 -12
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +52 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/generate.d.ts +2 -0
  7. package/dist/generate.d.ts.map +1 -0
  8. package/dist/generate.js +181 -0
  9. package/dist/generate.js.map +1 -0
  10. package/dist/skills.d.ts +2 -0
  11. package/dist/skills.d.ts.map +1 -0
  12. package/dist/skills.js +80 -0
  13. package/dist/skills.js.map +1 -0
  14. package/dist/update.d.ts +2 -0
  15. package/dist/update.d.ts.map +1 -0
  16. package/dist/update.js +387 -0
  17. package/dist/update.js.map +1 -0
  18. package/docs/adr/0001-four-atom-manifest-model.md +6 -7
  19. package/docs/adr/0007-ai-as-primary-author.md +100 -138
  20. package/docs/adr/0008-structured-diagnostic-shape.md +79 -99
  21. package/docs/adr/0009-consumer-supplied-manifests.md +101 -228
  22. package/docs/adr/0012-views-as-public-rest.md +43 -15
  23. package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +43 -17
  24. package/docs/adr/0018-core-starters-repository-boundary.md +155 -0
  25. package/docs/adr/README.md +8 -6
  26. package/docs/cloudflare-low-level-composition.md +94 -0
  27. package/docs/design-atoms.md +59 -57
  28. package/docs/design-references/editorial-blog-2026-05-05.md +7 -7
  29. package/docs/labels.md +1 -1
  30. package/docs/media-uploads.md +1 -1
  31. package/docs/release-process.md +156 -523
  32. package/package.json +9 -6
  33. package/skills/README.md +20 -16
  34. package/skills/develop/SKILL.md +4 -4
  35. package/skills/install/SKILL.md +16 -2
  36. package/skills/plugin/SKILL.md +1 -1
  37. package/skills/provision/SKILL.md +1 -1
  38. package/skills/theme/SKILL.md +12 -10
  39. package/skills/update/SKILL.md +31 -19
  40. package/skills/customize-design/SKILL.md +0 -215
  41. package/skills/extend/SKILL.md +0 -257
@@ -1,8 +1,9 @@
1
1
  # ADR-0008: Structured diagnostic shape for AI-parseable errors
2
2
 
3
- **Status:** Carried over from POC v0.0.x; refreshed for v0.1.0.
3
+ **Status:** Carried over from POC v0.0.x; amended for the shipped v0.1
4
+ diagnostic emitters and measured harnesses.
4
5
 
5
- **Date**: 2026-04-30 (POC); refreshed 2026-05-03 for v0.1.0 rebuild.
6
+ **Date:** 2026-04-30 (POC); last amended 2026-08-03.
6
7
 
7
8
  **Deciders**: phsu
8
9
 
@@ -12,11 +13,12 @@
12
13
 
13
14
  ## Context
14
15
 
15
- ADR-0007 commits the SDK to three feedback loops (static
16
- validation, test harness, boot-time fail-fast) on top of the
17
- existing runtime layer. Each loop emits errors. If each emits
18
- its own ad-hoc shape, the consumer Claude Code reading those
19
- errors must write three or four parsers — defeating the
16
+ ADR-0007 commits the SDK to three pre-serve feedback loops (static
17
+ validation, local tests/measurements, and boot-time fail-fast) before the
18
+ runtime layer. Authoring/runtime failures need one stable record shape; the
19
+ measured index and HTTP harnesses use their own purpose-shaped JSON reports.
20
+ If each failure emitter used an ad-hoc shape, the consumer agent reading those
21
+ errors would need multiple parsers — defeating the
20
22
  "deterministic feedback" property that justified the contract in
21
23
  the first place.
22
24
 
@@ -32,8 +34,9 @@ free-form message. That is under-specified for the new loops:
32
34
  the AI author can fix without doing its own grep.
33
35
  - A boot error needs to declare **what was checked and what was
34
36
  missing**, so the deploy log is self-explanatory.
35
- - All four loops should agree on **severity** (error vs warning)
36
- so CI integrations don't need per-loop logic.
37
+ - Validation, boot, runtime, and consumer-authored test diagnostics should
38
+ agree on **severity** (error vs warning) so integrations do not need
39
+ per-phase logic.
37
40
 
38
41
  A free-form message field carries all of this in prose, but
39
42
  forces the AI author to do natural-language parsing on every
@@ -41,11 +44,11 @@ diagnostic before it can route a fix. Structure is cheaper.
41
44
 
42
45
  ## Decision
43
46
 
44
- All four feedback loops emit diagnostics in the following shape.
45
- The canonical type, the diagnostic-code constants, and the phase
46
- helpers all live in `@aotter/mantle-spec`; every other
47
- package (runtime, cloudflare adapter, admin UI, CLI) imports from
48
- there.
47
+ Core validation, boot, and runtime emit diagnostics in the following shape.
48
+ The public `test` phase is reserved for consumer test diagnostics; the shipped
49
+ `mantle-harness` commands emit `IndexCoverageReport` and `HttpBenchmarkReport`
50
+ instead. The canonical type, diagnostic-code constants, and shipped phase
51
+ helpers live in `@aotter/mantle-spec`; every other package imports from there.
49
52
 
50
53
  ```ts
51
54
  type Phase = "validate" | "test" | "boot" | "runtime";
@@ -90,13 +93,13 @@ by `phase` (this-loop-only handling). Concrete examples:
90
93
  | `HANDLER_NOT_REGISTERED` | `validate`, `boot`, `runtime` | textual grep miss (warning, validate); registry lookup miss (error, boot); dispatch attempt miss (error, runtime, defense-in-depth) |
91
94
  | `TRIGGER_TARGET_PROCEDURE_UNKNOWN` | `validate`, `boot` | dangling reference caught by either loop |
92
95
  | `TRIGGER_PATH_COLLISION` | `validate`, `boot` | two http Triggers on same method+path |
93
- | `NOT_FOUND` | `test`, `runtime` | unknown name in queryView / GET /api/views/X |
94
- | `INPUT_VALIDATION_FAILED` | `runtime`, `test` | zod validation fail (test harness shares the dispatcher path) |
96
+ | `NOT_FOUND` | `runtime` (`test` reserved) | unknown name in queryView / GET /api/views/X |
97
+ | `INPUT_VALIDATION_FAILED` | `runtime` (`test` reserved) | zod validation failure at the serving boundary |
95
98
 
96
- Codes that are loop-exclusive simply never appear with another
97
- phase — e.g. `FIXTURE_SCHEMA_VIOLATION` only fires in
98
- `phase: "test"`; `INVALID_MANIFEST_ENVELOPE` only in
99
- `phase: "validate"`.
99
+ Codes that are phase-exclusive simply never appear with another phase.
100
+ `INVALID_MANIFEST_ENVELOPE` is validate-only. The catalog reserves
101
+ `FIXTURE_SCHEMA_VIOLATION` for consumer-authored `phase: "test"` diagnostics;
102
+ Core does not currently emit it.
100
103
 
101
104
  ### Why no prefixes
102
105
 
@@ -123,8 +126,8 @@ code string. That was retired because:
123
126
  ### `path` format
124
127
 
125
128
  - For static validation: filesystem path + JSON Pointer fragment,
126
- e.g. `starters/blog/manifests/recent-published.view.yaml#/spec/from`.
127
- - For test harness: test file path + assertion location when
129
+ e.g. `manifests/recent-published.view.yaml#/spec/from`.
130
+ - For a consumer test diagnostic: test file path + assertion location when
128
131
  available, e.g. `tests/handlers/contact.test.ts:42`.
129
132
  - For boot-time: manifest pointer (no on-disk path because boot
130
133
  reads parsed manifests, not files), e.g.
@@ -159,53 +162,47 @@ before applying.
159
162
  ### CLI output mode
160
163
 
161
164
  - `--format=json` (default when stdout is **not** a TTY, e.g. CI,
162
- AI-author): emits `{ "diagnostics": [<Diagnostic>, ...] }` on
163
- stdout; exit code 1 if any has `severity: "error"`, else 0.
165
+ AI-author): emits `{ phase, diagnostics, errorCount, warningCount }` on
166
+ stdout; exit code 1 if any diagnostic has `severity: "error"`, else 0.
164
167
  - `--format=text` (default when stdout **is** a TTY, i.e. human
165
- at terminal): pretty-prints with file:line, colored severity,
166
- prose message, and a "did you mean?" line when `suggestion`
167
- is set.
168
+ at terminal): prints severity, code, path, structured details, prose message,
169
+ and suggestion when present.
168
170
 
169
171
  The same diagnostic objects power both modes; text mode is a
170
172
  formatter, not a separate code path. AI authors invoking the CLI
171
173
  get JSON automatically because they pipe through subprocess; no
172
174
  flag needed.
173
175
 
174
- ### Test harness diagnostic surface
176
+ ### Consumer test diagnostic surface
175
177
 
176
- Test harness errors are returned as result objects, not thrown:
177
-
178
- ```ts
179
- type InvokeResult<T> =
180
- | { ok: true; data: T }
181
- | { ok: false; diagnostic: Diagnostic };
182
- ```
183
-
184
- Tests check `result.ok` and assert against `result.diagnostic.code`
185
- (stable string), not against thrown exception types. This makes
186
- test code robust to error-class refactoring inside the SDK.
178
+ Runtime use cases return result objects carrying runtime-phase diagnostics, so
179
+ consumer tests can assert stable `diagnostic.code` values without matching
180
+ exception prose. A consumer that emits its own fixture/setup diagnostic may use
181
+ `makeDiagnostic({ phase: "test", ... })`. Core currently exports no
182
+ `testDiagnostic` helper and its measured planner/HTTP harnesses return their
183
+ purpose-shaped reports instead of `Diagnostic` objects.
187
184
 
188
185
  ### Runtime diagnostic surface
189
186
 
190
- Runtime HTTP responses on error paths emit a JSON body of the
191
- same shape, plus the HTTP status from the existing error-code
192
- table. The `path` field becomes the HTTP request locator
193
- (method + URL + JSON Pointer for body issues). The `candidates`
194
- field is **always omitted** at runtime to avoid leaking schema
195
- information to untrusted callers.
187
+ Runtime HTTP responses on error paths wrap the same redacted object as
188
+ `{ ok: false, diagnostic }`, plus the HTTP status from the shared error-code
189
+ table. The `path` carries the most specific request/use-case locator available.
190
+ The `candidates` field is **always omitted** at wire egress to avoid leaking
191
+ schema information to untrusted callers.
196
192
 
197
193
  ```http
198
194
  HTTP/1.1 400 Bad Request
199
195
  Content-Type: application/json
200
196
 
201
197
  {
202
- "code": "INPUT_VALIDATION_FAILED",
203
- "phase": "runtime",
204
- "severity": "error",
205
- "path": "POST /api/contact#/body/email",
206
- "value": "not-an-email",
207
- "expected": "string matching format=email",
208
- "message": "Field 'email' must be a valid email address."
198
+ "ok": false,
199
+ "diagnostic": {
200
+ "code": "INPUT_VALIDATION_FAILED",
201
+ "phase": "runtime",
202
+ "severity": "error",
203
+ "path": "POST /api/contact#/body/email",
204
+ "message": "Field 'email' must be a valid email address."
205
+ }
209
206
  }
210
207
  ```
211
208
 
@@ -221,22 +218,15 @@ runtime validator a manifest author's request body hits is a
221
218
  zod schema, produced by the JSON-Schema → zod converter in
222
219
  `@aotter/mantle-spec` (see [`docs/design-atoms.md`](../design-atoms.md) § "Manifest validation — JSON Schema in, zod at runtime").
223
220
 
224
- Concretely, the translation now consumes `ZodError.issues`:
225
-
226
- - `issue.path: (string|number)[]` → JSON Pointer fragment on the
227
- diagnostic's `path` (URL-encoded indices, `/` between segments).
228
- - `issue.code` (`invalid_type`, `too_small`, `invalid_string`,
229
- `invalid_enum_value`, `unrecognized_keys`, …) → mapped to a
230
- small enumerated `expected` string, not surfaced as the
231
- Diagnostic `code` itself. The Diagnostic `code` stays
232
- `INPUT_VALIDATION_FAILED` for the family — keeping the consumer
233
- contract stable across validator-library swaps.
234
- - `invalid_enum_value.options` → `candidates` (validate / test /
235
- boot phases only; stripped at runtime per the rule above).
236
- - `issue.message` is treated as fallback prose; the Diagnostic's
237
- `message` is regenerated from the structured fields by the
238
- shared formatter, so a future zod upgrade that re-words its
239
- defaults doesn't ripple into our consumer-facing strings.
221
+ Concretely, runtime entry validation consumes `ZodError.issues`:
222
+
223
+ - `issue.path: PropertyKey[]` becomes an RFC 6901 JSON Pointer (`~` and `/`
224
+ escaped, numeric segments preserved);
225
+ - every issue stays in the stable `INPUT_VALIDATION_FAILED` family rather than
226
+ exposing zod's internal issue-code vocabulary;
227
+ - `issue.message` supplies fallback human prose. Call sites with known
228
+ trust-boundary context may additionally populate `value`, `expected`, or a
229
+ more specific message before wire redaction.
240
230
 
241
231
  The same rule that retired Ajv's per-validator error format as a
242
232
  Diagnostic candidate (alternative (d) below) applies to zod —
@@ -246,8 +236,8 @@ Diagnostic candidate (alternative (d) below) applies to zod —
246
236
 
247
237
  ### Pros
248
238
 
249
- - One parser handles errors from any loop. AI consumer code can
250
- branch on `code` prefix or suffix without per-loop adapters.
239
+ - One parser handles diagnostics from any phase. AI consumer code branches on
240
+ the exact `code` and optionally `phase`, without per-emitter adapters.
251
241
  - `candidates` + `suggestion` make the most common author errors
252
242
  (typo, unknown name, wrong enum value) one-step fixes — the AI
253
243
  author reads the diagnostic and writes the corrected manifest
@@ -265,9 +255,8 @@ Diagnostic candidate (alternative (d) below) applies to zod —
265
255
 
266
256
  ### Costs
267
257
 
268
- - Shape locked early: any field-shape change forces a doc revise
269
- + a code change across CLI / harness / runtime / consumer
270
- parsers.
258
+ - Shape locked early: any field-shape change forces a doc revise and code
259
+ change across CLI, runtime, adapters, and consumer parsers.
271
260
  - Implementing `candidates` and `suggestion` correctly requires
272
261
  the validator/dispatcher to track richer context (the set of
273
262
  declared Schema names, the registered ref list, etc.). More
@@ -284,11 +273,10 @@ Diagnostic candidate (alternative (d) below) applies to zod —
284
273
  failure mode, not by individual assertion. `INVALID_NAME`
285
274
  with `expected: "kebab-case, 1-64 chars"` covers the family;
286
275
  the `value` and `expected` fields carry the specifics.
287
- - **`message` and structured fields drift**. The free-form
288
- message contradicts the structured fields. Mitigation: in the
289
- spec package, `message` is generated FROM the structured
290
- fields by a single formatter; not authored separately per
291
- diagnostic site.
276
+ - **`message` and structured fields drift**. Mitigation: `makeDiagnostic`
277
+ derives a default message from the structured fields. Explicit contextual
278
+ messages are allowed, but reviewers treat `code`, `phase`, `path`, `value`,
279
+ and `expected` as authoritative and reject contradictions.
292
280
  - **`candidates` leaks information at runtime**. Already
293
281
  addressed: runtime responses omit `candidates`. Code review
294
282
  should treat any runtime path that populates `candidates` as a
@@ -327,27 +315,19 @@ objects feed *into* the Diagnostic translator described under
327
315
  code module; do not redeclare per-package.
328
316
  - When the same root cause can be caught by multiple loops,
329
317
  reuse the code; let `phase` distinguish.
330
- - Implementation: `message` is derived from structured fields by
331
- a single helper (`makeDiagnostic` + phase-helpers
332
- `validateDiagnostic` / `testDiagnostic` / `bootDiagnostic` /
333
- `runtimeDiagnostic`), all exported from
334
- `@aotter/mantle-spec`, not authored at each error site.
335
- - Documentation: every code in the catalog gets one row in the
336
- v0.1.0 authoring-contract doc (when ported) under
337
- § Error catalog with `code`, applicable phases,
338
- when-it-fires, and an example diagnostic.
318
+ - Implementation: use `makeDiagnostic` or the shipped phase helpers
319
+ `validateDiagnostic`, `bootDiagnostic`, and `runtimeDiagnostic`, all exported
320
+ from `@aotter/mantle-spec`. Consumer test diagnostics call `makeDiagnostic`
321
+ with `phase: "test"` directly.
322
+ - Documentation: keep phase/applicability prose in this ADR and the
323
+ version-matched design/runtime references synchronized with the exported
324
+ catalog.
339
325
 
340
326
  ## Implementation status
341
327
 
342
- **v0.1.0 rebuild — porting in progress.** The shape is locked
343
- by this ADR; the canonical declarations land in
344
- `@aotter/mantle-spec/src/diagnostic.ts` (interface +
345
- `DIAGNOSTIC_CODES` constants + `makeDiagnostic` formatter +
346
- `validateDiagnostic` / `testDiagnostic` / `bootDiagnostic` /
347
- `runtimeDiagnostic` phase helpers). `@aotter/mantle-runtime`
348
- imports them for the dispatcher and the boot validator;
349
- `@aotter/mantle-cloudflare` imports them for HTTP error
350
- responses; the admin UI imports them so the in-browser editor
351
- surfaces the same structured errors the CLI does. The
352
- `aotter/mantle` v0.1.0 milestone tracks the per-package
353
- landings.
328
+ Implemented. Canonical declarations live in
329
+ `packages/mantle-spec/src/kernel/diagnostic.ts`; runtime, Cloudflare adapter,
330
+ admin UI, and CLI import the public spec exports. `redactForWire` removes
331
+ `candidates` before REST/MCP egress. The `test` phase and
332
+ `FIXTURE_SCHEMA_VIOLATION` remain reserved compatibility surface; Core ships no
333
+ test-phase helper or emitter today.