@aotter/mantle 0.1.0-alpha.9 → 0.1.2-alpha.2

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 (109) hide show
  1. package/README.md +38 -38
  2. package/dist/cli/generate.d.ts +10 -1
  3. package/dist/cli/generate.d.ts.map +1 -1
  4. package/dist/cli/generate.js +49 -4
  5. package/dist/cli/generate.js.map +1 -1
  6. package/dist/cli/main.js +0 -8
  7. package/dist/cli/main.js.map +1 -1
  8. package/dist/codegen/emitMantleModule.js +8 -0
  9. package/dist/codegen/emitMantleModule.js.map +1 -1
  10. package/docs/adapter-guide.md +23 -26
  11. package/docs/adr/0008-structured-diagnostic-shape.md +7 -2
  12. package/docs/adr/0010-locale-and-translates.md +14 -16
  13. package/docs/adr/0011-adapter-port-spec.md +2 -1
  14. package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +100 -0
  15. package/docs/adr/0018-core-starters-repository-boundary.md +3 -0
  16. package/docs/adr/0019-sealed-manifest-runtime-pipeline.md +38 -2
  17. package/docs/adr/0020-builtin-handler-contracts-and-matched-upsert.md +199 -0
  18. package/docs/adr/0021-retire-starter-scaffolding.md +30 -0
  19. package/docs/adr/0022-caller-observed-version-occ.md +212 -0
  20. package/docs/adr/0023-port-failure-contract.md +69 -0
  21. package/docs/adr/0024-manifest-native-schema-tables.md +260 -0
  22. package/docs/adr/README.md +19 -3
  23. package/docs/adr/adr-lite-803-request-diagnostics.md +38 -0
  24. package/docs/adr/adr-lite-808-route-readiness.md +47 -0
  25. package/docs/adr/adr-lite-809-bounded-public-content.md +71 -0
  26. package/docs/adr/adr-lite-812-native-parity.md +150 -0
  27. package/docs/adr/adr-lite-823-home-statistics.md +64 -0
  28. package/docs/adr/adr-lite-842-mcp-authoring.md +30 -0
  29. package/docs/adr/adr-lite-861-admin-webmcp.md +42 -0
  30. package/docs/adr/adr-lite-909-admin-ui-kit.md +37 -0
  31. package/docs/api-mcp-authorization.md +3 -664
  32. package/docs/auth-hosting-model.md +4 -4
  33. package/docs/cloudflare-low-level-composition.md +3 -104
  34. package/docs/deferred-lifecycle-queues.md +2 -243
  35. package/docs/design-atoms.md +16 -796
  36. package/docs/direct-authoring.md +5 -0
  37. package/docs/examples/minimal-worker/README.md +37 -0
  38. package/docs/examples/minimal-worker/manifests/site.yaml +25 -0
  39. package/docs/examples/minimal-worker/package.json +26 -0
  40. package/docs/examples/minimal-worker/smoke.mjs +23 -0
  41. package/docs/examples/minimal-worker/src/index.ts +4 -0
  42. package/docs/examples/minimal-worker/tsconfig.json +17 -0
  43. package/docs/examples/minimal-worker/wrangler.jsonc +22 -0
  44. package/docs/handbook/cloudflare/authentication.md +167 -0
  45. package/docs/handbook/cloudflare/bindings.md +236 -0
  46. package/docs/handbook/cloudflare/conventional-worker.md +162 -0
  47. package/docs/handbook/cloudflare/deferred-hooks-queues.md +171 -0
  48. package/docs/handbook/cloudflare/deploy-and-operate.md +105 -0
  49. package/docs/handbook/cloudflare/low-level-composition.md +169 -0
  50. package/docs/handbook/cloudflare/media-r2.md +216 -0
  51. package/docs/handbook/cloudflare/public-web.md +144 -0
  52. package/docs/handbook/concepts/authorization.md +116 -0
  53. package/docs/handbook/concepts/four-atoms.md +173 -0
  54. package/docs/handbook/concepts/lifecycle-and-locales.md +142 -0
  55. package/docs/handbook/concepts/mcp-and-agents.md +109 -0
  56. package/docs/handbook/concepts/procedures-and-triggers.md +221 -0
  57. package/docs/handbook/concepts/runtime-and-adapters.md +177 -0
  58. package/docs/handbook/concepts/views.md +191 -0
  59. package/docs/handbook/examples/commerce-transaction.md +813 -0
  60. package/docs/handbook/examples/guarded-api.md +427 -0
  61. package/docs/handbook/examples/intake-form.md +319 -0
  62. package/docs/handbook/examples/legal-documents.md +218 -0
  63. package/docs/handbook/examples/procurement-approvals.md +240 -0
  64. package/docs/handbook/examples/publication.md +240 -0
  65. package/docs/handbook/examples/reservation.md +220 -0
  66. package/docs/handbook/navigation.json +63 -0
  67. package/docs/handbook/reference/authorization.md +295 -0
  68. package/docs/handbook/reference/diagnostics.md +183 -0
  69. package/docs/handbook/reference/manifest.md +132 -0
  70. package/docs/handbook/reference/procedure.md +263 -0
  71. package/docs/handbook/reference/schema.md +250 -0
  72. package/docs/handbook/reference/site-config.md +233 -0
  73. package/docs/handbook/reference/surface.md +207 -0
  74. package/docs/handbook/reference/trigger.md +193 -0
  75. package/docs/handbook/reference/view.md +256 -0
  76. package/docs/handbook/start/project-and-cli.md +122 -0
  77. package/docs/handbook/start/quickstart-worker.md +193 -0
  78. package/docs/labels.md +3 -1
  79. package/docs/media-uploads.md +3 -184
  80. package/docs/migration-0.1.2.md +60 -3
  81. package/docs/performance-harness.md +127 -10
  82. package/docs/release-process.md +85 -231
  83. package/docs/schema-indexes.md +3 -180
  84. package/docs/sealed-pipeline-ownership.md +6 -5
  85. package/docs/spec-only-host-adoption.md +158 -0
  86. package/docs/transaction-patterns.md +5 -0
  87. package/package.json +21 -25
  88. package/skills/README.md +4 -4
  89. package/skills/develop/SKILL.md +23 -28
  90. package/skills/install/SKILL.md +55 -147
  91. package/skills/provision/SKILL.md +4 -3
  92. package/skills/theme/SKILL.md +6 -6
  93. package/skills/update/SKILL.md +32 -68
  94. package/dist/cli/create.d.ts +0 -2
  95. package/dist/cli/create.d.ts.map +0 -1
  96. package/dist/cli/create.js +0 -243
  97. package/dist/cli/create.js.map +0 -1
  98. package/dist/cli/update.d.ts +0 -2
  99. package/dist/cli/update.d.ts.map +0 -1
  100. package/dist/cli/update.js +0 -413
  101. package/dist/cli/update.js.map +0 -1
  102. package/dist/provision/renderProvisionBundle.d.ts +0 -70
  103. package/dist/provision/renderProvisionBundle.d.ts.map +0 -1
  104. package/dist/provision/renderProvisionBundle.js +0 -367
  105. package/dist/provision/renderProvisionBundle.js.map +0 -1
  106. package/dist/provision.d.ts +0 -2
  107. package/dist/provision.d.ts.map +0 -1
  108. package/dist/provision.js +0 -2
  109. package/dist/provision.js.map +0 -1
@@ -0,0 +1,69 @@
1
+ # ADR-0023: Storage and service failure contracts
2
+
3
+ Status: Accepted for alpha.17 under #857 (amends ADR-0008 and media deletion behavior).
4
+
5
+ This is the diagnostic grammar-revise record: add RESOURCE_EXHAUSTED (507),
6
+ RESOURCE_UNAVAILABLE (503), RATE_LIMITED (429), OUTCOME_UNKNOWN (503),
7
+ PARTIAL_FAILURE (503), PRECONDITION_FAILED (412), and optional safe `failure`
8
+ facts to Diagnostic. No Manifest keys, new ports, or parallel wire format.
9
+ Existing codes and envelopes remain compatible. DiagnosticError accepts internal
10
+ ErrorOptions.cause; causes never enter Diagnostic. Unexpected exceptions must not
11
+ be copied into public messages. Core owns no tenant, plan or provider quota policy.
12
+
13
+ ## Contract
14
+
15
+ A port rejects with DiagnosticError for recognized failures. The diagnostic
16
+ contains stable code, safe message and optional failure facts: outcome is
17
+ not-applied/partial/unknown; retry is never/after-change/safe/reconcile; resource
18
+ is an optional non-sensitive logical resource name, not credentials or SQL.
19
+ A provider adapter or host policy owns classification. Unknown errors stay
20
+ unexpected; never guess quota from arbitrary exception prose. Existing specific
21
+ validation, not-found and atomic OCC diagnostics remain authoritative.
22
+
23
+ `safe` requires idempotence of the same operation against the same resource.
24
+ It does not request automatic retry. Timeouts after write/send default to unknown
25
+ outcome and reconciliation, not unconditional retry. Do not downgrade unknown
26
+ outcome to not-applied merely because no reply arrived. Not-found on an
27
+ idempotent object delete is success. Read absence may be null per the port.
28
+
29
+ ## Operation matrix (public contracts)
30
+
31
+ | Contract | Success | Failure / effect / retry |
32
+ | --- | --- | --- |
33
+ | EntryReader / ViewQueryExecutor | documented rows/null/page | denied/unavailable/rate limit; reads have no business mutation; explicit retry after transient failure |
34
+ | EntryRepository | semantic mutation with atomic expectedVersion | existing NOT_FOUND/CONFLICT; host capacity/denial; unknown write requires readback by stable id/version, never latest-version substitution |
35
+ | SiteConfigRepository | validated settings/locale | reads as above; writes same conditional and uncertain-effect rules as entries |
36
+ | MediaAssetRepository / PendingUploadRepository | metadata persisted/deleted | capacity/availability/unknown write; reconcile by asset/upload id; removal of missing metadata is idempotent where specified |
37
+ | MantleStorageAdapter.prepare / migrations | ready prepared storage | invalid plan/readiness; completed migration steps may persist; journal/readback before retry, no cross-provider rollback promise |
38
+ | DatabaseDriver | driver rows/batch result | constraint/precondition or recognized provider failure; transaction guarantees remain driver-specific; ambiguous writes require readback, SQL is never public |
39
+ | MediaStorage.createUpload | authorized capabilities, not uploaded bytes | policy/size/denied/unavailable; adapter must state any reservations created; no general single-use guarantee |
40
+ | MediaStorage.commitUpload | verified asset, then use case stores metadata | missing/type/size/precondition or partial/unknown provider effect; reconcile same upload group and objects before retry |
41
+ | MediaStorage.deleteObject | object absent | idempotent same-key retry; unavailable/unknown; use case retains metadata if any variant fails and returns PARTIAL_FAILURE |
42
+ | EmailSender | provider accepted, not guaranteed recipient delivery | known rejection not-applied; lost acknowledgement unknown/reconcile; do not resend automatically without provider idempotency/readback |
43
+ | DeferredHookDispatcher | accepted for at-least-once delivery | ambiguous enqueue may duplicate; existing fallback preserves eventId + trigger idempotency identity; consumers must deduplicate |
44
+ | HandlerRegistry / custom handler | application output | DiagnosticError/InvokeFailure preserved; unknown exceptions internal only; handler owns side-effect semantics |
45
+ | Clock / IdGenerator | timestamp / unpredictable unique id | unexpected environmental/programming errors; never silently substitute insecure ids |
46
+ | selected Auth contract (outside Runtime) | authentication/session/admin operation | preserve supported validation/denial; provider/email/storage failure handled at Auth adapter boundary; no assumption that Procedure catches Auth errors |
47
+
48
+ HTTP and Admin use the existing central mapping; MCP retains the diagnostic
49
+ code/failure facts rather than deriving application recovery from HTTP status.
50
+ Admin OCC recovery applies to structured CONFLICT only, not all 409 responses.
51
+ Unknown provider bodies, SQL and causes remain internal. Host-supplied messages
52
+ and resource labels are explicitly public and must not include sensitive data.
53
+
54
+ ## Media partial deletion change
55
+
56
+ Previously object errors were logged and the asset row removed. Now every
57
+ variant deletion is attempted; any failure retains the row and returns partial
58
+ failure. A retry deletes the same keys (including already absent objects), then
59
+ removes metadata. If metadata deletion itself has an uncertain result, reconcile
60
+ by asset id; no new object identities are created. No cross-store transaction is
61
+ implied. Remaining metadata may reference already removed bytes during recovery.
62
+
63
+ ## Compatibility / verification
64
+
65
+ New failure fields are additive; old consumers still have code/message. Media
66
+ partial-delete clients now receive failure rather than misleading success.
67
+ Focused tests cover diagnostic serialization, transport redaction, host rejection
68
+ and retry of partial deletion. Concrete adapter conformance must preserve
69
+ provider constraints and no automatic retry of uncertain writes/sends.
@@ -0,0 +1,260 @@
1
+ # ADR-0024: Materialize each Schema as a native storage table
2
+
3
+ **Status:** Accepted
4
+
5
+ **Date:** 2026-09-18
6
+
7
+ **Related:** ADR-0010, ADR-0011, ADR-0019, ADR-0020, ADR-0022, ADR-0023
8
+
9
+ ## Context
10
+
11
+ The SQLite adapter currently stores every Schema row in one `entries` table.
12
+ Business fields live in a JSON `data` column. Schema indexes add generated
13
+ columns and partial indexes to that shared table, and Schema-shaped SQL views
14
+ project JSON fields back into columns.
15
+
16
+ That layout made the first dynamic runtime small, but it is now the wrong
17
+ authority for a manifest-built system:
18
+
19
+ - a successfully built Manifest already fixes every Schema and field type;
20
+ - generated columns for every historical indexed field accumulate on one
21
+ table, while D1 allows at most 100 columns per table;
22
+ - native SQL, inspection, export, and migration tooling see an implementation
23
+ envelope instead of the authored data model;
24
+ - application migrations and Mantle's canonical `entries` migrations form two
25
+ persistence systems;
26
+ - the compatibility layer is now larger than direct table CRUD.
27
+
28
+ Mantle has not shipped a stable storage format. Keeping the generic table for
29
+ downward compatibility would create the dual path this change is intended to
30
+ remove.
31
+
32
+ ## Decision
33
+
34
+ ### One physical table per Schema
35
+
36
+ The SQLite/D1 storage adapter materializes every compiled Schema as a quoted
37
+ native table. The table contains:
38
+
39
+ - Mantle columns: `_mantle_id`, `_mantle_status`, `_mantle_version`,
40
+ `_mantle_created_at`, `_mantle_updated_at`, and `_mantle_author_id`;
41
+ - one column for every top-level Schema property;
42
+ - native indexes for every `indexes` and `uniqueIndexes` tuple.
43
+
44
+ Single scalar JSON Schema types map to SQLite affinities: string to `TEXT`,
45
+ integer and boolean to `INTEGER`, and number to `REAL`. Objects, arrays, unions,
46
+ and otherwise polymorphic values use `TEXT` containing canonical JSON so a
47
+ round trip cannot change their JSON type. Nullable values use SQL `NULL`.
48
+
49
+ Business columns remain nullable at the database layer. Mantle allows an
50
+ incomplete authoring draft; Runtime validation enforces required fields when a
51
+ record becomes complete or when an operational Schema is written. An optional
52
+ nullable property reads as `null` when its column is null. This is the v0.1
53
+ native-table contract; it intentionally does not preserve a distinction
54
+ between an absent optional nullable field and an explicit null.
55
+
56
+ Schema names and field names remain authored wire names and are always SQL
57
+ identifier quoted. A Schema table uses its authored Schema name. SQLite
58
+ preparation rejects collisions with selected infrastructure tables or views,
59
+ including auth tables; this check belongs to the concrete deployment because
60
+ the portable Manifest cannot know which optional infrastructure a host binds.
61
+ Internal Mantle tables and columns use the reserved `_mantle_` prefix. The
62
+ prefix prevents Mantle metadata from stealing ordinary authored names such as
63
+ `id`, `status`, or `createdAt`.
64
+
65
+ The SQLite adapter no longer creates `entries`, generated field columns, or
66
+ Schema projection views. There is no dual write, compatibility view, or
67
+ fallback JSON repository.
68
+
69
+ ### The compiled storage plan owns DDL
70
+
71
+ SQLite preparation lowers the Schemas already present in the sealed
72
+ `RuntimePlan` into quoted DDL and prepared queries. A persistence-only
73
+ projection of those Schemas has a deterministic storage fingerprint; changes
74
+ to Procedures, Views, or Triggers do not create a storage revision. No second
75
+ physical-plan model mirrors `RuntimePlan`.
76
+
77
+ Other adapters map the same Schema manifests into their own native storage.
78
+ Runtime continues to consume semantic `EntryRepository`,
79
+ `EntryReader`, and `ViewQueryExecutor` ports; SQL remains infrastructure.
80
+
81
+ Repository operations that address one row carry its Schema collection.
82
+ `get(id)` and `readById(id)` become collection-qualified operations. Generated
83
+ bindings hide this argument behind Schema-specific APIs. Runtime operations
84
+ already know the target Schema from their compiled handler, route, or row
85
+ context; callers must not search every table for an unqualified id.
86
+
87
+ Cross-Schema reads are compiled explicitly from the Runtime plan. There is no
88
+ implicit union of all tables. A caller that needs several Schemas invokes the
89
+ declared Views or Schema-specific readers and combines their results at the
90
+ application layer.
91
+
92
+ ### Migrations are build artifacts
93
+
94
+ The SQLite build compares a stored source Schema description with the target
95
+ RuntimePlan and emits a versioned SQL migration artifact containing:
96
+
97
+ - source and target storage fingerprints;
98
+ - ordered SQLite SQL;
99
+ - a checksum over the exact migration content;
100
+ - whether the change is expand-only or destructive.
101
+
102
+ Mantle deterministically emits initial tables and safe additive changes. Field
103
+ renames, type conversions, data transforms, and narrowing constraints are
104
+ destructive in the pre-beta contract. Cloud rejects them; operators rebuild the
105
+ database and move required data manually outside Mantle and Control. Production
106
+ neither generates nor accepts arbitrary migration SQL.
107
+
108
+ Preparation records applied migration ids in the existing `_migrations` ledger.
109
+ The enclosing immutable artifact checksum protects the ordered SQL,
110
+ fingerprints, and target projections. Preparation rejects an unknown source
111
+ fingerprint, changed artifact checksum, skipped revision, or target mismatch.
112
+ Generated migrations are idempotent and retryable after partial application;
113
+ activation and integrity verification run on every attempt instead of being
114
+ treated as one-time ledger entries.
115
+
116
+ Generated migrations quote all identifiers and never interpolate runtime
117
+ input. Automatic deployments retain removed fields, indexes, and tables as a
118
+ physical superset; logical reads follow the selected plan, while retained
119
+ storage keeps the previous Worker rollback-compatible.
120
+
121
+ ### Builder support
122
+
123
+ Builder keeps its in-memory or IndexedDB semantic adapter for interactive
124
+ preview. It does not carry SQLite into portable Runtime.
125
+
126
+ Each successful build can show a draft-to-draft storage delta for authoring
127
+ feedback. It is not labeled as the deployment artifact: only Cloud knows the
128
+ last successfully deployed source revision and produces the exact immutable
129
+ artifact used by deployment. The publish result shows its source/target
130
+ fingerprints, risk classification, ordered SQL, and checksum.
131
+ The interactive preview continues to run the real Mantle Runtime over the
132
+ existing IndexedDB semantic adapter; it does not carry a second SQLite runtime
133
+ or copy preview data into one. Destructive changes remain previewable but are
134
+ not deployable on the pre-beta Cloud path.
135
+
136
+ CI executes generated SQL against SQLite. Mantle Cloud/D1 is authoritative at
137
+ deployment: it checks the immutable artifact, migration ledger, source/target
138
+ fingerprints, database integrity, and canary before restoring traffic. Running
139
+ the same DDL in every Builder browser would duplicate those gates while adding
140
+ WASM weight and a second Worker/browser compatibility surface.
141
+
142
+ Unsaved invalid Manifest edits produce diagnostics and no storage revision.
143
+ Intermediate Builder edits do not become production migrations. Deployment
144
+ diffs the last deployed storage revision against the selected project revision.
145
+
146
+ ### Cloud runtime and Schema upgrades
147
+
148
+ Every Cloud deployment pins these immutable identities:
149
+
150
+ - Mantle runtime release;
151
+ - project revision and compiled plan fingerprint;
152
+ - source and target storage fingerprints;
153
+ - migration checksum;
154
+ - application artifact checksum.
155
+
156
+ Automatic migrations are expand-only and therefore run online. The deployment
157
+ sequence is:
158
+
159
+ 1. verify the current tenant D1 storage fingerprint;
160
+ 2. apply idempotent additive DDL and verify the ledger, marker, and integrity;
161
+ 3. upload an immutable Worker script named by project revision;
162
+ 4. run the canary directly against that script and the actual D1 marker;
163
+ 5. select that revision for the default and custom host routes;
164
+ 6. record the revision active.
165
+
166
+ There is no KV maintenance gate: KV propagation cannot drain in-flight writes,
167
+ and additive DDL does not need one. Destructive changes stop before deployment.
168
+ The old revision script remains addressable, so route failure or operator
169
+ rollback selects the previous script without rebuilding or replacing it.
170
+
171
+ Automatic deployments retain old columns and tables needed by the previous
172
+ active Worker. This keeps code rollback valid. Physical cleanup happens only
173
+ during a later reset or rebuild. Mantle runtime upgrades use the same mechanism
174
+ even when the authored Manifest does not change.
175
+
176
+ Release and application objects are content-addressed. A retry validates and
177
+ reads the same bytes selected by the original operation; mutable release names
178
+ are not valid deployment input.
179
+
180
+ ## Consequences
181
+
182
+ ### Positive
183
+
184
+ - D1, SQLite tools, generated types, and the Manifest describe the same tables.
185
+ - Each Schema gets independent native limits, indexes, query plans, and schema
186
+ evolution.
187
+ - The shared-table column ceiling and permanent generated-column buildup are
188
+ removed.
189
+ - Application migrations and Mantle runtime upgrades use one revision model.
190
+ - Removing the compatibility repository leaves less persistence code.
191
+
192
+ ### Negative
193
+
194
+ - This is a storage-format break and requires coordinated changes across Spec,
195
+ Runtime, SQLite adapters, conformance tests, Builder, and Cloud deployment.
196
+ - Unqualified global entry lookups and implicit cross-Schema lists disappear.
197
+ - Optional nullable fields no longer distinguish absent from explicit null.
198
+ - Destructive schema changes require a manual rebuild and data move outside
199
+ Mantle and Control.
200
+
201
+ ## Alternatives
202
+
203
+ ### Keep `entries` and improve its generated indexes
204
+
205
+ Rejected. It preserves the shared table's column ceiling, JSON inspection
206
+ surface, and a second schema representation after Manifest build already knows
207
+ the physical model.
208
+
209
+ ### Keep `entries` as a registry beside native Schema tables
210
+
211
+ Rejected. A registry adds dual-write atomicity and stale-index failure modes.
212
+ Schema-qualified access removes the need for it.
213
+
214
+ ### Put SQLite WASM in the portable Runtime
215
+
216
+ Rejected. Runtime already has a semantic storage boundary. Builder can verify
217
+ the SQLite lowering as a build check without making every adapter or browser
218
+ preview depend on SQLite.
219
+
220
+ ### Generate production migrations at deploy time
221
+
222
+ Rejected. Deployment must execute an immutable reviewed artifact and remain
223
+ deterministic when retried. AI generation belongs before review, not inside a
224
+ production mutation.
225
+
226
+ ## How to apply
227
+
228
+ 1. Add the sealed physical storage plan and SQLite DDL lowering.
229
+ 2. Change semantic row operations to require collection identity and update all
230
+ first-party callers.
231
+ 3. Replace the shared SQLite repository and View compiler with native-table
232
+ implementations; delete shared-table DDL, views, index reconciliation, and
233
+ compatibility helpers.
234
+ 4. Update memory and IndexedDB adapters to the new semantic port shape.
235
+ 5. Add build-time migration diff/artifact inspection, plus SQLite execution in
236
+ CI and Cloud/D1 deployment verification.
237
+ 6. Pin content-addressed runtime, storage, migration, application, and Worker
238
+ revision identities in Cloud deploys; test initial deploy, additive Schema
239
+ change, runtime-only upgrade, partial migration retry, and route rollback.
240
+ 7. Update all public storage, Schema, Builder, deployment, and migration
241
+ documentation after the conformance and consumer checks pass.
242
+
243
+ ## Decision review
244
+
245
+ Reviewed after implementation against ADR-0019, the semantic storage ports,
246
+ Builder preview persistence, and Mantle Cloud's retryable deployment state.
247
+ The review found and corrected three boundary mistakes before acceptance:
248
+
249
+ - authored data may legitimately contain `id`, `status`, or `createdAt`, so
250
+ physical envelope columns require the `_mantle_` prefix;
251
+ - Builder should expose draft storage risk without pretending it knows the
252
+ deployed baseline; Cloud shows the exact immutable artifact, while CI and
253
+ Cloud/D1 own executable DDL verification and preview stays on IndexedDB;
254
+ - Cloud must pin the runtime release and storage artifact selected when the
255
+ operation starts; a mutable current release would make retry and rollback
256
+ nondeterministic.
257
+
258
+ The native-table path is implemented without a compatibility `entries` table.
259
+ Acceptance is gated by the repository consumer check and the Cloud upgrade,
260
+ retry, and rollback checks in the ADR's final application step.
@@ -18,8 +18,12 @@ Records of *why* mantle ended up shaped this way. The numbering preserves POC AD
18
18
  | [0014](0014-auth-better-auth-and-multi-tenant-mcp.md) | The Cloudflare adapter owns one curated Better Auth 1.7 identity/OAuth/MCP authority with CIMD discovery. Verified callers are normalized into runtime context; mutable staff role and target authorization are re-evaluated per call. | Accepted + amended |
19
19
  | [0016](0016-site-semantic-layer.md) | Site semantic layer: `AGENTS.md` (cross-tool entry) + `.mantle/launch-state.json` (deterministic install context). The older `mantle/site.md` letter surface is suspended from first-run scaffolds. | Accepted (slimmed) |
20
20
  | [0017](0017-media-multi-variant-agent-side-optimization.md) | Multi-variant media assets with agent-side optimization and asset-id entry references. | Accepted |
21
- | [0018](0018-core-starters-repository-boundary.md) | Core produces published SDK artifacts; the separate starters repository validates them as an external consumer. Revisit after release-contract simplification. | Accepted for now |
21
+ | [0018](0018-core-starters-repository-boundary.md) | Core produces published SDK artifacts; the separate starters repository validates them as an external consumer. Revisit after release-contract simplification. | Superseded by 0021 |
22
22
  | [0019](0019-sealed-manifest-runtime-pipeline.md) | One sealed source-to-runtime pipeline, semantic storage seam, and optional Web/Admin/platform dependency direction. | Accepted |
23
+ | [0020](0020-builtin-handler-contracts-and-matched-upsert.md) | Static builtin handler contracts and natural-key matched upsert (`handler.match`). | Accepted + amended by 0022 |
24
+ | [0021](0021-retire-starter-scaffolding.md) | Direct authoring; retire Starter scaffolding. | Accepted; supersedes 0018 |
25
+ | [0022](0022-caller-observed-version-occ.md) | Caller-observed `expectedVersion` for Admin bind and builtin upsert OCC. | Accepted |
26
+ | [0024](0024-manifest-native-schema-tables.md) | Materialize each Schema as a native storage table and deploy reviewed migration artifacts. | Accepted |
23
27
 
24
28
  ## Reading order
25
29
 
@@ -31,7 +35,7 @@ If you're new to the codebase:
31
35
  4. **0007** — what running the SDK feels like as an AI author (and as the operator agent).
32
36
  5. **0011** — the boundary between the runtime and the adapter.
33
37
  6. **0010** — how locale flows through the system.
34
- 7. **0013** — historical install-session context; current first launch is landing provision bundles plus repo-local handoff.
38
+ 7. **0021** — current direct-authoring boundary; **0013** is historical install-session context.
35
39
  8. **0002, 0008** — the two ADRs that touch every diagnostic and every binding.
36
40
 
37
41
  ## What's NOT here (and why)
@@ -54,8 +58,20 @@ The rebuild's ADR-0011 (new) is the most load-bearing addition — the POC accum
54
58
 
55
59
  ## Contributing a new ADR
56
60
 
57
- 1. Pick the next number (currently 0020).
61
+ 1. Pick the next unused number after the highest existing ADR.
58
62
  2. File: `docs/adr/<NNNN>-<kebab-title>.md`.
59
63
  3. Sections: Status, Date, Context, Decision, Consequences, Alternatives, How to apply, Implementation status.
60
64
  4. Link from this README's table.
61
65
  5. Land it in a PR alongside (or before) the implementation it documents — ADR-as-design-artifact, not ADR-as-archaeology.
66
+
67
+ ## ADR-lite records
68
+
69
+ These retain their issue-based filenames and original decision status.
70
+
71
+ | Record | Status |
72
+ |---|---|
73
+ | [#803 Request diagnostics](adr-lite-803-request-diagnostics.md) | Implemented |
74
+ | [#808 Route readiness](adr-lite-808-route-readiness.md) | Accepted |
75
+ | [#809 Bounded public content](adr-lite-809-bounded-public-content.md) | Implemented |
76
+ | [#812 Native parity](adr-lite-812-native-parity.md) | Implemented; deployment evidence linked in record |
77
+ | [#823 Home statistics](adr-lite-823-home-statistics.md) | Proposed; unmerged demo |
@@ -0,0 +1,38 @@
1
+ # ADR-lite: request-scoped Cloudflare diagnostics
2
+
3
+ Status: implemented diagnostic record for #803; real-auth controls and measured
4
+ comparison acceptance belong to the #812 harness. This does not close the
5
+ separate starter provisioning/Smart Placement portion of #803.
6
+
7
+ Use native AsyncLocalStorage and a small versioned testing entry point instead of
8
+ a global current-request counter or a configurable production telemetry system.
9
+ Production mounts only check for an existing test context. With none, there are
10
+ no diagnostic clock reads, binding wrappers, records, observers or response headers.
11
+ Runtime, auth, role, catalog, dispatcher-build and dispatch retain their ownership
12
+ and authorization order. The ordinary runtime-ready promise keeps its identity.
13
+
14
+ Native D1 instrumentation sits beneath both Auth and Runtime and is idempotent.
15
+ It preserves receivers, bind chains, first-column behavior and native objects in
16
+ batches; no second driver observer is added for counting. Provider failures and
17
+ unknown metadata remain visible. Request context is captured when an operation
18
+ starts, so shared work belongs to its initiator. Catalog waiters inherit source
19
+ classification and wait time without inheriting the owner's binding counts.
20
+
21
+ The record freezes at response creation. Inclusive spans can overlap, and partial
22
+ metadata or deferred work must not be presented as a full total. A test-only cloned
23
+ MCP response supplies the JSON-RPC outcome without exposing its content; that
24
+ inspection is outside totalMs but remains instrumentation overhead for HTTP timing.
25
+ Observer errors never replace application results. D1/KV/R2 operations emit only
26
+ counts, sizes with their source/coverage, and durations; object keys, SQL, caller
27
+ identities and credentials never enter the record.
28
+
29
+ R2 GET bodies stay native. Successful direct stream-to-PUT completion confirms
30
+ payload bytes; canceled, incomplete and unconsumed reads remain unknown. This
31
+ avoids losing R2's known-length stream property or hiding buffering overhead.
32
+
33
+ Checks deliberately overlap MCP requests and share KV hit/failure loads, then
34
+ retry after failure. Native I/O is counted once per owner, and denied requests
35
+ leave unreached phases null. Additional checks preserve native D1 private receiver
36
+ and batch semantics, sync/async observer failure, immutable deferred snapshots,
37
+ R2 stream identity and partial-transfer uncertainty. The collector fixture labels
38
+ its deterministic auth explicitly; it is not evidence of native-auth parity.
@@ -0,0 +1,47 @@
1
+ # Route-owned Cloudflare readiness (#808)
2
+
3
+ Status: accepted for the unreleased #806–812 implementation. Follows ADR-0019
4
+ (preparation owns migrations) and amends ADR-0014's unconditional HTTP boot rule.
5
+
6
+ The facade assembles immutable route projections once, then prepares only for
7
+ routes that consume canonical storage. It retains one retryable preparation
8
+ promise, the sealed plan and Better Auth's existing global AsyncLocalStorage,
9
+ `ready` observation, failed-assembly eviction and HTTP `waitUntil` ownership.
10
+
11
+ | Surface | Readiness, including an empty database |
12
+ | --- | --- |
13
+ | Consumer constant health, `/api/views` catalog | No content preparation. |
14
+ | Static Admin shell and assets | No content preparation; incomplete Auth still fails closed as before. |
15
+ | Manifest View/Trigger | Prepare before credential resolution, then use the same runtime invocation. |
16
+ | Admin API, configured Auth base path, OAuth UI/discovery | Prepare before session/provider work. Auth tables share canonical migrations. |
17
+ | MCP, including missing-token challenge | Prepare before the selected Auth verifier. A custom Auth implementation may require D1 even for a denied request; the facade cannot assume otherwise. |
18
+ | Public page/list/discovery and favicon fallback | Their existing `ref.get()` starts preparation when content is needed. |
19
+ | Consumer extension handlers | Call the supplied `getRuntime()` or `ref.get()` before using Mantle content or database-backed Auth. Pure handlers need neither. |
20
+ | Queue/scheduled `getRuntime(env)` | Await both runtime preparation and Auth initialization, unchanged. |
21
+
22
+ No deployment-time migration flag or KV readiness authority is introduced. A
23
+ current database's first protected route needs one fingerprint SELECT; an empty
24
+ or changed database performs canonical setup there. Concurrent first uses share
25
+ that work. A failed preparation returns the facade's redacted 500, and later
26
+ requests retry. Static availability is not a promise that data is ready.
27
+
28
+ The pre-change full-facade fixture recorded 106 SQL operations for its empty-DB
29
+ health request (its four Schemas include indexes), then 1 fingerprint operation
30
+ for each new-state health/catalog/shell/challenge. These are statement counts,
31
+ not network round trips. Its dry-run bundle was 3,921.40 KiB / 690.43 KiB gzip
32
+ with Wrangler 4.124.0 and compatibility date 2026-07-08. Esbuild attributed
33
+ 1,342,428 emitted bytes to Better Auth, 76,078 to Admin, 24,624 to Web and
34
+ 203,130 to Runtime; the rest includes transitive libraries and adapter code.
35
+ Byte attribution does not measure startup CPU. We retain static imports and
36
+ immutable mount-time projections: deferring those modules has not yet been
37
+ justified by a startup profile. The final #812 report owns the separate startup,
38
+ preparation-wall and warm-dispatch measurements.
39
+
40
+ Post-change full-facade workerd checks pass all 13 operation gates: empty-DB
41
+ health and fresh-state health/catalog/shell perform zero **content** queries;
42
+ the challenge retains its one fingerprint query. The fixture Auth is a stated
43
+ stub. A separate real Better Auth regression records one eager oauthResource
44
+ lookup while `ready` initializes; Better Auth 1.7.2 defers missing-table resource
45
+ seeding to first access. Subsequent static requests perform no additional Auth
46
+ queries. This background initialization is retained, not counted as eliminated
47
+ content preparation or hidden behind a zero-total-SQL claim.
@@ -0,0 +1,71 @@
1
+ # ADR-lite: bounded public content and complete discovery
2
+
3
+ Status: implemented for #809; combined deployment measurements tracked in #812.
4
+ Context: ADR-0010 translation joins, ADR-0019 sealed semantic storage, #792 Web
5
+ transport/cache ownership. No manifest keys or remote Web SDK are introduced.
6
+
7
+ ## Decision
8
+
9
+ Add the semantic `EntryReader.readPublishedPage` operation instead of silently
10
+ capping generic `readPublished`. Forward pages sort by updatedAt and id descending,
11
+ with default 50 / maximum 2,000 rows and a 1-MiB data-JSON budget. A single larger
12
+ entry remains readable and advances the cursor. This budget covers the selected
13
+ canonical data, excluding envelope bytes, joined parents, media and consumer HTML.
14
+ SQLite uses indexed, bounded candidates, a running byte sum and lookahead before
15
+ transfer to Worker memory. Exact locale plus shared entries are merged in SQL.
16
+ Selected data fields retain JSON types and use one bound JSON field list, including
17
+ for projections larger than D1's ordinary bind or SQL-function argument limits.
18
+
19
+ The optional Web use cases return an explicit page object. Cloudflare mounts
20
+ publish `Link: rel="next"` and map cursors to URLs. Web passes `nextPageUrl` to
21
+ the list template; the host renders accessible navigation with its own language
22
+ and design. The adapter does not rewrite template HTML. Existing templates must
23
+ adopt this field to retain visible continuation. Web-owned llms composition
24
+ retains its body link. An empty intermediate/final llms page remains traversable.
25
+ Root llms reads each canonical page once and expands shared entries per locale
26
+ without repeated canonical reads. Unknown/unmapped/no-content rows consume their
27
+ place in the page; they do not prevent reaching later eligible rows.
28
+
29
+ Sitemap parts project path metadata and default to 2,000 entries, expanding shared
30
+ routes per locale. The index walks the same metadata-page boundaries as the parts,
31
+ so a byte-limited part cannot cause skipped URLs. Small sites keep a single urlset.
32
+ Additional routes appear only in the first part. A custom path resolver must declare
33
+ its required data fields to obtain projection; otherwise full bounded data remains
34
+ available. Protocol limits fail explicitly instead of silently truncating URLs.
35
+
36
+ Translation lists request only the newest published parent per join value. Storage
37
+ ranks matching IDs before loading their bodies, preventing duplicate historical
38
+ parents from multiplying transferred rows. Missing/draft parents leave the child
39
+ unchanged. Child data still wins and media resolution remains one batch per page.
40
+
41
+ ## Limits and alternatives
42
+
43
+ Sitemap index generation is O(N) metadata work on an origin MISS. It retains one
44
+ page and the index's URL list rather than all entry bodies; the protocol permits
45
+ at most 50,000 parts. Persisted generation/part boundaries would require an explicit
46
+ publication/invalidation owner and are deferred until index traffic justifies it.
47
+ A hard `LIMIT 500` would lose discovery URLs and is rejected. Offset pages would
48
+ make deep traversal grow with depth and are rejected. Entry caching would leave
49
+ the cold materialization spike and stale-state questions unresolved.
50
+
51
+ Pages reflect live canonical state, not a cross-request snapshot: publishing or
52
+ changing sort keys during a crawl can move entries between pages. Browser-local
53
+ IndexedDB shares the semantic cursor and output budget but still scans a local
54
+ collection. Parent/media data and consumer template expansion have separate costs;
55
+ there is no promise that arbitrary consumer rendering fits 1 MiB.
56
+
57
+ ## Verification
58
+
59
+ Real SQLite tests walk the 18 combinations of 100/10,000/50,000 rows, 64 B/4 KiB
60
+ body and 1/3/10 locales, comparing complete llms/sitemap URL sets. List transfer is
61
+ 21 rows at limit 20 in every case; 50,000 mixed rows and 10 locales retain all
62
+ 275,000 URLs. Tests cover tied sort keys, >1-MiB entries, JSON projection types,
63
+ missing projected keys, parent duplicates/missing/drafts, child overrides, media
64
+ batching and persistence-field privacy. HTTP tests walk visible continuations,
65
+ empty final pages, sitemap indexes and staff-only preview behavior. The portable
66
+ storage conformance suite checks new semantics across adapters.
67
+
68
+ Wrangler-local records native D1 query/row work for list, llms and sitemap alongside
69
+ existing readiness, View, Procedure and Admin gates. Node traversal CPU/RSS includes
70
+ fixture/assertion costs and is not reported as Worker CPU. Combined #812 evidence
71
+ will supply Worker CPU, heap, cache HIT/MISS, remote controls and placement results.