@aotter/mantle 0.0.11-alpha.73 → 0.1.0-alpha.10

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 (111) hide show
  1. package/README.md +107 -28
  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 +95 -51
  61. package/docs/adr/0001-four-atom-manifest-model.md +48 -307
  62. package/docs/adr/0002-closed-enums-for-bindings.md +6 -15
  63. package/docs/adr/0007-ai-as-primary-author.md +6 -4
  64. package/docs/adr/0008-structured-diagnostic-shape.md +2 -2
  65. package/docs/adr/0009-consumer-supplied-manifests.md +15 -9
  66. package/docs/adr/0010-locale-and-translates.md +13 -8
  67. package/docs/adr/0011-adapter-port-spec.md +39 -43
  68. package/docs/adr/0012-views-as-public-rest.md +6 -10
  69. package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +124 -43
  70. package/docs/adr/0018-core-starters-repository-boundary.md +22 -1
  71. package/docs/adr/0019-sealed-manifest-runtime-pipeline.md +204 -0
  72. package/docs/adr/README.md +16 -14
  73. package/docs/api-mcp-authorization.md +78 -44
  74. package/docs/assets/mantle-admin-operations.png +0 -0
  75. package/docs/assets/mantle-hero.jpg +0 -0
  76. package/docs/auth-hosting-model.md +15 -11
  77. package/docs/cloudflare-low-level-composition.md +30 -18
  78. package/docs/deferred-lifecycle-queues.md +20 -41
  79. package/docs/design-atoms.md +159 -400
  80. package/docs/labels.md +5 -3
  81. package/docs/media-uploads.md +9 -2
  82. package/docs/migration-0.1.2.md +45 -0
  83. package/docs/performance-harness.md +23 -23
  84. package/docs/release-process.md +91 -28
  85. package/docs/schema-indexes.md +1 -1
  86. package/docs/sealed-pipeline-ownership.md +100 -0
  87. package/package.json +85 -15
  88. package/skills/README.md +39 -7
  89. package/skills/develop/SKILL.md +33 -19
  90. package/skills/install/SKILL.md +26 -25
  91. package/skills/media-gc/SKILL.md +85 -0
  92. package/skills/plugin/SKILL.md +2 -1
  93. package/skills/provision/SKILL.md +24 -2
  94. package/skills/theme/SKILL.md +11 -1
  95. package/skills/update/SKILL.md +1 -0
  96. package/dist/cli.d.ts +0 -3
  97. package/dist/cli.d.ts.map +0 -1
  98. package/dist/cli.js.map +0 -1
  99. package/dist/generate.d.ts.map +0 -1
  100. package/dist/generate.js +0 -181
  101. package/dist/generate.js.map +0 -1
  102. package/dist/harness-cli.d.ts +0 -3
  103. package/dist/harness-cli.d.ts.map +0 -1
  104. package/dist/harness-cli.js.map +0 -1
  105. package/dist/skills.d.ts +0 -2
  106. package/dist/skills.d.ts.map +0 -1
  107. package/dist/skills.js.map +0 -1
  108. package/dist/update.d.ts.map +0 -1
  109. package/dist/update.js.map +0 -1
  110. /package/dist/{generate.d.ts → cli/generate.d.ts} +0 -0
  111. /package/dist/{update.d.ts → cli/update.d.ts} +0 -0
package/docs/labels.md CHANGED
@@ -26,14 +26,14 @@ For package README or package-local docs changes, prefer the package area label
26
26
 
27
27
  | Label | Meaning |
28
28
  |---|---|
29
- | `area:runtime` | `packages/mantle-runtime` behavior, ports, use cases, dispatcher, render, MCP runtime. |
29
+ | `area:runtime` | `packages/mantle-runtime` behavior, ports, use cases, dispatcher, and MCP runtime. |
30
30
  | `area:spec` | `packages/mantle-spec`, manifest parsing, validation, diagnostics, CLI, spec types. |
31
31
  | `area:cf` | `packages/adapters/cloudflare`, Workers adapter, D1/KV/ASSETS wiring, Cloudflare deploy behavior. |
32
32
  | `area:starters` | External `aotter/mantle-starters` integration, release fanout, and the local moved-starter stub. |
33
33
  | `area:skills` | `skills/*` agent briefs and install/extend/provision workflows. |
34
34
  | `area:admin-ui` | `packages/mantle-admin-ui` React admin SPA. |
35
35
  | `area:docs` | Repo-wide human docs, governance docs, ADR text, release docs, root README content, and cross-cutting documentation work. |
36
- | `area:adapter` | Adapter boundary work spanning Cloudflare, Netlify stub, or future adapters. |
36
+ | `area:adapter` | Adapter boundary work spanning Cloudflare or future adapters. |
37
37
 
38
38
  ## Release and review gates
39
39
 
@@ -41,7 +41,8 @@ For package README or package-local docs changes, prefer the package area label
41
41
  |---|---|---|---|
42
42
  | `release-gate` | Blocks a public release or release-quality claim. | Must be resolved or explicitly deferred before release. | The gate is closed or deferred by maintainer decision. |
43
43
  | `v0.1.0` | Required for the v0.1.0 release gate. | Track in the v0.1.0 release pass. | The item lands or is moved out of v0.1.0. |
44
- | `breaking-change` | Semver-relevant breaking change. | Changelog and release notes must call it out. | The change is redesigned to be non-breaking. |
44
+ | `breaking-change` | Semver-relevant breaking change. | Generated release notes must call it out. | The change is redesigned to be non-breaking. |
45
+ | `skip-release-notes` | Release bookkeeping with no user-facing change. | Excluded from generated GitHub Release notes. | The PR contains a user-facing change. |
45
46
  | `needs-adr` | Architecture, trust boundary, package boundary, or long-lived decision needs an ADR or ADR-lite proposal. | Do not merge implementation until the decision is captured. | ADR/proposal lands or maintainer confirms an existing ADR covers it. |
46
47
  | `needs-grammar-revise` | Manifest grammar or closed-enum change. | Requires grammar-revise round before code/types/starters change. | Grammar decision lands or the change no longer affects grammar. |
47
48
  | `needs-discussion` | Not converged enough for implementation. | Do not start coding from this issue. | Closing criteria are met and scope is concrete. |
@@ -60,6 +61,7 @@ gh label create "area:admin-ui" --description "React admin UI" --color "1d76db"
60
61
  gh label create "area:docs" --description "Documentation and governance" --color "1d76db"
61
62
  gh label create "area:adapter" --description "Adapter boundary and future adapter work" --color "1d76db"
62
63
  gh label create "breaking-change" --description "Semver-relevant breaking change" --color "b60205"
64
+ gh label create "skip-release-notes" --description "Release bookkeeping only; omit from generated GitHub notes" --color "ededed"
63
65
  gh label create "needs-adr" --description "Requires an ADR or ADR-lite decision before merge" --color "d93f0b"
64
66
  gh label create "needs-grammar-revise" --description "Requires manifest grammar review before implementation" --color "d93f0b"
65
67
  gh label create "needs-discussion" --description "Not converged enough for implementation" --color "fbca04"
@@ -78,7 +78,7 @@ wrangler secret put R2_SECRET_ACCESS_KEY
78
78
  ## `src/mantle/config.ts`
79
79
 
80
80
  ```ts
81
- import { R2MediaStorage, type CmsConfig } from "@aotter/mantle/cloudflare";
81
+ import { R2MediaStorage, type MantleCloudflareConfig } from "@aotter/mantle/cloudflare";
82
82
  import { AwsClient } from "aws4fetch";
83
83
 
84
84
  export interface Env {
@@ -89,7 +89,7 @@ export interface Env {
89
89
  readonly MEDIA_PUBLIC_URL_BASE?: string;
90
90
  }
91
91
 
92
- function buildMediaStorage(env: Env): CmsConfig["bindings"]["mediaStorage"] {
92
+ function buildMediaStorage(env: Env): MantleCloudflareConfig["bindings"]["mediaStorage"] {
93
93
  if (
94
94
  !env.MEDIA_BUCKET ||
95
95
  !env.R2_ACCOUNT_ID ||
@@ -177,3 +177,10 @@ Preserve source semantics:
177
177
  - animated GIFs must stay animated;
178
178
  - do not silently flatten, resize, or recompress user assets without
179
179
  asking.
180
+
181
+ ## Cleanup
182
+
183
+ Run the version-matched `media-gc` skill when an upload reached R2 but was
184
+ never committed. It audits first and removes only stale objects without
185
+ `committedAt` metadata after explicit operator confirmation. Do not use an R2
186
+ lifecycle rule: committed and uncommitted media share the same purpose prefix.
@@ -0,0 +1,45 @@
1
+ # Migrating from 0.1.0-alpha.7 to 0.1.2
2
+
3
+ 0.1.2 removes the temporary full-site compatibility stack. Mantle Core is now
4
+ an embeddable parse → link → compile → prepare → bind pipeline; Web, Admin,
5
+ Admin UI, Bun, Vercel, and Cloudflare are selected separately.
6
+
7
+ | alpha.7 | 0.1.2 |
8
+ |---|---|
9
+ | `parseManifests*` | `parseManifestSources({ sources })` |
10
+ | raw `Manifest[]` validation/runtime input | `ParsedManifestSet` → `LinkedManifestSet` → `RuntimePlan` |
11
+ | `createCmsRuntime({ manifests, db })` | `bootMantleRuntime({ plan, storage })`, or explicit prepare then `createMantleRuntime({ prepared })` |
12
+ | `CmsRuntime.db` / `entryReader` | keep the application DB handle; use `runtime.entries` for Mantle reads |
13
+ | generated `manifest`, `site.ts`, `types.d.ts` | generated `plan`, `createMantle`, `bindMantle`, and types in `mantle.ts` |
14
+ | `mantle introspect` | install `@aotter/mantle-spec` directly and run `mantle-spec introspect` |
15
+ | `mantle emit-types` | use `mantle generate`; for raw declarations, run `mantle-spec emit-types` |
16
+ | generated `.agent/skills/` | generated `.agents/skills/`; legacy user files are left untouched |
17
+ | `bindMantleSite` / string-keyed Views | `bindMantle(runtime)` and generated lower-camel properties |
18
+ | `createCmsRef` / `CmsConfig` | `createMantleRuntimeRef` / `MantleCloudflareConfig` |
19
+ | `mountServerEndpoints` | explicitly compose `mountRuntimeEndpoints` and optional `mountAdmin` |
20
+
21
+ Delete stale generated `site.ts` and `types.d.ts` files once, then run
22
+ `mantle generate`. Install only the optional package used by the host;
23
+ installing the umbrella alone now pulls only Spec and Runtime.
24
+
25
+ Intentional behavior changes:
26
+
27
+ - Generated-plan fingerprint or version mismatches fail immediately and ask
28
+ the developer to regenerate.
29
+ - Runtime HTTP trigger JSON bodies must be objects. Arrays and primitives are
30
+ rejected at the request boundary.
31
+ - Malformed percent-encoded paths are routing misses (`404`), not claimed
32
+ Mantle routes.
33
+ - Better Auth and every `@better-auth/*` package move together to 1.7.
34
+ `oauthProvider.validAudiences` becomes protected `resources`; MCP uses one
35
+ canonical `${PUBLIC_ORIGIN}/mcp` resource and CIMD client discovery.
36
+ - The Cloudflare adapter no longer requires `OAUTH_KV` or
37
+ `@cloudflare/workers-oauth-provider`. Old opaque tokens and KV registrations
38
+ cannot be migrated safely and must reconnect.
39
+ - Canonical plan ordering may change stable field/export order (including
40
+ Admin CSV columns) without changing field values.
41
+
42
+ This alpha changes the Better Auth D1 schema, including required account
43
+ issuer identity and OAuth resource/client tables. Reset and re-bootstrap a
44
+ pre-1.7 alpha auth database; do not guess an issuer backfill. Content tables
45
+ remain portable through the normal application migration/export path.
@@ -10,30 +10,29 @@ make a normal content/API/page change.
10
10
  | Read or state | Owner | Notes |
11
11
  |---|---|---|
12
12
  | Entry get/list and public slug/data-field/published reads | `DatabaseEntryRepository` through `EntryRepository` / `EntryReader` | Schema-aware field resolution is shared here. |
13
- | Manifest View execution | `ExecuteViewUseCase` + `ViewSqlCompiler` | The deliberate compiled-query exception; it still resolves declared Schema indexes. |
13
+ | Manifest View execution | `ExecuteViewUseCase` + prepared `ViewQueryExecutor` | Core owns authorization and request validation; selected storage lowers queries once and resolves declared Schema indexes. |
14
14
  | Editable settings and code-owned locale/media policy | `DatabaseSiteConfigRepository` | Editable values and dynamic media tool policy are read fresh; boot-seeded locale policy may be memoized within the runtime instance. |
15
15
  | Pending media uploads | `DatabasePendingUploadRepository` | Canonical, read-after-write D1 state; never publish-cache state. |
16
- | Rendered HTML, Markdown, and `llms.txt` | `HtmlPublishOrchestrator` plus the Cloudflare public-route cache policy | Reproducible derivatives live in KV. Settings updates invalidate through a runtime use case. |
17
- | D1/KV transport and optional query metrics | Cloudflare bindings | Bindings stay thin. Query/cache policy does not belong in a generic provider `BaseRepository`. |
16
+ | Rendered HTML, Markdown, and `llms.txt` | Request-time render use cases plus the Cloudflare public-route cache policy | D1 is canonical; version-local Workers Cache stores anonymous HTTP responses. |
17
+ | D1 transport and optional query metrics | Cloudflare bindings | Bindings stay thin. Query/cache policy does not belong in a generic provider `BaseRepository`. |
18
18
 
19
- `CmsRuntime.db` remains deprecated compatibility surface. New site code uses
20
- Manifests, runtime use cases, `entryReader`, and `siteConfig`. A site may own
19
+ The runtime exposes no raw database handle. Application and adapter code uses
20
+ the sealed plan, runtime use cases, `entries`, and `siteConfig`. An application may own
21
21
  additional tables behind its own repository at the composition root, but it
22
- must not query Mantle-owned tables through `runtime.db`.
22
+ must not query Mantle-owned tables outside the selected storage adapter.
23
23
 
24
24
  ## Cache contract
25
25
 
26
26
  - D1 is canonical for entries, site settings, media metadata, and pending
27
- uploads. KV contains only reproducible public artifacts.
28
- - A public KV hit checks the cache before loading full editable site settings.
29
- Locale policy is the small boot-seeded exception. A warm entry/page artifact
30
- therefore performs zero D1 queries.
31
- - A safe cache miss renders from canonical state and schedules KV write-back
32
- with the request execution context. It waits inline only when no execution
33
- context exists, such as a direct unit call.
34
- - Site-setting writes call the runtime settings use case, which completes
35
- public-artifact invalidation before reporting success. HTTP routes do not
36
- scan/delete KV prefixes themselves.
27
+ uploads. Core stores no rendered artifact copies.
28
+ - Public routes render canonical state and return
29
+ `Cache-Control: public, max-age=0, s-maxage=300`.
30
+ - Cloudflare Workers Cache checks eligible anonymous responses before invoking
31
+ the Worker. Cache keys are version-local, so a deploy starts with no stale
32
+ response from the previous Worker version.
33
+ - Successful publishing-content and site-setting writes purge the shared
34
+ `mantle-public` Cache-Tag through Cloudflare's native cache API. Operational
35
+ records and immutable assets stay outside that invalidation boundary.
37
36
  - Do not cache every repository read. Cross-isolate correctness for editable
38
37
  data wins unless a read has a measured hot-path contract and explicit
39
38
  invalidation.
@@ -76,11 +75,12 @@ Timing always reports p50/p95/max. A test-only Worker wrapper may also return
76
75
  `x-mantle-query-count` and `x-mantle-rows-read`; those become distributions in
77
76
  the same report. Do not expose these diagnostic headers in production.
78
77
 
79
- Core CI runs `pnpm bench:wrangler` against real Wrangler-local D1, KV, Worker
80
- HTTP routing, View execution, and live page rendering. It compares 100 and
81
- 10,000 row fixtures, then samples page MISS and HIT separately. CI gates
82
- row-read scaling, endpoint query budgets, and zero-D1 warm hits, not absolute
83
- milliseconds.
78
+ Core CI runs `pnpm bench:wrangler` against real Wrangler-local D1, Worker HTTP
79
+ routing, View execution, and origin page rendering. It compares 100 and 10,000
80
+ row fixtures and gates row-read scaling plus endpoint query budgets, not
81
+ absolute milliseconds. Wrangler-local does not emulate the new entrypoint
82
+ Workers Cache, so cache hits are a deployment-level smoke check rather than a
83
+ fabricated local metric.
84
84
 
85
85
  ## Seven findings: measured disposition
86
86
 
@@ -89,12 +89,12 @@ diagnostic, while query/row counts are the stable assertions.
89
89
 
90
90
  | Finding | Disposition |
91
91
  |---|---|
92
- | Public KV hits read D1 first | Fixed. A 10,000-row warm page measured 0 queries / 0 rows read. |
92
+ | Public cache hits read D1 first | Removed from Worker code. Cloudflare's entrypoint Workers Cache runs before the Worker; Core has no inner render cache. |
93
93
  | Slug/locale reads bypass generated indexes | Fixed by the shared schema-aware entry-read boundary. A 10,000-row page MISS measured 2 queries / 5 rows read. |
94
94
  | OFFSET pagination | Accepted for the v0.1 bounded-result surfaces: every response is capped at 500 rows and public hot paths must stay shallow. Deep/export workloads require a purpose-shaped cursor API before they are declared hot. |
95
95
  | Admin substring search scans | Accepted only for the authenticated Admin collection browser, with a 500-row response cap. Large/search-heavy sites should add a purpose-shaped indexed View or dedicated search service; do not expose this scan publicly. |
96
96
  | Published list/sitemap/llms paths lack system indexes | Fixed with measured partial indexes for published global, locale, collection, and collection+locale ordering. The 100-row and 10,000-row API runs both measured 1 query / 20 rows read. |
97
- | Page MISS waits for KV write-back | Fixed. Reproducible artifacts write through `waitUntil`; regression coverage proves response completion does not await KV. |
97
+ | Page MISS waits for cache write-back | Removed. Origin rendering returns directly; Workers Cache owns response storage outside the Worker. |
98
98
  | Benchmark stops at fake in-process dispatch | Fixed by the Node planner and Wrangler-local Worker/API/page layers. The old dispatch microbenchmark remains a narrow CPU signal only. |
99
99
 
100
100
  The retained OFFSET and substring-search trade-offs are visible exceptions,
@@ -1,8 +1,9 @@
1
1
  # Release process
2
2
 
3
- Mantle is in `0.0.x-alpha` until the v0.1.0 gate closes. Published package
4
- versions, Git tags, GitHub releases, and Starter tags are immutable: repair a
5
- bad release with the next version, never by replacing public state.
3
+ Mantle remains prerelease software until the stable v0.1.0 gate closes.
4
+ Published package versions, Git tags, GitHub releases, and Starter tags are
5
+ immutable: repair a bad release with the next version, never by replacing
6
+ public state.
6
7
 
7
8
  ## Authority
8
9
 
@@ -15,10 +16,12 @@ The controller owns this order:
15
16
  ```text
16
17
  Core source + exact-packed Starter gates
17
18
  -> Core tag
18
- -> npmjs + GitHub Packages
19
+ -> npmjs + GitHub Packages candidate packages (`mantle-release`)
19
20
  -> Starter release worker
20
21
  -> immutable Starter tag
21
22
  -> public-registry Starter gate
23
+ -> clean-create + reviewed Landing compatibility gates
24
+ -> npmjs + GitHub Packages public channel promotion
22
25
  -> Core GitHub Release
23
26
  -> optional Landing worker
24
27
  ```
@@ -45,23 +48,54 @@ verdict expires when that SHA changes. After two patch rounds, a new
45
48
  foundational blocker returns to the state table and the user for a scope
46
49
  decision instead of starting another local redesign loop.
47
50
 
51
+ For the candidate-to-channel transition, the controller follows this finite
52
+ state table:
53
+
54
+ | Durable state | Permitted next mutation | Re-run behavior | Public channel |
55
+ |---|---|---|---|
56
+ | Source gated; version unused | Create the immutable Core tag | Existing tag must match or the run fails | Unchanged |
57
+ | Core tag exists; candidate packages incomplete | Publish and verify missing exact versions under `mantle-release` through each registry's sole publish step | Existing versions are verified and skipped | Unchanged |
58
+ | Candidate packages verified; Starter tag absent | Dispatch the pinned Starter release and wait | The Starter worker resumes or reports its matching no-op | Unchanged |
59
+ | Matching Starter tag exists | Validate its Core/base provenance; run the frozen Starter, clean-create, and Landing compatibility gates | Validation and gates repeat without mutation | Unchanged |
60
+ | All downstream consumer gates pass | Promote npmjs and GitHub Packages channel tags monotonically | Same version is a no-op; an older run preserves a newer tag | Candidate or newer version |
61
+ | Channels promoted or preserved newer | Create the Core GitHub Release | Existing matching release is a no-op | Candidate or newer version |
62
+ | Core GitHub Release exists | Dispatch Landing only when explicitly enabled | Landing remains untouched by default | Candidate or newer version |
63
+
64
+ Invariants:
65
+
66
+ - immutable package versions and Core/Starter tags must keep the requested
67
+ version, Core SHA, and pinned Starter SHA identity;
68
+ - public channel tags cannot move until the released Starter, clean-create, and
69
+ reviewed Landing compatibility gates pass;
70
+ - channel updates use the controller's monotonic promotion boundary, so an
71
+ older re-run cannot move a channel backward;
72
+ - the candidate version may be fetched explicitly or through the temporary
73
+ `mantle-release` tag before promotion, but is not the public channel default.
74
+
75
+ Non-goals: this transition does not change Starter worker ownership, add
76
+ rollback or unpublish behavior, or deploy Landing unless
77
+ `deploy_landing=true`.
78
+
48
79
  ## Branches and channels
49
80
 
50
81
  - Feature and release PRs target `develop`.
51
- - Pre-v0.1 alphas release directly from the merged `develop` release commit.
82
+ - Alpha prereleases before stable v0.1.0 release directly from the merged
83
+ `develop` release commit.
52
84
  - Beta, RC, and stable promotion to `main` remains a deliberate human decision;
53
85
  it is not part of the alpha controller.
54
86
  - Alpha, beta, and RC GitHub releases are prereleases.
55
87
  - npm dist-tags follow the suffix: `alpha`, `beta`, `rc`, or `latest` for
56
88
  stable versions.
57
- - During the current `0.0.x-alpha` cadence, `latest` follows the current alpha
58
- while the `alpha` tag remains available.
89
+ - During the legacy `0.0.x-alpha` cadence, `latest` follows the current alpha.
90
+ The final `0.1.0-alpha.N` candidates advance only `alpha`; `latest` moves to
91
+ `0.1.0` after the stable gate passes.
59
92
 
60
93
  ## Release PR
61
94
 
62
95
  1. Fetch Core and Starter remotes and choose the next unused version.
63
- 2. Read `CHANGELOG.md` completely. Add a dated Keep-a-Changelog entry from the
64
- merged commits since the previous tag; do not add an `[Unreleased]` bucket.
96
+ 2. Preview GitHub's generated notes for the merged commits since the previous
97
+ tag. Correct PR titles and labels before release; do not duplicate the notes
98
+ in `CHANGELOG.md`. Label the release-only PR `skip-release-notes`.
65
99
  3. Set that exact version in every workspace package and in all four agent
66
100
  plugin manifests. Set `.agents/plugins/marketplace.json` to the immutable
67
101
  `v<version>` ref.
@@ -75,18 +109,37 @@ decision instead of starting another local redesign loop.
75
109
  packed-consumer gate. Review and merge a same-repository PR into `develop`;
76
110
  the controller rejects a direct-push release commit.
77
111
 
78
- The five public packages publish in dependency order:
112
+ Preview the native notes before merging the release PR:
113
+
114
+ ```bash
115
+ gh api --method POST repos/aotter/mantle/releases/generate-notes \
116
+ -f tag_name=vX.Y.Z \
117
+ -f target_commitish="$(git rev-parse origin/develop)" \
118
+ -f previous_tag_name=vPREVIOUS \
119
+ --jq .body
120
+ ```
121
+
122
+ The nine public packages publish in dependency order:
79
123
 
80
124
  1. `@aotter/mantle-spec`
81
125
  2. `@aotter/mantle-admin-ui`
82
126
  3. `@aotter/mantle-runtime`
83
- 4. `@aotter/mantle-cloudflare`
84
- 5. `@aotter/mantle`
127
+ 4. `@aotter/mantle-web`
128
+ 5. `@aotter/mantle-admin`
129
+ 6. `@aotter/mantle-bun`
130
+ 7. `@aotter/mantle-vercel`
131
+ 8. `@aotter/mantle-cloudflare`
132
+ 9. `@aotter/mantle`
85
133
 
86
134
  The umbrella package must contain its version-matched `docs/` and `skills/`
87
135
  payload. No tarball may contain `workspace:*` dependencies, secrets, local
88
- state, or workspace-only files. Starter projects are released from the
89
- versioned `mantle-starters` repository; Core does not publish a scaffolder.
136
+ state, or workspace-only files. Starter content is still authored and released
137
+ from the versioned `mantle-starters` repository — Core owns no starter source.
138
+ Core's umbrella CLI is the canonical consumer of that release: `mantle create`
139
+ resolves the official immutable `v${packageVersion}` starter tag and renders it
140
+ through Core's shared provision module. A published Core version
141
+ therefore requires the matching starter tag to exist; see
142
+ [ADR-0018](adr/0018-core-starters-repository-boundary.md).
90
143
 
91
144
  ## Run the controller
92
145
 
@@ -101,16 +154,20 @@ Before creating the Core tag, the controller proves:
101
154
  - the requested version matches every package, plugin, and marketplace ref;
102
155
  - `pnpm check` passes;
103
156
  - packed Core passes in the exact pinned Starter source;
104
- - all five release tarballs exist;
157
+ - all nine release tarballs exist;
105
158
  - npm and cross-repository credentials are present and readable;
106
159
  - a fresh version is unused across npmjs, GitHub Packages, and Starter tags;
107
160
  - the pinned Starter commit is still the remote `develop` tip.
108
161
 
109
- After npm publication, it compares each public registry integrity value with
110
- the locally packed tarball, rejects leaked `workspace:*` dependencies, waits
111
- for the Starter tag, checks that tag's exact Core/base provenance, installs its
112
- frozen locks from the public registry, and reruns the Starter bundle gates.
113
- Only then does it create the Core GitHub Release.
162
+ After candidate publication under `mantle-release`, it compares each public
163
+ registry integrity value with the locally packed tarball, rejects leaked
164
+ `workspace:*` dependencies, waits for the Starter tag, checks that tag's exact
165
+ Core/base provenance, installs its frozen locks from the public registry, and
166
+ reruns the Starter bundle gates. It then creates clean Blank and multilingual
167
+ Transaction projects through the registry candidate, frozen-installs and checks
168
+ both, and runs the reviewed Landing consumer against the exact packed candidate.
169
+ Only then does it promote the public npmjs and GitHub Packages channel tags and
170
+ create the Core GitHub Release.
114
171
 
115
172
  ## Idempotency and recovery
116
173
 
@@ -135,7 +192,7 @@ Core repository secrets:
135
192
 
136
193
  | Secret | Minimum purpose |
137
194
  |---|---|
138
- | `NPM_TOKEN` | Publish the five `@aotter/*` packages on npmjs. |
195
+ | `NPM_TOKEN` | Publish the nine `@aotter/*` packages on npmjs. |
139
196
  | `RELEASE_FANOUT_TOKEN` | Read and dispatch `aotter/mantle-starters`; also read and dispatch `aotter/mantle-landing` only when Landing is enabled. |
140
197
 
141
198
  Core's job-scoped `GITHUB_TOKEN` creates the Core tag and release and mirrors
@@ -158,18 +215,24 @@ for p in \
158
215
  @aotter/mantle-spec \
159
216
  @aotter/mantle-admin-ui \
160
217
  @aotter/mantle-runtime \
218
+ @aotter/mantle-web \
219
+ @aotter/mantle-admin \
220
+ @aotter/mantle-bun \
221
+ @aotter/mantle-vercel \
161
222
  @aotter/mantle-cloudflare \
162
223
  @aotter/mantle; do
163
224
  npm view "$p@X.Y.Z" version dist.integrity dependencies --json
164
225
  done
165
226
  ```
166
227
 
167
- Clone the exact Starter tag into a fresh directory, install with frozen locks,
168
- run its bundle gates, and materialize at least one typed project. Confirm the
169
- generated project contains version-matched repo-local Mantle skills and the
170
- expected typed runtime surface. `blank` remains headless and contains no Kiwa;
171
- a typed Starter revision may retain its replaceable offline UI palette, but
172
- runtime code must not import it.
228
+ The controller already creates and checks clean Blank and multilingual
229
+ Transaction projects. For 0.1.2 release acceptance, give a coding agent with no
230
+ Mantle checkout or repository knowledge only the generated instructions and
231
+ confirm it reaches a running Worker. This is one manual clean-room acceptance,
232
+ not a nondeterministic CI framework. Confirm the generated project contains
233
+ version-matched repo-local Mantle skills and the expected typed runtime surface.
234
+ `blank` remains headless and contains no Kiwa; a typed Starter revision may
235
+ retain its replaceable offline UI palette, but runtime code must not import it.
173
236
 
174
237
  If `deploy_landing=false`, also verify that no Landing release dispatch or
175
238
  deployment was started.
@@ -177,7 +240,7 @@ deployment was started.
177
240
  ## Fix-forward policy
178
241
 
179
242
  - Broken public package or Starter bundle: publish the next alpha and explain
180
- the re-spin in `CHANGELOG.md`.
243
+ the re-spin in the fix PR and generated GitHub Release notes.
181
244
  - Use `npm deprecate` to steer consumers away from a broken version.
182
245
  - Unpublish only for secrets, private files, or similarly severe exposure;
183
246
  npm versions cannot be reused and registry metadata may remain unavailable
@@ -11,7 +11,7 @@ kind: Schema
11
11
  metadata: { name: account-members }
12
12
  spec:
13
13
  title: Account members
14
- lifecycle: none
14
+ lifecycle: operational
15
15
  schema:
16
16
  type: object
17
17
  properties:
@@ -0,0 +1,100 @@
1
+ # Sealed pipeline ownership ledger
2
+
3
+ This is the migration evidence for ADR-0019 and epic #656. It records the
4
+ `v0.1.0-alpha.7` owners before code moves, the single target owner, and the
5
+ issue that must delete or delegate the old path.
6
+
7
+ ## Rule ownership
8
+
9
+ | Behavior | Current owner(s) | Target owner | Migration |
10
+ |---|---|---|---|
11
+ | YAML document decode, empty documents, syntax errors, alias cap | `ManifestParser.parseOneStream` | Parse/decode in `mantle-spec` | #663 |
12
+ | Four-atom discrimination, envelope keys, primitive/enum shape | `ManifestParser` | Parse/normalize | #663 |
13
+ | Source identity and document location | Synthetic parser doc index plus `loadManifests`/`ManifestPathDiagnoser` reconstruction | `ManifestSourceSet` authored metadata | #663 |
14
+ | Schema atom-local shape, index/search/UI shape | Parser plus `ValidateManifestsUseCase` checkers | Parse/normalize | #663; old checks deleted in #673 |
15
+ | Defaults for localized/lifecycle/indexes/search/order | `IntrospectManifestsUseCase`, runtime lifecycle checks, and callers using `??` | Parse/normalize exactly once | #663, #667 |
16
+ | Duplicate names | `ValidateManifestsUseCase` | Link | #664 |
17
+ | Schema/View/Procedure/Trigger cross-references | `ValidateManifestsUseCase` and repeated boot checks | Link | #664 |
18
+ | Guard existence, self-reference, builtin/chain rules | Validate plus `ValidateBootUseCase` | Link | #664 |
19
+ | Locale/translates graph | `checkLocaleAndTranslates` in validate and boot | Link for manifest graph; Prepare for selected deployment locales | #664, #666 |
20
+ | Manifest-owned HTTP/MCP collisions | Validate plus boot | Link | #664 |
21
+ | Handler source/registry availability | Optional CLI source scan plus boot registry scan | Prepare | #666 |
22
+ | Optional Web/Admin/Auth path reservations | Fixed boot/Cloudflare prefix lists | Prepare selected capabilities only | #666, #669, #670 |
23
+ | Kind/name lookup maps | `ValidateManifestsUseCase`, `ValidateBootUseCase`, `createCmsRuntime`, adapters | Compile once into `RuntimePlan` | #665 |
24
+ | Authorization/guard descriptors | Raw manifests interpreted by validators, runtime use cases, and mounts | Compile plan; evaluate in Core invocation | #665, #667 |
25
+ | Trigger indices and Procedure descriptors | Runtime construction/use cases | Compile plan | #665 |
26
+ | Semantic fingerprint | Runtime boot from raw manifests | Compile plan | #665 |
27
+ | Declarative View resolution | `ViewSqlCompiler` during each `ExecuteViewUseCase` call | Compile logical plan once | #665 |
28
+ | SQLite/JSON1 View lowering and native `spec.sql` | `ViewSqlCompiler` plus `DatabaseDriver` invocation | Selected storage preparation | #666 |
29
+ | Canonical SQL migrations, indexes, schema SQL Views, readiness | `createCmsRuntime.bootInit` and runtime infrastructure | Prepare | #666 |
30
+ | Entry/media/site repositories | Runtime constructs `Database*Repository` from `DatabaseDriver` | Prepared semantic storage ports; media/config move with final owner | #666, #669, #670 |
31
+ | Content, View, Procedure, Trigger, lifecycle invocation | Runtime use cases over raw maps/driver | `MantleRuntime` over plan + semantic ports | #667 |
32
+ | Target authorization/admin bypass | Runtime plus adapter entry points | One Core invocation policy; adapter resolves caller only | #667 |
33
+ | Generated manifest module and TypeScript names | `packages/mantle/src/cli/generate.ts` + `EmitTypesUseCase` | Pure linked/plan projection and `bindMantle` | #668 |
34
+ | Admin asset copy during generation | `packages/mantle/src/cli/generate.ts` | Removed; Admin install/composition owns assets | #668, #670 |
35
+ | HTML/templates/public paths/Markdown/SEO/preview/`llms.txt`/sitemap | Runtime render services plus Cloudflare public routes | Optional `mantle-web` | #669 |
36
+ | Public request mapping and cache policy | `mountPublicRoutes` | Platform adapter using selected Web projection | #669 |
37
+ | Admin API/application/static assets | Optional `mantle-admin`; Cloudflare only binds auth/request context/assets | Optional `mantle-admin` + existing UI artifact | #670 |
38
+ | View/HTTP Trigger route transport | Combined Cloudflare mounts | Platform adapters over the same Core descriptors | #669–#672 |
39
+ | Bun SQLite/process lifecycle | `mantle-bun`; host owns server/database | `mantle-bun`; host owns server/database | #671 |
40
+ | Vercel function/durable-storage lifecycle | `mantle-vercel`; host owns handler/client | `mantle-vercel`; host owns handler/client | #672 |
41
+ | Legacy overloads, aliases, combined mounts, duplicate tests | Current public API plus temporary migration delegates | Deleted | #673 |
42
+ | Contributor/agent/release guidance | `AGENTS.md`, `CLAUDE.md`, `CONTRIBUTING.md`, two release skill copies | One tool-neutral authority and one release skill | #674 |
43
+
44
+ ## Deletion evidence
45
+
46
+ All baseline production callers now consume `ParsedManifestSet`,
47
+ `LinkedManifestSet`, or `RuntimePlan` according to their pipeline stage.
48
+ `scripts/check-boundaries.mjs` fails if the removed runtime facade, generated
49
+ site API, raw parser facade, or combined Cloudflare route owner returns.
50
+ Parser-focused tests may inspect parser output, but runtime and platform tests
51
+ must compile and prepare the same sealed plan used by production.
52
+
53
+ ## Consumer manifest corpus
54
+
55
+ The Core repository does not vendor every downstream manifest. That would
56
+ create a second source of truth. The reusable golden fixture under
57
+ `packages/mantle-spec/test/fixtures/pipeline-v0.1/` covers every shipped atom,
58
+ auth/guard references, all Trigger surfaces, multi-document YAML, empty
59
+ documents, aliases, unknown keys, malformed YAML, and deterministic
60
+ diagnostics.
61
+
62
+ Exact downstream sources and their gate authorities are pinned here. The public
63
+ Starter runs in Core CI and release preflight. Private consumers run the same
64
+ exact-tarball checker in their own repositories, so public Core PRs never
65
+ receive cross-repository credentials:
66
+
67
+ | Consumer | Revision | Gate authority | Manifest paths |
68
+ |---|---|---|---|
69
+ | `aotter/mantle-starters` | `157e8f49e1e25ae1c52c0115f0dd9e8b6017ef0e` | Core CI + release | `blank/manifests/site.yaml`; `overlays/{community,intake,presence,publication,reservation,transaction}/manifests/site.yaml`; `recipes/typed-web/manifests/site.yaml` |
70
+ | `aotter/mantle-landing` | `4381354dd25d5d94f4096cf3e55a4cb9eecbf3ad` | Landing CI + Core release | `manifests/site.yaml` |
71
+ | `aotter/mantle-platform` (Remote Mantle/control plane) | `3cc0d9ad6ee47b15f06c915c12f56fc4b9143f32` | Platform `exact-packed-core` | `manifests/platform.yaml` |
72
+ | Core i18n fixture | this repository | Core CI | `packages/mantle-spec/test/fixtures/i18n-parent-child/manifests/site.yaml` |
73
+
74
+ ## Baseline gates
75
+
76
+ The alpha.7 baseline was captured from tag `v0.1.0-alpha.7` on 2026-08-16
77
+ with Node 22, pnpm 9, Wrangler local mode, and datasets of 100/10,000 rows:
78
+
79
+ | Route | p95 queries | p95 rows read | local p95 timing |
80
+ |---|---:|---:|---:|
81
+ | public View, 10k rows | 1 | 20 | 3.01 ms |
82
+ | public page miss, 10k rows | 2 | 5 | 3.92 ms |
83
+ | Admin list, 10k rows | 1 | 21–22 | 2.49–3.24 ms |
84
+ | Admin related detail, dense | 4 | 151 | 5.23 ms |
85
+ | public builtin create | 1 | 0 | 2.55 ms |
86
+
87
+ Wall-clock values are evidence, not a cross-machine budget. The normative
88
+ baseline is the existing `pnpm bench:wrangler` query/row gate: every gate must
89
+ remain true, unchanged revisions must perform no repeated preparation, and any
90
+ intentional budget change needs its own reviewed evidence.
91
+
92
+ Existing full-facade behavior is covered by Cloudflare authorization, Admin,
93
+ public-route/cache, View REST, HTTP Trigger, media, form, and facade tests.
94
+ Issues #669–#673 move those assertions to selected modules and exact packed
95
+ consumers; they do not duplicate the suite under new names.
96
+
97
+ Issue #674 leaves `CONTRIBUTING.md` plus accepted ADRs as the contributor
98
+ authority. `AGENTS.md`, `CLAUDE.md`, and the Claude release-skill entry are
99
+ small routers; `.agent/skills/mantle-release/SKILL.md` is the only maintainer
100
+ release procedure. Shipped `skills/*` remain separate consumer artifacts.