@aotter/mantle 0.1.0-alpha.6 → 0.1.0-alpha.8

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 (106) hide show
  1. package/README.md +68 -30
  2. package/dist/admin.d.ts +2 -0
  3. package/dist/admin.d.ts.map +1 -0
  4. package/dist/admin.js +2 -0
  5. package/dist/admin.js.map +1 -0
  6. package/dist/bun.d.ts +2 -0
  7. package/dist/bun.d.ts.map +1 -0
  8. package/dist/bun.js +2 -0
  9. package/dist/bun.js.map +1 -0
  10. package/dist/cli/create.d.ts +2 -0
  11. package/dist/cli/create.d.ts.map +1 -0
  12. package/dist/cli/create.js +243 -0
  13. package/dist/cli/create.js.map +1 -0
  14. package/dist/cli/generate.d.ts.map +1 -0
  15. package/dist/cli/generate.js +101 -0
  16. package/dist/cli/generate.js.map +1 -0
  17. package/dist/cli/harness.d.ts +3 -0
  18. package/dist/cli/harness.d.ts.map +1 -0
  19. package/dist/{harness-cli.js → cli/harness.js} +13 -8
  20. package/dist/cli/harness.js.map +1 -0
  21. package/dist/cli/main.d.ts +3 -0
  22. package/dist/cli/main.d.ts.map +1 -0
  23. package/dist/{cli.js → cli/main.js} +6 -8
  24. package/dist/cli/main.js.map +1 -0
  25. package/dist/cli/skills.d.ts +3 -0
  26. package/dist/cli/skills.d.ts.map +1 -0
  27. package/dist/{skills.js → cli/skills.js} +51 -6
  28. package/dist/cli/skills.js.map +1 -0
  29. package/dist/cli/update.d.ts.map +1 -0
  30. package/dist/{update.js → cli/update.js} +72 -46
  31. package/dist/cli/update.js.map +1 -0
  32. package/dist/codegen/emitMantleModule.d.ts +16 -0
  33. package/dist/codegen/emitMantleModule.d.ts.map +1 -0
  34. package/dist/codegen/emitMantleModule.js +217 -0
  35. package/dist/codegen/emitMantleModule.js.map +1 -0
  36. package/dist/codegen.d.ts +2 -0
  37. package/dist/codegen.d.ts.map +1 -0
  38. package/dist/codegen.js +2 -0
  39. package/dist/codegen.js.map +1 -0
  40. package/dist/provision/renderProvisionBundle.d.ts +70 -0
  41. package/dist/provision/renderProvisionBundle.d.ts.map +1 -0
  42. package/dist/provision/renderProvisionBundle.js +367 -0
  43. package/dist/provision/renderProvisionBundle.js.map +1 -0
  44. package/dist/provision.d.ts +2 -0
  45. package/dist/provision.d.ts.map +1 -0
  46. package/dist/provision.js +2 -0
  47. package/dist/provision.js.map +1 -0
  48. package/dist/vercel-libsql.d.ts +2 -0
  49. package/dist/vercel-libsql.d.ts.map +1 -0
  50. package/dist/vercel-libsql.js +2 -0
  51. package/dist/vercel-libsql.js.map +1 -0
  52. package/dist/vercel.d.ts +2 -0
  53. package/dist/vercel.d.ts.map +1 -0
  54. package/dist/vercel.js +2 -0
  55. package/dist/vercel.js.map +1 -0
  56. package/dist/web.d.ts +2 -0
  57. package/dist/web.d.ts.map +1 -0
  58. package/dist/web.js +2 -0
  59. package/dist/web.js.map +1 -0
  60. package/docs/adapter-guide.md +88 -45
  61. package/docs/adr/0001-four-atom-manifest-model.md +11 -3
  62. package/docs/adr/0007-ai-as-primary-author.md +3 -3
  63. package/docs/adr/0009-consumer-supplied-manifests.md +9 -4
  64. package/docs/adr/0011-adapter-port-spec.md +18 -4
  65. package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +111 -6
  66. package/docs/adr/0018-core-starters-repository-boundary.md +22 -1
  67. package/docs/adr/0019-sealed-manifest-runtime-pipeline.md +204 -0
  68. package/docs/adr/README.md +12 -10
  69. package/docs/api-mcp-authorization.md +21 -42
  70. package/docs/assets/mantle-admin-operations.png +0 -0
  71. package/docs/assets/mantle-hero.jpg +0 -0
  72. package/docs/auth-hosting-model.md +5 -5
  73. package/docs/cloudflare-low-level-composition.md +30 -18
  74. package/docs/deferred-lifecycle-queues.md +20 -38
  75. package/docs/design-atoms.md +31 -133
  76. package/docs/labels.md +1 -1
  77. package/docs/media-uploads.md +9 -2
  78. package/docs/migration-0.1.2.md +45 -0
  79. package/docs/performance-harness.md +4 -4
  80. package/docs/release-process.md +72 -22
  81. package/docs/sealed-pipeline-ownership.md +100 -0
  82. package/package.json +84 -14
  83. package/skills/README.md +39 -7
  84. package/skills/develop/SKILL.md +7 -5
  85. package/skills/install/SKILL.md +26 -25
  86. package/skills/media-gc/SKILL.md +85 -0
  87. package/skills/plugin/SKILL.md +1 -0
  88. package/skills/provision/SKILL.md +2 -0
  89. package/skills/theme/SKILL.md +1 -0
  90. package/skills/update/SKILL.md +1 -0
  91. package/dist/cli.d.ts +0 -3
  92. package/dist/cli.d.ts.map +0 -1
  93. package/dist/cli.js.map +0 -1
  94. package/dist/generate.d.ts.map +0 -1
  95. package/dist/generate.js +0 -226
  96. package/dist/generate.js.map +0 -1
  97. package/dist/harness-cli.d.ts +0 -3
  98. package/dist/harness-cli.d.ts.map +0 -1
  99. package/dist/harness-cli.js.map +0 -1
  100. package/dist/skills.d.ts +0 -2
  101. package/dist/skills.d.ts.map +0 -1
  102. package/dist/skills.js.map +0 -1
  103. package/dist/update.d.ts.map +0 -1
  104. package/dist/update.js.map +0 -1
  105. /package/dist/{generate.d.ts → cli/generate.d.ts} +0 -0
  106. /package/dist/{update.d.ts → cli/update.d.ts} +0 -0
@@ -2,20 +2,24 @@
2
2
 
3
3
  This guide is the fresh-developer entry point for implementing a new mantle platform adapter.
4
4
 
5
- Read this with [ADR-0011](adr/0011-adapter-port-spec.md). The source of truth for TypeScript shapes is `packages/mantle-runtime/src/domain/port/`.
5
+ Read this with [ADR-0019](adr/0019-sealed-manifest-runtime-pipeline.md). The source of truth for TypeScript shapes is `packages/mantle-runtime/src/domain/port/`.
6
6
 
7
7
  Adapter packages live under `packages/adapters/<platform>/` using a plural `adapters` bucket. The npm package names stay unchanged, for example `@aotter/mantle-cloudflare`. Keep adapters in this monorepo until the runtime/spec API is stable enough that coordinated releases across separate repositories would not create version skew for starters.
8
8
 
9
- ## Required runtime ports
9
+ ## Required storage boundary
10
10
 
11
- A first-run adapter must implement exactly these two runtime ports:
11
+ A storage adapter prepares one `RuntimePlan` into semantic ports:
12
12
 
13
13
  | Contract | Source | Cloudflare example |
14
14
  |---|---|---|
15
- | `DatabaseDriver` plus `PreparedStatement` and `MigrationRunner` | `packages/mantle-runtime/src/domain/port/DatabaseDriver.ts` | `packages/adapters/cloudflare/src/bindings/D1DatabaseDriver.ts` |
16
- | `AssetServer` | `packages/mantle-runtime/src/domain/port/AssetServer.ts` | `packages/adapters/cloudflare/src/bindings/AssetsAssetServer.ts` |
15
+ | `MantleStorageAdapter` / `PreparedMantleStorage` | `packages/mantle-runtime/src/domain/port/MantleStorageAdapter.ts` | `SqliteMantleStorageAdapter` over `D1DatabaseDriver` |
16
+ | `EntryRepository & EntryReader` | Existing semantic content ports | `DatabaseEntryRepository` supplied by the SQLite adapter |
17
+ | `ViewQueryExecutor` | `packages/mantle-runtime/src/domain/port/ViewQueryExecutor.ts` | `SqliteViewQueryExecutor` |
17
18
 
18
- The runtime must not import platform types such as `D1Database`, `KVNamespace`, Cloudflare `Fetcher`, Postgres pools, or adapter SDK types. Those live in adapter packages.
19
+ `DatabaseDriver` is only the reusable SQLite/D1 implementation seam. A
20
+ PostgreSQL, MongoDB, or application-owned-table adapter implements the semantic
21
+ ports directly; it does not emulate D1 and needs no mapping DSL. Platform types
22
+ such as `D1Database`, Postgres pools, and Mongo clients remain in adapter code.
19
23
 
20
24
  ## Optional capabilities
21
25
 
@@ -26,7 +30,7 @@ Optional ports are enabled only when a feature needs them:
26
30
  | `MediaStorage` | `packages/mantle-runtime/src/domain/port/MediaStorage.ts` | The adapter exposes admin/MCP media upload flows. |
27
31
  | `DeferredHookDispatcher` | `packages/mantle-runtime/src/domain/port/DeferredHookDispatcher.ts` | The adapter wants at-least-once queue delivery for `after_*` lifecycle hooks. |
28
32
 
29
- Test seams such as `Clock` and `IdGenerator` are injectable through `createCmsRuntime`, but normal adapters do not need custom implementations.
33
+ Test seams such as `Clock` and `IdGenerator` are injectable through `createMantleRuntime`, but normal adapters do not need custom implementations.
30
34
 
31
35
  Deferred delivery is an optional, versioned wire contract. Queue acceptance is
32
36
  not atomic with the entry write; adapters must preserve the supplied event id,
@@ -35,37 +39,72 @@ to their retry mechanism, and document poison-message/DLQ behavior. See
35
39
  [Deferred lifecycle hooks on Cloudflare Queues](deferred-lifecycle-queues.md)
36
40
  for the reference implementation and exact guarantees.
37
41
 
38
- ## Runtime boot
42
+ ## Storage preparation
39
43
 
40
- Adapters compose the runtime through `createCmsRuntime`:
44
+ Compile before deployment preparation, then pass only the sealed plan:
41
45
 
42
46
  ```ts
43
- import { createCmsRuntime } from "@aotter/mantle-runtime";
44
-
45
- const runtime = createCmsRuntime({
46
- manifests,
47
+ import {
48
+ bootMantleRuntime,
49
+ SqliteMantleStorageAdapter,
50
+ } from "@aotter/mantle-runtime";
51
+
52
+ const storage = new SqliteMantleStorageAdapter(db, siteDefaults);
53
+ const runtime = await bootMantleRuntime({
54
+ plan,
55
+ storage,
47
56
  handlers,
48
- templates,
49
- siteDefaults,
50
- db,
51
- assets,
52
- publicPathResolver,
53
- mediaStorage,
54
- deferredHookDispatcher,
57
+ ports,
58
+ deployment: {
59
+ reservedHttpPathPrefixes: selectedCapabilities.flatMap(
60
+ (capability) => capability.reservedHttpPathPrefixes,
61
+ ),
62
+ },
55
63
  });
64
+ ```
65
+
66
+ `bootMantleRuntime` performs one attempt and derives Procedure readiness from
67
+ the supplied handlers. The platform adapter remains responsible for lazy boot,
68
+ promise caching, retry policy, and teardown.
56
69
 
57
- await runtime.bootInit();
70
+ Hosts that need work between preparation and binding may keep the same stages
71
+ public and explicit:
72
+
73
+ ```ts
74
+ const prepared = await prepareDeployment(plan, storage, {
75
+ handlerNames: Object.keys(handlers ?? {}),
76
+ });
77
+ const runtime = createMantleRuntime({ prepared, handlers, ports });
58
78
  ```
59
79
 
60
- `bootInit()` runs canonical migrations, seeds `siteDefaults`, and validates the manifest set. Call it once before serving CMS traffic. The Cloudflare adapter's reference pattern is `packages/adapters/cloudflare/src/mount/bootRuntimeOnce.ts`.
80
+ The prepared revision carries its exact plan, but exposes both `plan` and
81
+ `storage`; it seals the pairing invariant rather than hiding low-level host
82
+ capabilities. Omit `handlerNames` only for a read-only embedding that never
83
+ dispatches Procedures.
61
84
 
62
- Use purpose-shaped runtime surfaces for canonical data: `runtime.entryReader`
63
- applies Schema index declarations, locale semantics, and the public `Entry`
64
- projection; `runtime.siteConfig` owns site settings. `runtime.db` remains only
65
- for source compatibility and is deprecated. An adapter that owns additional
66
- tables should retain the `DatabaseDriver` it injected instead of reaching back
67
- through the assembled runtime. Authoring continues through the pre-wired
68
- content use cases.
85
+ The official SQLite adapter runs canonical migrations, defaults, indexes, and
86
+ schema-View reconciliation, and skips mutation for an unchanged revision. A
87
+ custom adapter owns its own preparation and returns application-owned semantic
88
+ ports. Unsupported native View dialects fail before the adapter mutates state.
89
+
90
+ ### Bun embedding
91
+
92
+ `@aotter/mantle-bun` is the minimal SQLite reference: pass an application-owned
93
+ `bun:sqlite` `Database` and a compiled `RuntimePlan` to `createBunMantle()`.
94
+ Its `handle()` returns `null` for sibling routes and a Web-standard `Response`
95
+ for manifest-declared public Views and HTTP Triggers. The host owns
96
+ `Bun.serve`, database shutdown, authentication, and CSRF policy; the adapter
97
+ prepares the semantic revision once and retries only after failed preparation.
98
+
99
+ ### Vercel Functions embedding
100
+
101
+ `@aotter/mantle-vercel` accepts a compiled plan plus any application-owned
102
+ `MantleStorageAdapter` and reuses the same public View/HTTP Trigger transport as
103
+ Bun. It maps deferred work to Vercel Functions `waitUntil` and otherwise leaves
104
+ the Web Handler, auth/CSRF, and route composition to the application. The
105
+ optional `/libsql` subpath adapts a caller-owned remote Turso/libSQL client to
106
+ the canonical SQLite chain; the default entry has no database-vendor policy.
107
+ Vercel's read-only filesystem and writable `/tmp` are never durable state.
69
108
 
70
109
  ## HTTP and MCP surfaces
71
110
 
@@ -73,9 +112,10 @@ The runtime is a library, not an HTTP server. A new adapter must mount equivalen
73
112
 
74
113
  | Surface | Adapter responsibility | Cloudflare reference |
75
114
  |---|---|---|
76
- | Public/admin HTTP endpoints | Route HTTP Triggers, View REST endpoints, admin SPA assets, and public render routes into runtime use cases. | `packages/adapters/cloudflare/src/mount/mountServerEndpoints.ts`, `mountPublicRoutes.ts` |
77
- | Auth endpoints | Own sign-in/session/OAuth metadata routes through the adapter's Better Auth integration. | `packages/adapters/cloudflare/src/auth/createAuth.ts`, `mountServerEndpoints.ts` |
78
- | MCP endpoints | Mount `/mcp/staff` and `/mcp` via `createOAuthProvider({ apiHandlers })`; the OAuth lib verifies bearer tokens against its KV grant store, then calls the matching apiHandler with `ctx.props` set. The adapter enforces the staff D1 role inside the apiHandler, then dispatches JSON-RPC. | `packages/adapters/cloudflare/src/mount/mountMcp.ts`, `oauth/oauthSingleton.ts`, `oauth/mountOAuth.ts` |
115
+ | Runtime HTTP endpoints | Route HTTP Triggers and public View REST endpoints into runtime use cases. | `packages/adapters/cloudflare/src/mount/mountRuntimeEndpoints.ts` |
116
+ | Optional Admin | Supply session/request context and assets to `mantle-admin`; mount only when selected. | `packages/adapters/cloudflare/src/mount/mountAdmin.ts` |
117
+ | Auth endpoints | Own sign-in/session/OAuth metadata through the adapter's Better Auth implementation selected by Admin/OAuth surfaces. | `packages/adapters/cloudflare/src/auth/createAuth.ts` |
118
+ | MCP endpoints | Mount `/mcp/staff` and `/mcp` behind one canonical protected resource. The adapter verifies Better Auth JWTs, normalizes the caller, re-reads the staff D1 role, then dispatches JSON-RPC. | `packages/adapters/cloudflare/src/mount/mountMcp.ts`, `auth/createAuth.ts` |
79
119
 
80
120
  Auth is not a runtime port. Per [ADR-0014](adr/0014-auth-better-auth-and-multi-tenant-mcp.md), the adapter owns Better Auth wiring and passes authenticated user/staff context into runtime dispatchers. Procedure handlers receive that data through `HandlerContext` in `packages/mantle-runtime/src/domain/model/HandlerContext.ts`.
81
121
 
@@ -93,7 +133,7 @@ Minimum HTTP behavior for a full adapter:
93
133
  - Route manifest HTTP Triggers to `runtime.invokeProcedure`.
94
134
  - Route `GET /api/views/<name>` to `runtime.executeView`.
95
135
  - Mount admin content APIs with session/role checks before calling runtime content use cases.
96
- - Serve admin SPA assets through `AssetServer`, with an SPA catchall for admin client-side routes.
136
+ - Serve selected Admin SPA assets through `AdminAssetServer`, with an SPA catchall for client-side routes.
97
137
  - Mount public render routes and markdown mirrors when the starter exposes public pages.
98
138
  - Translate runtime diagnostics and validation failures into stable HTTP JSON responses instead of throwing raw errors.
99
139
  - Evaluate target auth and dynamic guards through the runtime use cases; do
@@ -101,16 +141,20 @@ Minimum HTTP behavior for a full adapter:
101
141
 
102
142
  For the Cloudflare adapter, public rendering requires three matching consumer
103
143
  inputs: `mountPublicRoutes(...)` route declarations, a `TemplateRegistry`
104
- passed through `CmsConfig.templates`, and a `publicPathResolver` passed through
105
- `CmsConfig.publicPathResolver`. Omitting public routes is valid for a headless
144
+ passed through `MantleCloudflareConfig.templates`, and a `publicPathResolver`
145
+ passed through `MantleCloudflareConfig.publicPathResolver`. Omitting public routes is valid for a headless
106
146
  consumer; mounting every Schema automatically is not, because some collections
107
147
  are private even when they contain a slug.
108
148
 
149
+ `TemplateRegistry` and `createPublicPathResolver` come from
150
+ `@aotter/mantle-web`. Other adapters can call `createMantleWeb(runtime)` and map
151
+ its document operations into their own routing and cache conventions.
152
+
109
153
  ### HTTP cache contract
110
154
 
111
- The Cloudflare adapter is private by default. Consumers must export
112
- `createOAuthProvider(...)` as the Worker's top-level handler so its final
113
- response policy covers admin, auth, API, OAuth, MCP, redirects, and errors.
155
+ The Cloudflare adapter is private by default. Consumers must apply its final
156
+ cache policy after admin, auth, API, OAuth, MCP, application routes, redirects,
157
+ and errors.
114
158
  Those responses receive `Cache-Control: private, no-store`; Cloudflare-specific
115
159
  CDN cache overrides are removed.
116
160
 
@@ -146,20 +190,19 @@ Minimum auth/MCP behavior:
146
190
 
147
191
  ## Static assets
148
192
 
149
- `AssetServer` is required because every adapter must have a strategy for serving the prebuilt admin UI from `@aotter/mantle-admin-ui`. The adapter may serve those files from platform assets, a static publish directory, object storage plus CDN, or a filesystem bundle. Return `null` from `AssetServer.fetch()` when a specific asset is not found so the adapter can fall back to the admin SPA catchall.
193
+ `AdminAssetServer` belongs to optional `@aotter/mantle-admin`. Headless Core
194
+ storage preparation and binding do not accept or require a static asset port.
150
195
 
151
196
  ## Implementation checklist
152
197
 
153
- - [ ] Implement `DatabaseDriver`, including canonical migration tracking.
154
- - [ ] Implement `AssetServer` for the admin UI assets.
155
- - [ ] Compose `createCmsRuntime` with manifests, handlers, templates, site defaults, and required ports.
156
- - [ ] Call `bootInit()` before serving CMS traffic.
198
+ - [ ] Implement `MantleStorageAdapter` returning existing semantic ports, or reuse `SqliteMantleStorageAdapter` with an already-owned handle.
199
+ - [ ] Call `bootMantleRuntime()` once per semantic revision, or explicitly prepare before binding.
157
200
  - [ ] Mount HTTP Trigger and View REST surfaces.
158
201
  - [ ] Mount admin/public render routes and admin SPA assets.
159
202
  - [ ] Provide adapter-owned Better Auth wiring and session helpers.
160
203
  - [ ] Normalize session/OAuth and any consumer credential seam into
161
204
  `HandlerContext.auth`; never put raw credentials in runtime context.
162
- - [ ] Mount `/mcp/staff` and `/mcp` via the platform's OAuth provider lib (Cloudflare adapter uses `@cloudflare/workers-oauth-provider` at top level). Enforce staff D1 role inside the apiHandler.
205
+ - [ ] Mount `/mcp/staff` and `/mcp` behind one resource-bound token verifier. Enforce the live staff role inside the apiHandler.
163
206
  - [ ] Preserve the HTTP cache contract: private by default; explicit anonymous 200 `GET`/`HEAD` public opt-in only.
164
207
  - [ ] Prove one guarded target has identical REST/MCP outcomes, including
165
208
  mutable revocation on the next call.
@@ -174,4 +217,4 @@ Minimum auth/MCP behavior:
174
217
  - Do not add API-key, personal-token, transaction, billing, or entitlement
175
218
  repositories to Core. They are consumer state behind the adapter resolver
176
219
  and guard Procedure.
177
- - Do not add a second canonical migration chain for a new adapter. The runtime owns canonical migrations; adapters execute them through `DatabaseDriver.migrations`.
220
+ - Do not generalize `DatabaseDriver` for PostgreSQL/MongoDB or add a mapping DSL. Implement semantic ports; SQLite/D1 alone reuse the canonical SQL chain.
@@ -1,12 +1,20 @@
1
1
  # ADR-0001: 4-atom YAML manifest model under `cms.mantle.aotter.net/v1`
2
2
 
3
- **Status:** Carried over from POC v0.0.x; refreshed and folded for v0.1.0 (incorporates POC ADRs 0005 + 0006).
3
+ **Status:** Accepted for the four-atom grammar and multi-document YAML;
4
+ the fixed `site.yaml` file contract is superseded by ADR-0019.
4
5
 
5
- **Date**: 2026-04-30 (POC origin), refreshed 2026-05-03 for v0.1.0 rebuild
6
+ **Date**: 2026-04-30 (POC origin); last amended 2026-08-16
6
7
 
7
8
  **Deciders**: phsu
8
9
 
9
- **Related**: ADR-0002 (closed enums for bindings)
10
+ **Related**: ADR-0002 (closed enums for bindings),
11
+ [ADR-0019](0019-sealed-manifest-runtime-pipeline.md) (caller-owned source boundary)
12
+
13
+ > **2026-08-16 amendment:** the four atoms and multi-document YAML remain
14
+ > normative. Core no longer assigns source file names: its parser accepts
15
+ > caller-owned source IDs, and its CLI reads immediate `.yaml` / `.yml` files
16
+ > in lexicographic order. `manifests/site.yaml` remains only a starter
17
+ > convention. Fixed-file statements below are retained as decision history.
10
18
 
11
19
  ---
12
20
 
@@ -252,9 +252,9 @@ Concrete artifacts today:
252
252
  - Version-matched Core skills ship inside `@aotter/mantle`, through the Mantle
253
253
  agent plugin, and through exact-byte repo-local projections written by
254
254
  `mantle skills`.
255
- - The umbrella `mantle` CLI exposes `validate`, `generate`, `skills`, `update`,
256
- `introspect`, `emit-openapi`, and `emit-types`; direct spec installs expose
257
- the authoring subset through `mantle-spec`.
255
+ - The umbrella `mantle` CLI exposes `create`, `generate`, `validate`,
256
+ `emit-openapi`, `update`, and `skills`; direct spec installs expose advanced
257
+ `introspect` and `emit-types` primitives through `mantle-spec`.
258
258
  - `@aotter/mantle/runtime/testing` and `mantle-harness` expose the measured
259
259
  SQLite/index and live-HTTP checks described in Loop 2.
260
260
 
@@ -1,13 +1,18 @@
1
1
  # ADR-0009: Consumer-supplied manifests at SDK boot
2
2
 
3
- **Status:** Carried over from POC v0.0.x; amended for the parser-free v0.1
4
- consumer boundary.
3
+ **Status:** Superseded by ADR-0019.
5
4
 
6
- **Date:** 2026-05-01 (POC); last amended 2026-08-03
5
+ **Date:** 2026-05-01 (POC); superseded 2026-08-16
7
6
 
8
7
  **Related:** [ADR-0001](0001-four-atom-manifest-model.md),
9
8
  [ADR-0007](0007-ai-as-primary-author.md),
10
- [ADR-0018](0018-core-starters-repository-boundary.md)
9
+ [ADR-0018](0018-core-starters-repository-boundary.md),
10
+ [ADR-0019](0019-sealed-manifest-runtime-pipeline.md)
11
+
12
+ > **Supersession note:** consumer ownership remains durable, but the exact
13
+ > `site.yaml`, generated `site.ts`, and parser-free array workflow below is
14
+ > historical. The sealed source → parse → link → compile pipeline in ADR-0019
15
+ > is current; source names and generated code are optional caller concerns.
11
16
 
12
17
  ## Context
13
18
 
@@ -1,14 +1,17 @@
1
1
  # ADR-0011: Adapter port spec
2
2
 
3
- **Status:** Accepted for v0.1.0. Amended 2026-08-13 to remove the unimplemented adapter stub.
3
+ **Status:** Superseded for Core storage and Admin composition by ADR-0019.
4
+ Retained as the alpha.7 Cloudflare adapter record; `DatabaseDriver` is now an
5
+ implementation detail of the SQLite/D1 `MantleStorageAdapter`, while the asset
6
+ contract belongs to optional `@aotter/mantle-admin`.
4
7
 
5
- **Date:** 2026-05-04 (revised 2026-05-09, 2026-05-10, 2026-08-11, and 2026-08-13).
8
+ **Date:** 2026-05-04 (revised 2026-05-09, 2026-05-10, 2026-08-11, 2026-08-13, and 2026-08-22).
6
9
 
7
10
  ## Context
8
11
 
9
12
  `@aotter/mantle-runtime` is adapter-agnostic. It owns dispatcher, entry-writer, view executor, content-ops, render pipeline, boot validation, and MCP JSON-RPC dispatch. It depends only on `@aotter/mantle-spec` and a small set of TypeScript interfaces it defines itself.
10
13
 
11
- `@aotter/mantle-cloudflare` is the only adapter shipping in v0.1.0. It binds the runtime's interfaces against Cloudflare Workers' D1 and ASSETS, and supplies a Better Auth instance (per ADR-0014) for sign-in + MCP bearer validation. OAuth grant KV remains adapter-owned infrastructure and is not a runtime port.
14
+ `@aotter/mantle-cloudflare` is the only adapter shipping in v0.1.0. It binds the runtime's interfaces against Cloudflare Workers' D1 and ASSETS, and supplies a Better Auth instance (per ADR-0014) for sign-in and MCP authorization. Better Auth 1.7 stores OAuth grants in D1; auth storage remains adapter-owned infrastructure, not a runtime port.
12
15
 
13
16
  This ADR fixes the contract so:
14
17
  - Future adapter authors have a stable target.
@@ -19,7 +22,14 @@ The POC accumulated multiple half-decisions about this seam (POC ADR-0015 docume
19
22
 
20
23
  ## Decision
21
24
 
22
- **Two required adapter ports**, defined as TypeScript interfaces in `@aotter/mantle-runtime/src/domain/port/`. Concrete adapters provide implementations and inject them into `createCmsRuntime`.
25
+ > 0.1.2 amendment: the portable storage input is
26
+ > `PreparedMantleStorage` (`EntryRepository & EntryReader` plus
27
+ > `ViewQueryExecutor`). Hosts either use an official storage adapter with an
28
+ > already-owned client/handle or implement those semantic ports over their own
29
+ > tables. `AssetServer` moved out of Runtime to optional Mantle Admin. The
30
+ > two-port contract below is the historical alpha.7 shape.
31
+
32
+ Alpha.7 had **two required adapter ports**, defined as TypeScript interfaces in `@aotter/mantle-runtime/src/domain/port/`. Concrete adapters provided implementations and injected them into `createCmsRuntime`.
23
33
 
24
34
  | Port | Surface |
25
35
  |---|---|
@@ -140,6 +150,10 @@ The admin SPA itself lives in `@aotter/mantle-admin-ui` as a pre-built `dist/`.
140
150
 
141
151
  ## How adapters wire ports
142
152
 
153
+ > Historical alpha.7 example. Current convenience composition is
154
+ > `createMantleWorker`; ADR-0014's 2026-08-22 amendment replaces the OAuth
155
+ > provider shown below with Better Auth 1.7 MCP/CIMD.
156
+
143
157
  ```ts
144
158
  // simplified Cloudflare adapter wiring (post-ADR-0014, amended
145
159
  // 2026-05-15 by PR #193's OAuth carve-out).
@@ -2,17 +2,18 @@
2
2
 
3
3
  ## Status
4
4
 
5
- Accepted. Amended 2026-05-14, 2026-05-15, 2026-06-30, 2026-07-15, and
6
- 2026-08-03.
5
+ Accepted. Amended 2026-05-14, 2026-05-15, 2026-06-30, 2026-07-15,
6
+ 2026-08-03, and 2026-08-22.
7
7
 
8
8
  ## Date
9
9
 
10
- 2026-05-09 (last amended 2026-08-03)
10
+ 2026-05-09 (last amended 2026-08-22)
11
11
 
12
12
  > **Current authority:** the original decision below records the rejected
13
- > Better-Auth-for-MCP design. The 2026-05-15 carve-out and 2026-07-15 unified
14
- > authorization amendment are authoritative where they conflict. Operational
15
- > guidance in "How to apply" is maintained against the current adapter/runtime.
13
+ > Better-Auth-for-MCP design. The 2026-08-22 Better Auth 1.7 amendment is
14
+ > authoritative where it conflicts with the 2026-05-15 carve-out; the
15
+ > 2026-07-15 normalized authorization boundary still applies. Operational
16
+ > guidance is maintained against the current adapter/runtime.
16
17
 
17
18
  ## Context
18
19
 
@@ -520,3 +521,107 @@ Dynamic membership, billing, and entitlement state remains consumer-owned.
520
521
  does not introduce a Policy atom or an entitlement service. See
521
522
  [`API and MCP authorization`](../api-mcp-authorization.md) for the public API
522
523
  and end-to-end examples.
524
+
525
+ ## Amendment — 2026-08-22: Better Auth 1.7 MCP and CIMD convergence
526
+
527
+ Issue #734 revisits the 2026-05-15 compatibility carve-out after Better Auth
528
+ 1.7 shipped a dedicated `@better-auth/mcp` package, resource-bound JWT grants,
529
+ and the MCP 2026-07-28 Client ID Metadata Document profile. These are the
530
+ missing capabilities that originally forced Mantle to keep a second OAuth
531
+ authority.
532
+
533
+ The Cloudflare adapter now uses one Better Auth instance for staff identity,
534
+ OAuth authorization, consent, client registration/discovery, token issuance,
535
+ and MCP resource verification. `@cloudflare/workers-oauth-provider` and Core's
536
+ `OAUTH_KV` requirement are removed. This amendment supersedes only the
537
+ 2026-05-15 transport carve-out; adapter ownership, the curated `Auth` facade,
538
+ fresh D1 staff-role checks, the single `mcp` compatibility scope, and normalized
539
+ `HandlerContext.auth` remain unchanged.
540
+
541
+ ### Provider and resource boundary
542
+
543
+ `createAuth` keeps its general OAuth-provider capability and adds MCP as an
544
+ explicit curated mode, implemented by composing `jwt()` and
545
+ `@better-auth/mcp`. It is not replaced by an MCP-only factory and no Better
546
+ Auth passthrough is exposed. Standard Workers bind one canonical protected
547
+ resource, `${PUBLIC_ORIGIN}/mcp`. Both `/mcp` and `/mcp/staff` accept tokens for
548
+ that resource; `/mcp/staff` remains a stricter server-side role projection, not
549
+ a second OAuth audience.
550
+
551
+ The adapter continues to verify and normalize credentials before calling the
552
+ portable runtime. Better Auth imports remain confined to the default
553
+ implementation. A host app may still implement the `Auth` facade or mount its
554
+ own low-level routes; the generated convenience path does not make Better Auth
555
+ a runtime dependency.
556
+
557
+ MCP request verification reuses Better Auth's DPoP binding primitive and its
558
+ database-backed replay store. Bearer JWTs remain valid; a DPoP-bound JWT is
559
+ accepted only with a matching request proof, method, URL, token hash, and
560
+ single-use proof id. Raw-token callers cannot bypass that request boundary.
561
+
562
+ ### CIMD is primary; DCR is bounded compatibility
563
+
564
+ The MCP mode composes:
565
+
566
+ ```ts
567
+ mcp({ resource, loginPage, consentPage, scopes: ["mcp"], ... })
568
+ cimd({
569
+ fetchClientMetadataResource,
570
+ metadataProfile: "mcp-2026-07-28",
571
+ })
572
+ ```
573
+
574
+ Cloudflare's native `fetch` is the metadata transport only when the Worker has
575
+ `global_fetch_strictly_public` enabled. The runtime flag makes the subrequest
576
+ use Cloudflare's public-Internet routing boundary; Better Auth owns URL
577
+ validation, timeout, response limits, redirect refusal, revalidation, and the
578
+ bounded fetch governor. Mantle does not add a DNS resolver, socket HTTP client,
579
+ or generic transport abstraction.
580
+
581
+ Unauthenticated DCR remains enabled only for older MCP clients. Its lifetime
582
+ stays at the removed provider's 90-day default. Better Auth expires confidential
583
+ registration secrets; Mantle additionally prunes only expired ownerless DCR
584
+ rows (`clientDiscoveryId`, user owner, and reference owner all absent) on
585
+ OAuth traffic. CIMD-owned and operator-managed clients are never cleanup
586
+ candidates. Cleanup is storage hygiene: failures are logged and do not turn a
587
+ valid authorization request into an outage. No cron or second registry is
588
+ introduced.
589
+
590
+ Better Auth's `oauthClient` row is the connected-client authority. It retains
591
+ the discovery provenance and validated name, URI, redirect URIs, application
592
+ type, and private server metadata. The consent UI reads only the public
593
+ secret-free projection. Remote client metadata is not copied into portable
594
+ `HandlerContext` or deferred event envelopes.
595
+
596
+ ### Breaking migration
597
+
598
+ All Better Auth packages upgrade together to 1.7. The D1 schema adopts account
599
+ issuer identity, resource/client relationships, resource-bound token and
600
+ consent fields, discovery provenance, and replay storage required by the
601
+ installed plugins. Removed `validAudiences` configuration becomes the one
602
+ explicit MCP resource; generic upstream OAuth adopts the 1.7 social sign-in and
603
+ callback contract.
604
+
605
+ This is an alpha breaking migration. KV registrations, grants, and opaque
606
+ tokens are not migrated into D1 because their issuer/resource provenance cannot
607
+ be established safely; MCP clients reconnect through CIMD or DCR. Existing
608
+ pre-1.7 alpha auth databases are reset and re-bootstrapped rather than receiving
609
+ a guessed account issuer backfill.
610
+
611
+ The authorization endpoints consequently move from `/oauth/*` to Better
612
+ Auth's `/api/auth/oauth2/*` discovery-advertised endpoints. No compatibility
613
+ aliases are retained: existing KV client identifiers are invalid after the
614
+ authority change regardless, and standards-compliant clients rediscover the
615
+ new endpoints.
616
+
617
+ ### Downstream ownership
618
+
619
+ Starters remove their obsolete OAuth package and `OAUTH_KV` binding while
620
+ retaining `global_fetch_strictly_public`. Landing opts its custom `createAuth`
621
+ construction into the same MCP mode. Landing may keep an `OAUTH_KV` binding for
622
+ its own launch/bootstrap state; that storage is unrelated to the removed Core
623
+ OAuth store and is not renamed by this decision.
624
+
625
+ This amendment adopts the 2026-07-28 CIMD authorization profile only. Updating
626
+ Mantle's JSON-RPC dispatcher to the complete MCP 2026-07-28 transport revision
627
+ is a separate decision.
@@ -19,9 +19,30 @@ Core (SDK producer)
19
19
  -> published npm contract
20
20
  mantle-starters (external consumer and bundle producer)
21
21
  -> immutable provision bundle
22
- mantle-landing (provisioner)
22
+ mantle-landing (provisioner) Core CLI (`mantle create`)
23
23
  ```
24
24
 
25
+ > **Amended 2026-08-19 (#699).** The chain above is no longer linear. Core's
26
+ > umbrella CLI is now also a consumer of the immutable bundle: `mantle create`
27
+ > resolves the official `v${packageVersion}` starter tag, renders it through
28
+ > the environment-neutral module Core owns, and writes a local project. Core
29
+ > is therefore both the upstream producer of the npm contract and a downstream
30
+ > consumer of the release train it starts.
31
+ >
32
+ > This does not move starter content into Core, so the decision below stands:
33
+ > starters still author the bundles and still validate the published SDK as an
34
+ > external consumer. What changed is the supporting argument. Two consequences
35
+ > are worth stating rather than rediscovering:
36
+ >
37
+ > - **The published-consumer guarantee is now proven twice.** `mantle create`
38
+ > materializes a project that installs the published package, so a break in
39
+ > the npm contract fails in Core's own release smoke as well as in starter CI.
40
+ > - **Reconsideration input 1 is being answered.** #699 replaces the release
41
+ > order so a candidate is published under a temporary dist-tag, validated
42
+ > against the exact packed artifacts, and only then promoted. That was listed
43
+ > below as an unresolved prerequisite for any future merge; when it lands,
44
+ > this ADR should record it as resolved rather than pending.
45
+
25
46
  The repositories were originally split because premium starters needed a
26
47
  private ACL. That reason does not determine where public starters must live,
27
48
  and the private premium repository remains a stub. A later decision, #191,