@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
@@ -1,39 +1,29 @@
1
1
  # Release process
2
2
 
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.
7
-
8
- ## Authority
9
-
10
- `.github/workflows/release.yml` is the single release controller. Humans merge
11
- a reviewed release PR and dispatch that workflow from the merge commit. Humans
12
- do not push release tags or start downstream release workers directly.
13
-
14
- The controller owns this order:
15
-
16
- ```text
17
- Core source + exact-packed Starter gates
18
- -> Core tag
19
- -> npmjs + GitHub Packages candidate packages (`mantle-release`)
20
- -> Starter release worker
21
- -> immutable Starter tag
22
- -> public-registry Starter gate
23
- -> clean-create + reviewed Landing compatibility gates
24
- -> npmjs + GitHub Packages public channel promotion
25
- -> Core GitHub Release
26
- -> optional Landing worker
27
- ```
28
-
29
- The Starter worker owns only its repository transition: it prepares a release
30
- PR from the exact gated `develop` commit, waits for the named checks, merges
31
- that checked head atomically into `develop`, and tags the recorded merge
32
- commit. It does not promote `main`, backport, infer releases from commit text,
33
- or dispatch Landing.
34
-
35
- Landing is an explicit controller input and defaults off. A release that keeps
36
- `deploy_landing=false` does not mutate or deploy Landing.
3
+ First stable targets 0.1.2 (#826). The last legacy Landing/Starter release is
4
+ 0.1.0-alpha.17. Its immutable artifacts and repositories remain available;
5
+ recover that version with its tagged controller/docs. New releases have no
6
+ Starter/Landing checkout, tag, dispatch, credential or deployment dependency.
7
+
8
+ ## Authority and state transitions
9
+
10
+ `.github/workflows/release.yml` is the only release controller. Humans merge
11
+ a reviewed same-repository release PR, then explicitly dispatch that merge.
12
+ No task implicitly authorizes publication; no manual package/tag writer exists.
13
+
14
+ | State | Sole next writer | Retry / invariant |
15
+ |---|---|---|
16
+ | Reviewed source; unused version | Core source/packed-consumer gates, then immutable Core tag | Exact canonical merged PR SHA and version required |
17
+ | Tag exists; registry candidates partial | Existing npm/GPR publication steps | Verify existing artifact identity; publish missing versions only |
18
+ | Registry candidates verified | Public-registry reference consumer gate | No mutation; failure leaves public channels unchanged |
19
+ | Consumer passes | Monotonic npm/GPR channel promotion | Same version is a no-op; older runs cannot move a channel backward |
20
+ | Channels promoted/preserved newer | GitHub release step | Existing release identity or fail |
21
+
22
+ The public-registry gate uses a disposable copy of the directly authored
23
+ `docs/examples/minimal-worker` reference, installs the exact candidate, then
24
+ checks generation, skill projection, TypeScript and real Worker HTTP behavior.
25
+ The same reference is gated against exact tarballs before Core tagging. It is
26
+ a test/example, not a scaffold product or another repository release.
37
27
 
38
28
  ## Changing release automation
39
29
 
@@ -48,203 +38,67 @@ verdict expires when that SHA changes. After two patch rounds, a new
48
38
  foundational blocker returns to the state table and the user for a scope
49
39
  decision instead of starting another local redesign loop.
50
40
 
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`.
41
+ Invariants: immutable versions/tags retain their identity; registry integrity
42
+ and the published-consumer gate precede public channel promotion; retries
43
+ cannot move channels backward. No downstream mutation, unpublish or rollback
44
+ is introduced. The runnable release-order check guards these transitions.
78
45
 
79
46
  ## Branches and channels
80
47
 
81
- - Feature and release PRs target `develop`.
82
- - Alpha prereleases before stable v0.1.0 release directly from the merged
83
- `develop` release commit.
84
- - Beta, RC, and stable promotion to `main` remains a deliberate human decision;
85
- it is not part of the alpha controller.
86
- - Alpha, beta, and RC GitHub releases are prereleases.
87
- - npm dist-tags follow the suffix: `alpha`, `beta`, `rc`, or `latest` for
88
- stable versions.
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.
92
-
93
- ## Release PR
94
-
95
- 1. Fetch Core and Starter remotes and choose the next unused version.
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`.
99
- 3. Set that exact version in every workspace package and in all four agent
100
- plugin manifests. Set `.agents/plugins/marketplace.json` to the immutable
101
- `v<version>` ref.
102
- 4. Pin both the controller and Core CI to the exact reviewed
103
- `mantle-starters/develop` commit intended for this release. Do not use a
104
- branch, latest tag, or inferred fallback.
105
- 5. If an SDK type changed, audit downstream literal constructors and exhaustive
106
- switches before publication. CI in Core cannot prove downstream source
107
- compatibility by itself.
108
- 6. Run `pnpm check`, inspect the packed umbrella package, and run the exact
109
- packed-consumer gate. Review and merge a same-repository PR into `develop`;
110
- the controller rejects a direct-push release commit.
111
-
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:
123
-
124
- 1. `@aotter/mantle-spec`
125
- 2. `@aotter/mantle-admin-ui`
126
- 3. `@aotter/mantle-runtime`
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`
133
-
134
- The umbrella package must contain its version-matched `docs/` and `skills/`
135
- payload. No tarball may contain `workspace:*` dependencies, secrets, local
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).
143
-
144
- ## Run the controller
145
-
146
- Dispatch `.github/workflows/release.yml` from the merged release commit with:
147
-
148
- - `version`: the version without the leading `v`.
149
- - `deploy_landing`: `false` unless Landing was separately reviewed and is
150
- intentionally part of this release.
151
-
152
- Before creating the Core tag, the controller proves:
153
-
154
- - the requested version matches every package, plugin, and marketplace ref;
155
- - `pnpm check` passes;
156
- - packed Core passes in the exact pinned Starter source;
157
- - all nine release tarballs exist;
158
- - npm and cross-repository credentials are present and readable;
159
- - a fresh version is unused across npmjs, GitHub Packages, and Starter tags;
160
- - the pinned Starter commit is still the remote `develop` tip.
161
-
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.
171
-
172
- ## Idempotency and recovery
173
-
174
- The global controller lock serializes releases. Re-running the same release is
175
- supported:
176
-
177
- - an existing Core tag must resolve to the same controller commit;
178
- - existing npm and GitHub Packages versions are verified and skipped;
179
- - channel dist-tags are never moved backward by an older rerun;
180
- - a duplicate Starter dispatch resumes its open/merged state or reports a
181
- tagged no-op;
182
- - an existing GitHub Release is a no-op.
183
-
184
- If source or immutable state disagrees, the workflow fails instead of guessing.
185
- Fix source and publish the next version when public state is wrong. Re-run the
186
- same controller only for a transient failure or a verified partial transition.
187
- Never force-retag or republish an existing version.
188
-
189
- ## Credentials
190
-
191
- Core repository secrets:
192
-
193
- | Secret | Minimum purpose |
194
- |---|---|
195
- | `NPM_TOKEN` | Publish the nine `@aotter/*` packages on npmjs. |
196
- | `RELEASE_FANOUT_TOKEN` | Read and dispatch `aotter/mantle-starters`; also read and dispatch `aotter/mantle-landing` only when Landing is enabled. |
197
-
198
- Core's job-scoped `GITHUB_TOKEN` creates the Core tag and release and mirrors
199
- packages to GitHub Packages. Starter's job-scoped token pushes its generated
200
- branch, checked merge, and tag; its `RELEASE_FANOUT_TOKEN` is used only to
201
- create the canonical same-repository PR. Prefer separate fine-grained tokens
202
- or a GitHub App when practical; do not grant organization-wide repository
203
- access for this flow.
204
-
205
- ## Post-release verification
206
-
207
- Completion requires evidence for both repositories, not only a green publish
208
- step:
209
-
210
- ```bash
211
- gh -R aotter/mantle release view vX.Y.Z
212
- gh api repos/aotter/mantle-starters/git/ref/tags/vX.Y.Z
213
-
214
- for p in \
215
- @aotter/mantle-spec \
216
- @aotter/mantle-admin-ui \
217
- @aotter/mantle-runtime \
218
- @aotter/mantle-web \
219
- @aotter/mantle-admin \
220
- @aotter/mantle-bun \
221
- @aotter/mantle-vercel \
222
- @aotter/mantle-cloudflare \
223
- @aotter/mantle; do
224
- npm view "$p@X.Y.Z" version dist.integrity dependencies --json
225
- done
226
- ```
227
-
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.
236
-
237
- If `deploy_landing=false`, also verify that no Landing release dispatch or
238
- deployment was started.
239
-
240
- ## Fix-forward policy
241
-
242
- - Broken public package or Starter bundle: publish the next alpha and explain
243
- the re-spin in the fix PR and generated GitHub Release notes.
244
- - Use `npm deprecate` to steer consumers away from a broken version.
245
- - Unpublish only for secrets, private files, or similarly severe exposure;
246
- npm versions cannot be reused and registry metadata may remain unavailable
247
- during the unpublish cooldown.
248
- - A cross-cutting rename must include an explicit infrastructure-config diff
249
- and live smoke test. CI success does not prove renamed Worker, D1, KV, route,
250
- or secret bindings are correct.
48
+ - Alpha releases use the reviewed develop merge. Beta/RC/stable use main after
49
+ explicit promotion; first stable acceptance is tracked by #826.
50
+ - Alpha/beta/RC GitHub releases are prereleases; their npm tags match suffixes.
51
+ - Stable publishes latest. Final 0.1.0 alphas only advance alpha, preserving
52
+ existing legacy latest. Historic 0.0 alpha behavior remains recoverable.
53
+
54
+ ## Prepare and run
55
+
56
+ 1. Fetch Core refs, prove the version and tag unused. Preview GitHub generated
57
+ notes since the previous tag; correct PR metadata and label release-only
58
+ PRs skip-release-notes. Do not duplicate release entries in CHANGELOG.md.
59
+ 2. Align every workspace package, plugin and marketplace ref to the version.
60
+ 3. Review API compatibility and migration instructions for actual consumers.
61
+ Frozen legacy consumers stay on alpha.17; do not make them follow new Core.
62
+ 4. Run `pnpm check`, including exact packed Worker, optional products, Bun,
63
+ Vercel, skills, release invariants, types and tests. Inspect the umbrella
64
+ docs/skills payload: no workspace dependencies, secrets or local state.
65
+ 5. Freeze the PR head for self review; CI must pass before merge. Dispatch
66
+ release.yml from that merge with `version` (without v). It refuses an
67
+ untagged source that is no longer the expected branch tip.
68
+
69
+ The ten public packages remain in dependency order:
70
+
71
+ 1. @aotter/mantle-spec
72
+ 2. @aotter/mantle-admin-ui
73
+ 3. @aotter/mantle-runtime
74
+ 4. @aotter/mantle-indexeddb
75
+ 5. @aotter/mantle-web
76
+ 6. @aotter/mantle-admin
77
+ 7. @aotter/mantle-bun
78
+ 8. @aotter/mantle-vercel
79
+ 9. @aotter/mantle-cloudflare
80
+ 10. @aotter/mantle
81
+
82
+ ## Credentials and verification
83
+
84
+ Core needs NPM_TOKEN for npmjs. Its job-scoped GITHUB_TOKEN creates the Core
85
+ tag/release and mirrors GitHub Packages. No cross-repository fanout token is
86
+ needed. Before tagging, verify credentials and new-version absence on both
87
+ registries. Existing artifacts on retry must have matching integrity.
88
+
89
+ Completion requires the Core tag SHA, all ten npmjs/GPR packages, exact
90
+ integrity, no workspace dependencies, a passing public-registry Worker gate,
91
+ correct channel tags and the GitHub release. Retain run links and gate evidence.
92
+ This does not prove stable production soak or upgrade safety; #826 owns those
93
+ acceptance requirements. A first-stable agent acceptance uses only the
94
+ version-matched authoring instructions, not an SDK checkout or generated site.
95
+
96
+ ## Recovery
97
+
98
+ Rerun the same controller commit/version for a transient or verified partial
99
+ transition. Existing tags/artifacts must match; newer channels stay put. Fail
100
+ on identity disagreement instead of guessing. A wrong public artifact needs
101
+ a new version; never force-retag, overwrite or reuse a published version.
102
+ Unpublish is reserved for actual secret/private-file exposure, never routine
103
+ fixes. Infrastructure renames require their explicit config diff and live
104
+ smoke; CI alone cannot prove provider identity.
@@ -1,182 +1,5 @@
1
- # Schema indexes on D1
1
+ # Schema indexes
2
2
 
3
- Mantle stores every authored Schema property inside the shared `entries.data`
4
- JSON `TEXT` column. Declare `indexes` for measured, hot access paths that need
5
- an ordered non-unique B-tree index. Use `uniqueIndexes` when the same ordered
6
- fields are a data-integrity constraint.
3
+ This guide moved into the handbook: [`docs/handbook/reference/schema.md`](handbook/reference/schema.md).
7
4
 
8
- ```yaml
9
- apiVersion: cms.mantle.aotter.net/v1
10
- kind: Schema
11
- metadata: { name: account-members }
12
- spec:
13
- title: Account members
14
- lifecycle: operational
15
- schema:
16
- type: object
17
- properties:
18
- userId: { type: string }
19
- state: { type: string }
20
- accountId: { type: string }
21
- email: { type: [string, "null"] }
22
- indexes:
23
- - [userId, state, accountId]
24
- - [accountId, state, userId]
25
- uniqueIndexes:
26
- - [accountId, userId]
27
- - [accountId, email]
28
- ```
29
-
30
- Each inner array is one index. Field order is significant. A one-field array
31
- is valid; a bare string or the retired `indexedFields` spelling is not.
32
- Invalid matrix shapes report `INVALID_MANIFEST_ENVELOPE`; invalid index
33
- semantics report `SCHEMA_INDEX_INVALID`, and unknown fields report
34
- `SCHEMA_INDEX_FIELD_UNKNOWN` (`uniqueIndexes` keeps its existing
35
- `UNIQUE_INDEX_FIELD_UNKNOWN` code).
36
-
37
- ## Leftmost-prefix behavior
38
-
39
- For `[userId, state, accountId]`, SQLite can use the index for:
40
-
41
- ```sql
42
- WHERE userId = ?
43
- WHERE userId = ? AND state = ?
44
- WHERE userId = ? AND state = ? AND accountId = ?
45
- ```
46
-
47
- It does not provide the same guarantee when the leftmost field is skipped:
48
-
49
- ```sql
50
- WHERE state = ? AND accountId = ?
51
- ```
52
-
53
- The second declaration, `[accountId, state, userId]`, supports the other hot
54
- path and supplies the requested order without a temporary sort:
55
-
56
- ```sql
57
- WHERE accountId = ? AND state = ?
58
- ORDER BY userId
59
- ```
60
-
61
- Do not declare every possible permutation. Each index consumes storage and
62
- adds work to inserts and updates. Start from an observed query plan or hot
63
- endpoint and declare only the access paths it needs.
64
-
65
- ## Supported fields
66
-
67
- Indexed fields are exact, own, top-level keys of
68
- `spec.schema.properties`. `a.b` means a literal top-level key named `a.b`; it
69
- does not traverse `{ a: { b: ... } }`.
70
-
71
- An index-bearing Schema name and every indexed field must match
72
- `^[A-Za-z][A-Za-z0-9_.-]*$`.
73
-
74
- The property must declare exactly one non-null scalar type. It may also allow
75
- `null` with a type array or `nullable: true`.
76
-
77
- | JSON Schema type | generated-column affinity |
78
- |---|---|
79
- | `string` | `TEXT` |
80
- | `integer`, `boolean` | `INTEGER` |
81
- | `number` | `REAL` |
82
-
83
- Objects, arrays, enum-only properties, and mixed non-null unions are not
84
- indexable. Reserved native View fields (`id`, `status`, `version`,
85
- `createdAt`, `updatedAt`, `authorId`) also cannot be index declarations.
86
-
87
- Missing and `null` leftmost values are omitted from the partial index. SQLite
88
- UNIQUE semantics still allow more than one composite containing `NULL`.
89
-
90
- ## Core-compiled queries
91
-
92
- Mantle creates collection-gated VIRTUAL generated columns during `bootInit`.
93
- Core-compiled View projections, filters, and ordering automatically reference
94
- a generated column when their field is declared by `indexes` or
95
- `uniqueIndexes`; undeclared fields keep using `json_extract`.
96
-
97
- D1 stores the original JSON as `TEXT`, not PostgreSQL JSONB. The generated
98
- scalar columns and their B-tree indexes are the supported indexed-path
99
- mechanism. Their physical identifiers are private, versioned, and encoded;
100
- never copy one from `sqlite_schema` into site code.
101
-
102
- ## Site-owned Procedure SQL
103
-
104
- Use the pure helper when a business query remains site-owned. It returns a
105
- fully quoted reference for a declared field or `null` when that field has no
106
- declared index. Pass a table alias for joins so the generated column is not
107
- ambiguous.
108
-
109
- ```ts
110
- import {
111
- schemaIndexedFieldSql,
112
- type SchemaManifest,
113
- } from "@aotter/mantle/spec";
114
- import { loadManifests } from "../mantle/manifests.js";
115
-
116
- const accountMembers = loadManifests().find(
117
- (manifest): manifest is SchemaManifest =>
118
- manifest.kind === "Schema" && manifest.metadata.name === "account-members",
119
- );
120
- if (!accountMembers) throw new Error("account-members Schema is missing");
121
-
122
- const userId = schemaIndexedFieldSql(accountMembers, "userId", "member");
123
- const state = schemaIndexedFieldSql(accountMembers, "state", "member");
124
- if (!userId || !state) {
125
- throw new Error("account-members actor lookup requires its declared index");
126
- }
127
-
128
- const rows = await env.DB.prepare(
129
- `SELECT member.id, member.data
130
- FROM entries AS member
131
- WHERE member.collection = ?
132
- AND ${userId} = ?
133
- AND ${state} = ?`,
134
- )
135
- .bind("account-members", actorId, "active")
136
- .all();
137
- ```
138
-
139
- The helper does not authorize the query or define its business response. The
140
- site still owns actor resolution, account rules, aggregation, and output.
141
-
142
- ## Verify a plan
143
-
144
- Prefer the shipped crowded-data harness for a manifest View:
145
-
146
- ```bash
147
- pnpm exec mantle-harness indexes --require-public --format text
148
- ```
149
-
150
- It applies Mantle's real canonical migrations and generated DDL, seeds skewed
151
- rows, compiles and executes the real View SQL, then records
152
- `EXPLAIN QUERY PLAN`. By default findings are advisory; use `--require-public`
153
- or repeat `--require <view-name>` only for paths whose performance is part of
154
- the contract. See [the performance harness](./performance-harness.md).
155
-
156
- For site-owned SQL that cannot be represented by a View, inspect the real
157
- database directly when adding or changing a hot path:
158
-
159
- ```sql
160
- PRAGMA index_list("entries");
161
- PRAGMA index_xinfo("<index returned above>");
162
-
163
- EXPLAIN QUERY PLAN
164
- SELECT id FROM entries
165
- WHERE collection = 'account-members'
166
- AND "<reference emitted by Core>" = 'user-1';
167
- ```
168
-
169
- The plan should contain `SEARCH entries USING INDEX ...`, and an indexed
170
- filter/order path should not contain `USE TEMP B-TREE FOR ORDER BY`.
171
-
172
- Existing databases upgrade by adding new affinity-correct VIRTUAL columns and
173
- versioned indexes; populated `entries` rows do not need a rewrite. Unused
174
- generated columns may remain because dropping them is not safe across every D1
175
- version Mantle supports. Compatible alpha.59 unique indexes remain during a
176
- rolling upgrade; ambiguous legacy flattened names and indexes removed from
177
- manifests are reconciled away at boot.
178
-
179
- References: [D1 JSON](https://developers.cloudflare.com/d1/sql-api/query-json/),
180
- [D1 generated columns](https://developers.cloudflare.com/d1/reference/generated-columns/),
181
- [D1 indexes](https://developers.cloudflare.com/d1/best-practices/use-indexes/),
182
- [SQLite partial indexes](https://www.sqlite.org/partialindex.html).
5
+ The handbook ships inside the `@aotter/mantle` package under `node_modules/@aotter/mantle/docs/handbook/` and describes the installed release.
@@ -26,7 +26,7 @@ issue that must delete or delegate the old path.
26
26
  | Semantic fingerprint | Runtime boot from raw manifests | Compile plan | #665 |
27
27
  | Declarative View resolution | `ViewSqlCompiler` during each `ExecuteViewUseCase` call | Compile logical plan once | #665 |
28
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 |
29
+ | Canonical SQL migrations, native Schema tables/indexes, readiness | `createCmsRuntime.bootInit` and runtime infrastructure | Prepare | #666 |
30
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
31
  | Content, View, Procedure, Trigger, lifecycle invocation | Runtime use cases over raw maps/driver | `MantleRuntime` over plan + semantic ports | #667 |
32
32
  | Target authorization/admin bypass | Runtime plus adapter entry points | One Core invocation policy; adapter resolves caller only | #667 |
@@ -59,10 +59,11 @@ auth/guard references, all Trigger surfaces, multi-document YAML, empty
59
59
  documents, aliases, unknown keys, malformed YAML, and deterministic
60
60
  diagnostics.
61
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:
62
+ The following pins record the historical sealed-pipeline migration gates.
63
+ ADR-0021 supersedes the Starter/Landing release coupling: current Core CI and
64
+ release use `docs/examples/minimal-worker` from the same reviewed commit.
65
+ Private consumers can still run the exact-tarball checker in their own repos;
66
+ public Core PRs receive no cross-repository credentials:
66
67
 
67
68
  | Consumer | Revision | Gate authority | Manifest paths |
68
69
  |---|---|---|---|