@aotter/mantle 0.1.5-alpha.1 → 0.2.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 (495) hide show
  1. package/README.md +166 -298
  2. package/dist/auth/adapter.d.ts +32 -0
  3. package/dist/auth/adapter.js +288 -0
  4. package/dist/auth/admin.d.ts +3 -0
  5. package/dist/auth/admin.js +21 -0
  6. package/dist/auth/caller.d.ts +86 -0
  7. package/dist/auth/caller.js +155 -0
  8. package/dist/auth/hardening.d.ts +24 -0
  9. package/dist/auth/hardening.js +40 -0
  10. package/dist/auth/identity.d.ts +121 -0
  11. package/dist/auth/identity.js +203 -0
  12. package/dist/auth/oauth.d.ts +63 -0
  13. package/dist/auth/oauth.js +217 -0
  14. package/dist/auth/resource-seeds.js +10 -0
  15. package/dist/auth/routes.d.ts +32 -0
  16. package/dist/auth/routes.js +226 -0
  17. package/dist/build/compiler.d.ts +721 -0
  18. package/dist/build/compiler.js +7029 -0
  19. package/dist/build/spec/domain/model/ManifestGrammar.d.ts +439 -0
  20. package/dist/build/spec/domain/model/RuntimePlan.d.ts +168 -0
  21. package/dist/build/spec/domain/model/SqlIr.d.ts +129 -0
  22. package/dist/build/spec/domain/model/UserFields.d.ts +21 -0
  23. package/dist/build/spec/domain/service/PlanFingerprint.d.ts +7 -0
  24. package/dist/build/spec/kernel/diagnostic.d.ts +108 -0
  25. package/dist/bun/assets.d.ts +2 -0
  26. package/dist/bun/assets.js +24 -0
  27. package/dist/domain/adminOrder.js +24 -0
  28. package/dist/domain/columns.js +57 -0
  29. package/dist/domain/describe/chunk-ZVXBGP7Y.js +424 -0
  30. package/dist/domain/describe/index.d.ts +58 -0
  31. package/dist/domain/describe/index.js +115 -0
  32. package/dist/domain/describe/target-hash.d.ts +8 -0
  33. package/dist/domain/describe/target-hash.js +12 -0
  34. package/dist/domain/describe/targets.d.ts +40 -0
  35. package/dist/domain/entry.js +33 -0
  36. package/dist/domain/generated-tools.js +19 -0
  37. package/dist/domain/generation.d.ts +16 -0
  38. package/dist/domain/generation.js +1 -0
  39. package/dist/domain/input.js +17 -0
  40. package/dist/domain/model.js +1 -0
  41. package/dist/domain/paging.js +230 -0
  42. package/dist/domain/recipes.js +24 -0
  43. package/dist/domain/userReferences.js +5 -0
  44. package/dist/domain/wireScalars.js +47 -0
  45. package/dist/infrastructure/adminEntries.js +153 -0
  46. package/dist/infrastructure/adminPaging.js +72 -0
  47. package/dist/infrastructure/artifacts.js +71 -0
  48. package/dist/infrastructure/authSchema.js +83 -0
  49. package/dist/infrastructure/bundle.js +188 -0
  50. package/dist/infrastructure/cli.js +118 -0
  51. package/dist/infrastructure/generate.d.ts +12 -0
  52. package/dist/infrastructure/generate.js +189 -0
  53. package/dist/infrastructure/generateAuth.d.ts +8 -0
  54. package/dist/infrastructure/generateAuth.js +74 -0
  55. package/dist/infrastructure/help.js +60 -0
  56. package/dist/infrastructure/init.js +54 -0
  57. package/dist/infrastructure/inputs.js +41 -0
  58. package/dist/infrastructure/mounts.js +25 -0
  59. package/dist/infrastructure/wrangler.js +109 -0
  60. package/dist/kernel/authorization.d.ts +4 -0
  61. package/dist/kernel/authorization.js +16 -0
  62. package/dist/kernel/binds.d.ts +60 -0
  63. package/dist/kernel/binds.js +49 -0
  64. package/dist/kernel/caller-identity.d.ts +24 -0
  65. package/dist/kernel/caller-identity.js +22 -0
  66. package/dist/kernel/contract-error.d.ts +12 -0
  67. package/dist/kernel/contract-error.js +14 -0
  68. package/dist/kernel/contracts.d.ts +143 -0
  69. package/dist/kernel/contracts.js +97 -0
  70. package/dist/kernel/cron.d.ts +1 -0
  71. package/dist/kernel/cron.js +58 -0
  72. package/dist/kernel/dialect/common.d.ts +38 -0
  73. package/dist/kernel/dialect/common.js +6 -0
  74. package/dist/kernel/dialect/postgres.d.ts +16 -0
  75. package/dist/kernel/dialect/postgres.js +18 -0
  76. package/dist/kernel/dialect/sqlite.d.ts +20 -0
  77. package/dist/kernel/dialect/sqlite.js +34 -0
  78. package/dist/kernel/drain.d.ts +5 -0
  79. package/dist/kernel/drain.js +35 -0
  80. package/dist/kernel/driver/bun-sqlite.d.ts +19 -0
  81. package/dist/kernel/driver/bun-sqlite.js +77 -0
  82. package/dist/kernel/driver/d1.d.ts +24 -0
  83. package/dist/kernel/driver/d1.js +22 -0
  84. package/dist/kernel/driver/postgres.d.ts +25 -0
  85. package/dist/kernel/driver/postgres.js +99 -0
  86. package/dist/kernel/driver/transaction-context.d.ts +10 -0
  87. package/dist/kernel/driver/transaction-context.js +29 -0
  88. package/dist/kernel/email.d.ts +28 -0
  89. package/dist/kernel/email.js +38 -0
  90. package/dist/kernel/host-access.d.ts +10 -0
  91. package/dist/kernel/host-access.js +65 -0
  92. package/dist/kernel/host-caller.d.ts +39 -0
  93. package/dist/kernel/host-caller.js +56 -0
  94. package/dist/kernel/json-body.d.ts +4 -0
  95. package/dist/kernel/json-body.js +44 -0
  96. package/dist/kernel/mcp-apps.d.ts +69 -0
  97. package/dist/kernel/mcp-apps.js +40 -0
  98. package/dist/kernel/mcp-call.d.ts +5 -0
  99. package/dist/kernel/mcp-call.js +25 -0
  100. package/dist/kernel/mcp-handler.js +371 -0
  101. package/dist/kernel/mcp.d.ts +110 -0
  102. package/dist/kernel/mcp.js +50 -0
  103. package/dist/kernel/media.d.ts +27 -0
  104. package/dist/kernel/media.js +216 -0
  105. package/dist/kernel/paging.d.ts +55 -0
  106. package/dist/kernel/paging.js +95 -0
  107. package/dist/kernel/publishing.d.ts +4 -0
  108. package/dist/kernel/publishing.js +16 -0
  109. package/dist/kernel/r2-media.d.ts +42 -0
  110. package/dist/kernel/r2-media.js +78 -0
  111. package/dist/kernel/rest-dispatch.js +38 -0
  112. package/dist/kernel/rest-router.js +64 -0
  113. package/dist/kernel/rest.d.ts +58 -0
  114. package/dist/kernel/rest.js +41 -0
  115. package/dist/kernel/scalars.d.ts +6 -0
  116. package/dist/kernel/scalars.js +44 -0
  117. package/dist/kernel/search.js +5 -0
  118. package/dist/kernel/site-types.d.ts +146 -0
  119. package/dist/kernel/site-types.js +1 -0
  120. package/dist/kernel/site.d.ts +39 -0
  121. package/dist/kernel/site.js +32 -0
  122. package/dist/kernel/store.d.ts +175 -0
  123. package/dist/kernel/store.js +269 -0
  124. package/dist/kernel/surface.d.ts +10 -0
  125. package/dist/kernel/surface.js +19 -0
  126. package/dist/kernel/sweep.d.ts +17 -0
  127. package/dist/kernel/sweep.js +27 -0
  128. package/dist/kernel/translations.d.ts +1 -0
  129. package/dist/kernel/translations.js +13 -0
  130. package/dist/kernel/user-caller.d.ts +31 -0
  131. package/dist/kernel/user-caller.js +67 -0
  132. package/dist/kernel/user-field-name.js +3 -0
  133. package/dist/kernel/user-fields.d.ts +35 -0
  134. package/dist/kernel/user-fields.js +81 -0
  135. package/dist/kernel/validation.d.ts +15 -0
  136. package/dist/kernel/validation.js +54 -0
  137. package/dist/kernel/web-gateway.js +68 -0
  138. package/dist/kernel/web-head.js +15 -0
  139. package/dist/kernel/web-index.js +40 -0
  140. package/dist/kernel/web-response.js +8 -0
  141. package/dist/kernel/web.d.ts +77 -0
  142. package/dist/kernel/web.js +124 -0
  143. package/dist/kernel/where.js +27 -0
  144. package/dist/testing/index.d.ts +1 -0
  145. package/dist/testing/index.js +1 -0
  146. package/dist/usecase/adminBindings.js +143 -0
  147. package/dist/usecase/adminClient.js +87 -0
  148. package/dist/usecase/adminDescriptors.js +107 -0
  149. package/dist/usecase/generate.js +166 -0
  150. package/dist/usecase/handlers.js +21 -0
  151. package/dist/usecase/mcp-media.js +17 -0
  152. package/dist/usecase/mcp.js +100 -0
  153. package/dist/usecase/paging.js +71 -0
  154. package/dist/usecase/publishing.js +63 -0
  155. package/dist/usecase/refusals.js +27 -0
  156. package/dist/usecase/rest.js +54 -0
  157. package/dist/usecase/search.js +7 -0
  158. package/dist/usecase/site.js +39 -0
  159. package/dist/usecase/stores.js +64 -0
  160. package/dist/usecase/tool-version.js +9 -0
  161. package/dist/usecase/translations.js +78 -0
  162. package/dist/usecase/ttl.js +20 -0
  163. package/dist/usecase/validation.js +241 -0
  164. package/dist/usecase/web.js +23 -0
  165. package/docs/examples/README.md +39 -18
  166. package/docs/examples/app-shell/.dev.vars.example +4 -0
  167. package/docs/examples/app-shell/README.md +121 -0
  168. package/docs/examples/app-shell/accept.mjs +91 -0
  169. package/docs/examples/app-shell/gitignore +7 -0
  170. package/docs/examples/app-shell/package.json +43 -0
  171. package/docs/examples/app-shell/pnpm-workspace.yaml +8 -0
  172. package/docs/examples/app-shell/smoke-kit.mjs +168 -0
  173. package/docs/examples/app-shell/src/auth.ts +58 -0
  174. package/docs/examples/app-shell/src/handlers.ts +5 -0
  175. package/docs/examples/app-shell/src/index.ts +4 -0
  176. package/docs/examples/app-shell/src/routes.ts +14 -0
  177. package/docs/examples/app-shell/src/schedule.ts +8 -0
  178. package/docs/examples/app-shell/src/service.ts +70 -0
  179. package/docs/examples/app-shell/src/sign-in.ts +41 -0
  180. package/docs/examples/app-shell/src/signup.ts +8 -0
  181. package/docs/examples/app-shell/tsconfig.json +26 -0
  182. package/docs/examples/app-shell/worker-configuration.d.ts +22 -0
  183. package/docs/examples/app-shell/wrangler.jsonc +62 -0
  184. package/docs/examples/club-events/README.md +65 -0
  185. package/docs/examples/club-events/manifests/club-events.yaml +247 -0
  186. package/docs/examples/club-events/smoke.mjs +127 -0
  187. package/docs/examples/club-events/src/handlers.ts +25 -0
  188. package/docs/examples/club-events/src/signup.ts +9 -0
  189. package/docs/examples/generated-web/README.md +78 -0
  190. package/docs/examples/generated-web/posts.yaml +38 -0
  191. package/docs/examples/generated-web/seed.sql +6 -0
  192. package/docs/examples/generated-web/src/worker.ts +43 -0
  193. package/docs/examples/generated-web/tsconfig.json +8 -0
  194. package/docs/examples/generated-web/wrangler.jsonc +8 -0
  195. package/docs/examples/purchasing/.dev.vars.example +6 -0
  196. package/docs/examples/purchasing/README.md +99 -0
  197. package/docs/examples/purchasing/manifests/purchasing.yaml +374 -0
  198. package/docs/examples/purchasing/seed.sql +4 -0
  199. package/docs/examples/purchasing/smoke.mjs +191 -0
  200. package/docs/examples/purchasing/src/admin.tsx +13 -0
  201. package/docs/examples/purchasing/src/handlers.ts +33 -0
  202. package/docs/examples/purchasing/src/notify.ts +29 -0
  203. package/docs/examples/purchasing/src/requests-page.ts +57 -0
  204. package/docs/examples/purchasing/src/routes.ts +53 -0
  205. package/docs/examples/purchasing/src/schedule.ts +31 -0
  206. package/docs/examples/purchasing/src/signup.ts +5 -0
  207. package/docs/examples/purchasing/src/supplier.ts +32 -0
  208. package/docs/examples/purchasing/wrangler.jsonc +69 -0
  209. package/docs/examples/recipes/README.md +60 -0
  210. package/docs/examples/recipes/manifests/recipes.yaml +75 -0
  211. package/docs/examples/recipes/smoke.mjs +102 -0
  212. package/docs/examples/recipes/src/media.ts +13 -0
  213. package/docs/examples/recipes/src/pages.ts +99 -0
  214. package/docs/examples/recipes/src/routes.ts +71 -0
  215. package/docs/examples/recipes/src/site-config.ts +12 -0
  216. package/docs/examples/recipes/wrangler.jsonc +74 -0
  217. package/docs/handbook/cloudflare/authentication.md +180 -322
  218. package/docs/handbook/cloudflare/chatgpt-sites.md +5 -23
  219. package/docs/handbook/cloudflare/deploy-and-operate.md +55 -77
  220. package/docs/handbook/cloudflare/media-r2.md +61 -205
  221. package/docs/handbook/cloudflare/service-entry.md +239 -0
  222. package/docs/handbook/concepts/authorization.md +10 -107
  223. package/docs/handbook/concepts/four-atoms.md +9 -168
  224. package/docs/handbook/concepts/lifecycle-and-locales.md +9 -132
  225. package/docs/handbook/concepts/mcp-and-agents.md +24 -121
  226. package/docs/handbook/concepts/procedures-and-triggers.md +5 -217
  227. package/docs/handbook/concepts/runtime-and-adapters.md +15 -169
  228. package/docs/handbook/concepts/views.md +10 -185
  229. package/docs/handbook/examples/hub.md +3 -8
  230. package/docs/handbook/guides/adapter-guide.md +11 -0
  231. package/docs/handbook/guides/admin-ui.md +115 -133
  232. package/docs/handbook/guides/agent-setup.md +64 -74
  233. package/docs/handbook/guides/agent-workflow-acceptance.md +232 -0
  234. package/docs/handbook/guides/email.md +86 -0
  235. package/docs/handbook/guides/local-testing.md +40 -0
  236. package/docs/handbook/guides/mcp-apps.md +560 -0
  237. package/docs/handbook/guides/native-admin.md +566 -0
  238. package/docs/handbook/guides/native-execution.md +133 -0
  239. package/docs/handbook/guides/oauth.md +219 -0
  240. package/docs/handbook/guides/postgres-adapters.md +56 -0
  241. package/docs/handbook/guides/public-pages.md +87 -0
  242. package/docs/handbook/guides/size-and-startup.md +9 -0
  243. package/docs/handbook/guides/sql-patterns.md +266 -0
  244. package/docs/handbook/guides/typed-queries.md +211 -107
  245. package/docs/handbook/navigation.json +176 -55
  246. package/docs/handbook/reference/admin-descriptors.md +53 -0
  247. package/docs/handbook/reference/authorization.md +39 -266
  248. package/docs/handbook/reference/describe.md +56 -0
  249. package/docs/handbook/reference/diagnostics.md +19 -186
  250. package/docs/handbook/reference/features.md +45 -55
  251. package/docs/handbook/reference/manifest.md +6 -129
  252. package/docs/handbook/reference/procedure.md +11 -303
  253. package/docs/handbook/reference/schema.md +64 -240
  254. package/docs/handbook/reference/site-config.md +5 -218
  255. package/docs/handbook/reference/sql.md +64 -0
  256. package/docs/handbook/reference/surface.md +392 -201
  257. package/docs/handbook/reference/trigger.md +56 -192
  258. package/docs/handbook/reference/view.md +24 -243
  259. package/docs/handbook/releases/index.md +244 -77
  260. package/docs/handbook/start/agents.md +45 -0
  261. package/docs/handbook/start/overview.md +9 -48
  262. package/docs/handbook/start/project-and-cli.md +51 -104
  263. package/docs/handbook/start/quickstart-worker.md +43 -178
  264. package/docs/skills/develop/SKILL.md +79 -249
  265. package/docs/skills/integrate/SKILL.md +39 -50
  266. package/docs/skills/media-gc/SKILL.md +34 -10
  267. package/docs/skills/provision/SKILL.md +36 -186
  268. package/docs/skills/update/SKILL.md +23 -38
  269. package/docs/source/scripts/postgres-adapter.ts +101 -0
  270. package/docs/upgrade-0.1-to-0.2.md +227 -0
  271. package/package.json +120 -131
  272. package/skills/README.md +48 -108
  273. package/skills/mantle/SKILL.md +76 -0
  274. package/dist/admin-ui.d.ts +0 -2
  275. package/dist/admin-ui.d.ts.map +0 -1
  276. package/dist/admin-ui.js +0 -2
  277. package/dist/admin-ui.js.map +0 -1
  278. package/dist/admin.d.ts +0 -2
  279. package/dist/admin.d.ts.map +0 -1
  280. package/dist/admin.js +0 -2
  281. package/dist/admin.js.map +0 -1
  282. package/dist/auth.d.ts +0 -2
  283. package/dist/auth.d.ts.map +0 -1
  284. package/dist/auth.js +0 -2
  285. package/dist/auth.js.map +0 -1
  286. package/dist/bun.d.ts +0 -2
  287. package/dist/bun.d.ts.map +0 -1
  288. package/dist/bun.js +0 -2
  289. package/dist/bun.js.map +0 -1
  290. package/dist/cli/generate-cloudflare.d.ts +0 -7
  291. package/dist/cli/generate-cloudflare.d.ts.map +0 -1
  292. package/dist/cli/generate-cloudflare.js +0 -123
  293. package/dist/cli/generate-cloudflare.js.map +0 -1
  294. package/dist/cli/generate-project.d.ts +0 -25
  295. package/dist/cli/generate-project.d.ts.map +0 -1
  296. package/dist/cli/generate-project.js +0 -282
  297. package/dist/cli/generate-project.js.map +0 -1
  298. package/dist/cli/generate-sites.d.ts +0 -8
  299. package/dist/cli/generate-sites.d.ts.map +0 -1
  300. package/dist/cli/generate-sites.js +0 -273
  301. package/dist/cli/generate-sites.js.map +0 -1
  302. package/dist/cli/generate.d.ts +0 -20
  303. package/dist/cli/generate.d.ts.map +0 -1
  304. package/dist/cli/generate.js +0 -299
  305. package/dist/cli/generate.js.map +0 -1
  306. package/dist/cli/harness.d.ts +0 -3
  307. package/dist/cli/harness.d.ts.map +0 -1
  308. package/dist/cli/harness.js +0 -214
  309. package/dist/cli/harness.js.map +0 -1
  310. package/dist/cli/main.d.ts +0 -3
  311. package/dist/cli/main.d.ts.map +0 -1
  312. package/dist/cli/main.js +0 -77
  313. package/dist/cli/main.js.map +0 -1
  314. package/dist/cli/skills.d.ts +0 -3
  315. package/dist/cli/skills.d.ts.map +0 -1
  316. package/dist/cli/skills.js +0 -128
  317. package/dist/cli/skills.js.map +0 -1
  318. package/dist/cloudflare.d.ts +0 -2
  319. package/dist/cloudflare.d.ts.map +0 -1
  320. package/dist/cloudflare.js +0 -2
  321. package/dist/cloudflare.js.map +0 -1
  322. package/dist/codegen/emitMantleModule.d.ts +0 -22
  323. package/dist/codegen/emitMantleModule.d.ts.map +0 -1
  324. package/dist/codegen/emitMantleModule.js +0 -291
  325. package/dist/codegen/emitMantleModule.js.map +0 -1
  326. package/dist/codegen.d.ts +0 -2
  327. package/dist/codegen.d.ts.map +0 -1
  328. package/dist/codegen.js +0 -2
  329. package/dist/codegen.js.map +0 -1
  330. package/dist/runtime-testing.d.ts +0 -2
  331. package/dist/runtime-testing.d.ts.map +0 -1
  332. package/dist/runtime-testing.js +0 -2
  333. package/dist/runtime-testing.js.map +0 -1
  334. package/dist/runtime.d.ts +0 -2
  335. package/dist/runtime.d.ts.map +0 -1
  336. package/dist/runtime.js +0 -2
  337. package/dist/runtime.js.map +0 -1
  338. package/dist/spec.d.ts +0 -2
  339. package/dist/spec.d.ts.map +0 -1
  340. package/dist/spec.js +0 -2
  341. package/dist/spec.js.map +0 -1
  342. package/dist/vercel-libsql.d.ts +0 -2
  343. package/dist/vercel-libsql.d.ts.map +0 -1
  344. package/dist/vercel-libsql.js +0 -2
  345. package/dist/vercel-libsql.js.map +0 -1
  346. package/dist/vercel.d.ts +0 -2
  347. package/dist/vercel.d.ts.map +0 -1
  348. package/dist/vercel.js +0 -2
  349. package/dist/vercel.js.map +0 -1
  350. package/dist/web.d.ts +0 -2
  351. package/dist/web.d.ts.map +0 -1
  352. package/dist/web.js +0 -2
  353. package/dist/web.js.map +0 -1
  354. package/docs/adapter-guide.md +0 -222
  355. package/docs/adr/0001-four-atom-manifest-model.md +0 -440
  356. package/docs/adr/0002-closed-enums-for-bindings.md +0 -253
  357. package/docs/adr/0007-ai-as-primary-author.md +0 -473
  358. package/docs/adr/0008-structured-diagnostic-shape.md +0 -338
  359. package/docs/adr/0009-consumer-supplied-manifests.md +0 -149
  360. package/docs/adr/0010-locale-and-translates.md +0 -453
  361. package/docs/adr/0011-adapter-port-spec.md +0 -281
  362. package/docs/adr/0012-views-as-public-rest.md +0 -161
  363. package/docs/adr/0013-agent-provisioned-consumer-projects.md +0 -154
  364. package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +0 -900
  365. package/docs/adr/0016-site-semantic-layer.md +0 -70
  366. package/docs/adr/0017-media-multi-variant-agent-side-optimization.md +0 -181
  367. package/docs/adr/0018-core-starters-repository-boundary.md +0 -179
  368. package/docs/adr/0019-sealed-manifest-runtime-pipeline.md +0 -240
  369. package/docs/adr/0020-builtin-handler-contracts-and-matched-upsert.md +0 -199
  370. package/docs/adr/0021-retire-starter-scaffolding.md +0 -30
  371. package/docs/adr/0022-caller-observed-version-occ.md +0 -212
  372. package/docs/adr/0023-port-failure-contract.md +0 -69
  373. package/docs/adr/0024-manifest-native-schema-tables.md +0 -264
  374. package/docs/adr/0025-reserved-native-columns-and-published-only-public-views.md +0 -105
  375. package/docs/adr/0026-progressive-generate.md +0 -36
  376. package/docs/adr/0027-scheduled-procedure-triggers.md +0 -31
  377. package/docs/adr/0028-schema-ttl-expiry.md +0 -33
  378. package/docs/adr/README.md +0 -81
  379. package/docs/adr/adr-lite-803-request-diagnostics.md +0 -38
  380. package/docs/adr/adr-lite-808-route-readiness.md +0 -47
  381. package/docs/adr/adr-lite-809-bounded-public-content.md +0 -71
  382. package/docs/adr/adr-lite-812-native-parity.md +0 -150
  383. package/docs/adr/adr-lite-823-home-statistics.md +0 -64
  384. package/docs/adr/adr-lite-842-mcp-authoring.md +0 -30
  385. package/docs/adr/adr-lite-845-frontend-client.md +0 -38
  386. package/docs/adr/adr-lite-861-admin-webmcp.md +0 -42
  387. package/docs/adr/adr-lite-909-admin-ui-kit.md +0 -37
  388. package/docs/agent-prompts.md +0 -64
  389. package/docs/api-mcp-authorization.md +0 -5
  390. package/docs/assets/mantle-admin-developer.png +0 -0
  391. package/docs/assets/mantle-admin-operations.png +0 -0
  392. package/docs/assets/mantle-hero.jpg +0 -0
  393. package/docs/auth-hosting-model.md +0 -166
  394. package/docs/cloudflare-low-level-composition.md +0 -5
  395. package/docs/consumer-onboarding-audit.md +0 -65
  396. package/docs/deferred-lifecycle-queues.md +0 -5
  397. package/docs/design-atoms.md +0 -16
  398. package/docs/design-references/editorial-blog-2026-05-05.md +0 -218
  399. package/docs/direct-authoring.md +0 -5
  400. package/docs/examples/builtin-commerce.md +0 -269
  401. package/docs/examples/builtin-intake.md +0 -143
  402. package/docs/examples/builtin-legal-documents.md +0 -189
  403. package/docs/examples/builtin-procurement.md +0 -241
  404. package/docs/examples/builtin-publication.md +0 -241
  405. package/docs/examples/builtin-reservation.md +0 -149
  406. package/docs/examples/cf-primitives-commerce-inventory.md +0 -809
  407. package/docs/examples/cf-primitives-guarded-api.md +0 -429
  408. package/docs/examples/cf-primitives-intake-hooks.md +0 -319
  409. package/docs/examples/host-chatgpt-sites/.openai/hosting.json +0 -1
  410. package/docs/examples/host-chatgpt-sites/README.md +0 -70
  411. package/docs/examples/host-chatgpt-sites/drizzle/0000_sites_users.sql +0 -8
  412. package/docs/examples/host-chatgpt-sites/drizzle/0001_mantle.sql +0 -294
  413. package/docs/examples/host-chatgpt-sites/drizzle/0002_article_cover.sql +0 -5
  414. package/docs/examples/host-chatgpt-sites/drizzle/0003_store_instance_id.sql +0 -1
  415. package/docs/examples/host-chatgpt-sites/drizzle/0004_mantle.sql +0 -10
  416. package/docs/examples/host-chatgpt-sites/drizzle/0005_mantle.sql +0 -24
  417. package/docs/examples/host-chatgpt-sites/drizzle/meta/_journal.json +0 -1
  418. package/docs/examples/host-chatgpt-sites/drizzle/meta/mantle-state.json +0 -60
  419. package/docs/examples/host-chatgpt-sites/manifests/site.yaml +0 -27
  420. package/docs/examples/host-chatgpt-sites/package.json +0 -1
  421. package/docs/examples/host-chatgpt-sites/public/site.css +0 -1
  422. package/docs/examples/host-chatgpt-sites/scripts/build.mjs +0 -13
  423. package/docs/examples/host-chatgpt-sites/scripts/check.mjs +0 -101
  424. package/docs/examples/host-chatgpt-sites/scripts/migration.mjs +0 -43
  425. package/docs/examples/host-chatgpt-sites/src/chatgpt-auth.ts +0 -66
  426. package/docs/examples/host-chatgpt-sites/src/index.ts +0 -46
  427. package/docs/examples/host-chatgpt-sites/src/mcp.ts +0 -49
  428. package/docs/examples/host-chatgpt-sites/src/media.ts +0 -109
  429. package/docs/examples/host-chatgpt-sites/src/r2-lab.ts +0 -38
  430. package/docs/examples/host-chatgpt-sites/src/storage-fingerprint.json +0 -1
  431. package/docs/examples/host-chatgpt-sites/src/web.ts +0 -35
  432. package/docs/examples/host-chatgpt-sites/tsconfig.json +0 -1
  433. package/docs/examples/host-chatgpt-sites/wrangler.jsonc +0 -10
  434. package/docs/examples/host-local-admin-otp/.dev.vars.example +0 -3
  435. package/docs/examples/host-local-admin-otp/README.md +0 -80
  436. package/docs/examples/host-local-admin-otp/ensure-dev-vars.mjs +0 -5
  437. package/docs/examples/host-local-admin-otp/manifests/site.yaml +0 -25
  438. package/docs/examples/host-local-admin-otp/package.json +0 -29
  439. package/docs/examples/host-local-admin-otp/public/.gitkeep +0 -1
  440. package/docs/examples/host-local-admin-otp/smoke.mjs +0 -141
  441. package/docs/examples/host-local-admin-otp/src/index.ts +0 -54
  442. package/docs/examples/host-local-admin-otp/tsconfig.json +0 -17
  443. package/docs/examples/host-local-admin-otp/wrangler.jsonc +0 -23
  444. package/docs/examples/host-minimal-worker/README.md +0 -41
  445. package/docs/examples/host-minimal-worker/manifests/site.yaml +0 -25
  446. package/docs/examples/host-minimal-worker/package.json +0 -26
  447. package/docs/examples/host-minimal-worker/smoke.mjs +0 -23
  448. package/docs/examples/host-minimal-worker/src/index.ts +0 -4
  449. package/docs/examples/host-minimal-worker/tsconfig.json +0 -17
  450. package/docs/examples/host-minimal-worker/wrangler.jsonc +0 -22
  451. package/docs/handbook/chatgpt-sites/equipment-checkout.md +0 -231
  452. package/docs/handbook/chatgpt-sites/generated-app.md +0 -84
  453. package/docs/handbook/chatgpt-sites/host-reference.md +0 -113
  454. package/docs/handbook/chatgpt-sites/index.md +0 -133
  455. package/docs/handbook/cloudflare/bindings.md +0 -291
  456. package/docs/handbook/cloudflare/conventional-worker.md +0 -166
  457. package/docs/handbook/cloudflare/deferred-hooks-queues.md +0 -170
  458. package/docs/handbook/cloudflare/low-level-composition.md +0 -169
  459. package/docs/handbook/cloudflare/public-web.md +0 -144
  460. package/docs/handbook/cloudflare/site-chrome.md +0 -75
  461. package/docs/handbook/examples/commerce-transaction.md +0 -11
  462. package/docs/handbook/examples/commerce.md +0 -11
  463. package/docs/handbook/examples/guarded-api.md +0 -10
  464. package/docs/handbook/examples/intake-form.md +0 -12
  465. package/docs/handbook/examples/intake-hooks.md +0 -11
  466. package/docs/handbook/examples/legal-documents.md +0 -10
  467. package/docs/handbook/examples/procurement-approvals.md +0 -10
  468. package/docs/handbook/examples/publication.md +0 -10
  469. package/docs/handbook/examples/reservation.md +0 -10
  470. package/docs/handbook/start/quickstart-admin.md +0 -52
  471. package/docs/labels.md +0 -71
  472. package/docs/media-uploads.md +0 -5
  473. package/docs/migration-0.1.2.md +0 -13
  474. package/docs/performance-harness.md +0 -228
  475. package/docs/release-process.md +0 -244
  476. package/docs/schema-indexes.md +0 -5
  477. package/docs/sealed-pipeline-ownership.md +0 -101
  478. package/docs/skills/plugin/SKILL.md +0 -132
  479. package/docs/skills/theme/SKILL.md +0 -77
  480. package/docs/spec-only-host-adoption.md +0 -157
  481. package/docs/transaction-patterns.md +0 -5
  482. package/skills/develop/SKILL.md +0 -258
  483. package/skills/install/SKILL.md +0 -112
  484. package/skills/integrate/SKILL.md +0 -60
  485. package/skills/media-gc/SKILL.md +0 -85
  486. package/skills/plugin/SKILL.md +0 -132
  487. package/skills/provision/SKILL.md +0 -194
  488. package/skills/theme/SKILL.md +0 -77
  489. package/skills/update/SKILL.md +0 -51
  490. package/templates/chatgpt-sites/auth.ts +0 -66
  491. package/templates/chatgpt-sites/build.mjs +0 -14
  492. package/templates/chatgpt-sites/env.ts +0 -1
  493. package/templates/chatgpt-sites/mcp.ts +0 -48
  494. package/templates/chatgpt-sites/public-mcp.ts +0 -29
  495. package/templates/chatgpt-sites/smoke-local.mjs +0 -20
@@ -1,286 +1,110 @@
1
- ---
2
- description: Schema field reference — JSON Schema subset, uiSchema, indexes, translates, lifecycle and TTL rules.
3
- ---
4
1
  # Schema
5
2
 
6
- A Schema declares one collection: the JSON Schema for each entry's `data`, its indexes, its Admin presentation and its lifecycle mode. Schemas are never exposed directly; Views read them and Procedures write them. This page is the field-level contract; the concepts are in [The four atoms](../concepts/four-atoms.md) and [Lifecycle and locales](../concepts/lifecycle-and-locales.md). Envelope rules are in [Manifest envelope and conventions](./manifest.md).
7
-
8
- ## Fields
9
-
10
- | Field | Type | Required | Default | Rules |
11
- |---|---|---|---|---|
12
- | `title` | LocalizedText | yes | — | Admin label. Non-empty string or locale map. |
13
- | `description` | LocalizedText | no | — | Same shape as `title`. |
14
- | `schema` | JSON Schema 2020-12 | yes | — | Must be an object. Walked by the [subset validator](#json-schema-subset). |
15
- | `uiSchema` | object | no | — | Accepts `fields`, `list`, and `nav`. Violations are `SCHEMA_UI_INVALID`. |
16
- | `uniqueIndexes` | `string[][]` | no | `[]` | Ordered tuples of top-level scalar fields. See [Indexes](#indexes). |
17
- | `indexes` | `string[][]` | no | `[]` | Ordered non-unique tuples of data fields and native entry columns. Must not repeat a `uniqueIndexes` tuple. |
18
- | `searchableFields` | `string[]` | no | `[]` | Top-level string fields for Admin and Staff MCP substring search. |
19
- | `localized` | boolean | no | `false` | When `false`, a `locale` property is rejected. Must be a boolean. |
20
- | `translates` | `{ parent, on }` | no | — | Marks a translation child. Requires `localized: true`. |
21
- | `lifecycle` | `publishing` \| `operational` | no | `publishing` | Selects the [state machine](#lifecycle). |
22
- | `ttl` | `{ field, expireAfterSeconds }` | no | — | Logical expiry over one top-level date-time property. See [TTL](#ttl). |
23
-
24
- ### Reserved entry columns
25
-
26
- Every entry carries `id`, `status`, `version`, `createdAt`, `updatedAt` and `authorId` as native columns outside `data`. They are valid in View `fields`, `filter`, `orderBy` and `uiSchema.list.columns`, and `indexes` may include them (`uniqueIndexes` may not). `uiSchema.list.primaryField` is the entry title and must be a declared data property. A data property may not reuse one of these names: validate fails closed with `INVALID_MANIFEST_ENVELOPE` at `/spec/schema/properties/<name>`, because SQLite-family and IndexedDB storage would otherwise resolve the name differently and an index declared today could change meaning when a same-named property is added later. Use a domain name instead (`submittedAt`, `orderStatus`, `submittedBy`); the native column is still there and still readable (ADR-0025). `locale` is a reserved data field: only a localized Schema may declare it, and the runtime requires it on writes to a localized Schema. SQL Views project the native column. Do not declare `expectedVersion` under `spec.schema.properties` — that name is the reserved Procedure OCC token; validate fails closed with `INVALID_MANIFEST_ENVELOPE` (ADR-0022). New reserved Procedure input names need an ADR.
27
-
28
- ## Example
3
+ A Schema declares one table and its typed Store collection. Required keys are title and an object JSON Schema. Optional keys include lifecycle, scope, TTL, indexes, uniqueIndexes, checks, searchableFields, localized, translates and uiSchema. Unknown keys fail validation.
29
4
 
30
5
  ```yaml
31
- apiVersion: cms.mantle.aotter.net/v1
6
+ apiVersion: cms.mantle.aotter.net/v2
32
7
  kind: Schema
33
- metadata:
34
- name: support-requests
8
+ metadata: { name: orders }
35
9
  spec:
36
- title: { en: Support requests, "zh-TW": 客服請求 }
37
- description: Requests submitted from the public contact form.
10
+ title: Orders
38
11
  lifecycle: operational
12
+ scope: "owner = auth.uid()"
13
+ uniqueIndexes: [[owner, orderNumber]]
14
+ searchableFields: [orderNumber]
15
+ checks: ["qty > 0"]
39
16
  schema:
40
17
  type: object
41
18
  additionalProperties: false
42
- required: [ticketNumber, subject, body, requestStatus]
43
- properties:
44
- ticketNumber: { type: string, pattern: "^SR-[0-9]{6}$" }
45
- subject: { type: string, minLength: 1, maxLength: 200 }
46
- body: { type: string, x-mcp-hint: markdown }
47
- requestStatus: { type: string, enum: [open, waiting, closed], default: open }
48
- customerId: { type: string, x-mantle-ref: customers }
49
- attachmentId: { type: string, x-mantle-ref: media_assets, x-mcp-hint: media-file }
50
- submittedBy: { type: string, x-mantle-bind: ctx.user }
51
- submittedAt: { type: integer, x-mcp-hint: timestamp-ms, x-mantle-bind: now }
52
- uiSchema:
53
- fields:
54
- body: { widget: textarea }
55
- list:
56
- filterField: requestStatus
57
- primaryField: ticketNumber
58
- columns: [subject, requestStatus, submittedAt]
59
- uniqueIndexes: [[ticketNumber]]
60
- indexes: [[requestStatus, submittedAt], [customerId]]
61
- searchableFields: [ticketNumber, subject]
62
- ```
63
-
64
- ## `translates`
65
-
66
- A translation child holds the locale-specific fields of a non-localized parent, joined on a shared field.
67
-
68
- ```yaml
69
- apiVersion: cms.mantle.aotter.net/v1
70
- kind: Schema
71
- metadata:
72
- name: product-translations
73
- spec:
74
- title: Product translations
75
- localized: true
76
- translates: { parent: products, on: sku }
77
- schema:
78
- type: object
79
- required: [sku, name]
19
+ required: [owner, orderNumber, qty]
80
20
  properties:
81
- sku: { type: string }
82
- locale: { type: string }
83
- name: { type: string, minLength: 1 }
84
- description: { type: string, x-mcp-hint: markdown }
85
- uniqueIndexes: [[sku, locale]]
21
+ owner: { type: string }
22
+ orderNumber: { type: string }
23
+ qty: { type: integer, minimum: 1 }
86
24
  ```
87
25
 
88
- `locale` is declared but not listed in `required`; the write-time gate enforces presence.
89
-
90
- | Phase | Rule | Diagnostic |
91
- |---|---|---|
92
- | parse | `parent` and `on` are non-empty strings; no other keys. | `INVALID_MANIFEST_ENVELOPE` |
93
- | parse | `localized: true` is set. | `TRANSLATES_REQUIRES_LOCALIZED` |
94
- | parse | At least one property besides `locale` and the join field. | `TRANSLATES_REQUIRES_CONTENT_FIELD` |
95
- | parse | `on` is declared in this Schema's `properties`. | `TRANSLATES_FIELD_NOT_IN_CHILD` |
96
- | validate and boot | `parent` names a declared Schema. | `TRANSLATES_PARENT_UNKNOWN` |
97
- | validate and boot | The parent is not `localized: true`. | `TRANSLATES_PARENT_IS_LOCALIZED` |
98
- | validate and boot | `on` is declared in the parent's `properties`. | `TRANSLATES_FIELD_NOT_IN_PARENT` |
99
- | boot | A localized Schema needs at least one site locale. | `SCHEMA_LOCALIZED_REQUIRES_SITE_LOCALES` |
100
-
101
- ## JSON Schema subset
26
+ ## Fields and storage
102
27
 
103
- Authors write JSON Schema; the runtime validates with zod via `z.fromJSONSchema`. The parser accepts a bounded subset so every manifest converts.
28
+ A string `pattern` needs a `maxLength`: generation bounds each regex's backtracking and, when it refuses one (`INVALID_PATTERN`), names the largest `maxLength` it accepts. Anchor patterns with `^` and avoid nested quantifiers such as `(-[a-z0-9]+)*`.
104
29
 
105
- | Recognized keywords |
106
- |---|
107
- | `$defs`, `$ref`, `oneOf`, `const`, `type`, `properties`, `required`, `items`, `enum`, `format`, `pattern`, `minLength`, `maxLength`, `minimum`, `maximum`, `minItems`, `maxItems`, `nullable`, `readOnly`, `default`, `additionalProperties`, `title`, `description`, and any `x-` keyword |
30
+ | Field | sqlite | postgres |
31
+ | --- | --- | --- |
32
+ | string | TEXT | text |
33
+ | date-time | integer microseconds | timestamptz |
34
+ | date | integer days | date |
35
+ | integer | INTEGER | int8 |
36
+ | number | REAL | float8 |
37
+ | boolean | 0/1 | bool |
38
+ | object/array | JSON text | jsonb |
39
+ | geo | lat/lng columns, R*Tree | lat/lng columns |
108
40
 
109
- | Rejected keywords (`JSON_SCHEMA_UNSUPPORTED`) |
110
- |---|
111
- | `anyOf`, `allOf`, `not`, `if`, `then`, `else`, `$anchor`, `$dynamicAnchor`, `$dynamicRef`, `definitions`, `patternProperties`, `prefixItems`, `contains`, `dependentSchemas`, `propertyNames`, `unevaluatedProperties` |
41
+ System columns include id, version, created_at, updated_at and author_id; publishing adds status/published_at. Initial DDL declares a field NOT NULL when an `operational` Schema lists it in `required` and it does not allow null; `default` never does, and no column gets a DDL `DEFAULT` ([server-maintained fields](#admin-uischema)). Do not declare reserved fields. Manifest native column names in indexes use camelCase (`createdAt`); generated Store/SQL use storage names (`created_at`). Scope is omitted from returned rows.
112
42
 
113
- Other standard keywords are not rejected by the parser, but only the recognized set is part of the documented contract.
43
+ Declared date/date-time outputs are SQL-formatted strings (`YYYY-MM-DD`, UTC ISO with six fractional digits). Computed timestamps remain native. Inputs and other output scalars follow [the native contract](../guides/native-execution.md). Date conversion through JS Date loses microseconds.
114
44
 
115
- | Rule | Diagnostic |
116
- |---|---|
117
- | Nesting deeper than 100 levels, or more than 10,000 schema nodes. | `JSON_SCHEMA_LIMIT_EXCEEDED` |
118
- | `$ref` must begin `#/$defs/` and resolve to an object in the same document. | `JSON_SCHEMA_REF_INVALID` |
119
- | `pattern` must compile as a JavaScript regular expression. | `INVALID_PATTERN` |
120
- | Every `required` entry of `spec.schema` must be declared under `properties`. | `REQUIRED_FIELD_UNKNOWN` |
121
- | `properties` and `$defs` must be objects; `oneOf` a non-empty array; `additionalProperties` a boolean or a schema. | `INVALID_MANIFEST_ENVELOPE` |
45
+ Generated types constrain Store fields and writes; Store does not interpret a JSON Schema on each call. Validate untrusted inputs at the boundary. Selected Admin emits full/partial field checks; drafts may be incomplete, while publishing checks required data. Native constraints remain database-enforced.
122
46
 
123
- Two accepted spellings are normalized at the boundary: `nullable: true` becomes a `type` array that includes `"null"`, and `format: url` becomes `format: uri`. `additionalProperties` keeps standard semantics: omitted or `true` preserves extra keys, `false` rejects them, a schema validates them.
47
+ ## Row rules
124
48
 
125
- ### `x-mantle-bind`
49
+ Schemas default to operational. Publishing opts into draft/published/archived and generated admin/system transitions. Store cannot assign system columns or scope; generated policy fills them. See [lifecycle and locales](../concepts/lifecycle-and-locales.md).
126
50
 
127
- Marks a property as server-stamped. The value is a closed enum; anything else is `BIND_VALUE_NOT_IN_ENUM`.
51
+ Owner and field columns prefix every unique index in that order. User reads/writes see their own rows; anonymous reads see none. System callers bypass scope. TTL uses `{ field, expireAfterSeconds }` over a date-time field; expired rows become invisible but remain stored until a system sweep. TTL is not allowed on translations.
128
52
 
129
- | Value | Stamped as | Typical field |
130
- |---|---|---|
131
- | `ctx.user` | `ctx.user?.id ?? null` | `authorId`, `submittedBy` |
132
- | `ctx.staff` | `ctx.staff?.id ?? null` | `approvedBy`, `grantedBy` |
133
- | `now` | write-time Unix epoch milliseconds | `createdAt`, `submittedAt` |
53
+ `localized` and `translates: { parent, on }` declare a translation child. Parent visibility and publication are retained, with matching scope where needed. Locale values stay plain strings.
134
54
 
135
- Stamping semantics: on create the computed value replaces whatever the caller sent. On update the existing stamp is preserved and only computed when the stored row lacks it, so a `now` bind does not become an updated-at field. A `null` stamp is dropped before JSON Schema validation, so `type: string` passes for anonymous callers. Bound properties are removed from Staff MCP `create_*` and `update_*` tool schemas. Stamped values appear in View output as ordinary fields.
55
+ ## Indexes, checks and search
136
56
 
137
- ### `x-mantle-ref`
57
+ Indexes are ordered composite scalar/native columns. A paged View's `ORDER BY` must match an index on the base Schema after any fixed equality prefix ([index prefixes](#index-prefixes-for-paged-views)), ending with `id` as the tiebreak: `ORDER BY created_at DESC, id DESC` needs `indexes: [[createdAt, id]]` (generation reports `Missing index for ORDER BY ...` otherwise). Required operational fields are NOT NULL; publishing drafts may be incomplete. Store sortable types use indexed/non-null columns, with explicit nullable published_at support.
138
58
 
139
- An informational foreign-key marker on a string property that holds another collection's entry id (`x-mantle-ref: customers`). Nothing is enforced: no constraint, cascade or orphan check. Admin uses it for pickers and related rows; `x-mantle-ref: media_assets` marks a media asset id. Declare a single-field index on the ref field when reverse lookups must stay bounded. On a Procedure input property the marker exposes a row action; see [Procedure](./procedure.md#uischema).
59
+ ### Index prefixes for paged Views
140
60
 
141
- ### `x-mcp-hint`
61
+ Only equality fixes an index prefix: `col = input.x`, `col = 'literal'` and an `= auth.uid()` scope or restrict. A user-field term (`region IN auth.user('region')`, as a `scope` or `restrict`) binds a set of values, so it never fixes a prefix, even when the caller holds one value or `{ all: true }`: the statement is prepared for a set, and an `ORDER BY` after that column would read and sort all of the caller's rows on every page. With `scope: "region IN auth.user('region')"`, `indexes: [[region, orderNo, id]]` and `ORDER BY orderNo`, generation refuses the View, names the bounded order and links here. The bounded ways:
142
62
 
143
- A free-form string that tells agents and Admin widgets how to render or produce a value. The grammar accepts any string; these values are conventional.
63
+ - `ORDER BY region, orderNo`, served by the same index: rows come back grouped by region. `region DESC, orderNo DESC` reads it backwards; on PostgreSQL confirm with `EXPLAIN` that no Sort remains. Every column added to the `ORDER BY` must be non-null and nameable in SQL; a `publishing` Schema field other than a user-field scope column can be null, and the `scope` owner column cannot be named, so the refusal then says this order is unavailable.
64
+ - A View input bound with equality, `WHERE region = input.region ORDER BY orderNo`: the input fixes the prefix, and the scope still applies. Every set-bound column before the ordered ones needs its own equality.
65
+ - For `{ all: true }` callers, an index on the equality-fixed columns, then the ordered columns, then `id`: `[orderNo, id]` here, `[tier, orderNo, id]` with `WHERE tier = input.tier`. It is not bounded for scoped callers, who scan the index and filter, and it does not help a View with any `restrict`, which [`{ all: true }` never lifts](view.md#restrict).
144
66
 
145
- | Value | Meaning |
146
- |---|---|
147
- | `markdown`, `richtext`, `code` | Text editor and authoring format. |
148
- | `media`, `media-image`, `media-video`, `media-file` | Media-shaped URL or asset reference (`isMediaMcpHint`). |
149
- | `money-minor` | Integer amount in minor currency units. |
150
- | `timestamp-ms` | Unix epoch milliseconds. |
151
- | `idempotency-key` | On a Procedure input: Admin generates and hides one UUID per form; other callers generate one and reuse it on retry. |
67
+ Declaring both indexes does not make one View bounded for every caller. System (trusted) reads drop scope terms, so a scope-first index such as `[owner, at]` is not a proved range scan for them.
152
68
 
153
- Do not use a hint for optimistic concurrency. The reserved Procedure input name `expectedVersion` is the OCC token (observed `entry.version` at read time). First-party Admin binds and hides it by that name. Schema `spec.schema.properties` must not declare it (`INVALID_MANIFEST_ENVELOPE`).
69
+ `uniqueIndexes` accept declared fields only, never native entry columns such as `authorId`. For per-member uniqueness, declare a required string `member` field, write `member: caller.subject` in a handler, and use `uniqueIndexes: [[member, orderNumber]]`; do not take `member` from client input.
154
70
 
155
- ### Root `readOnly: true`
71
+ Publishing fields may be NULL in drafts even when required, so they cannot be View paging keys. Store accepts `published_at` ordering, but View paging rejects it. Use `ORDER BY id`, or keep the business date in an operational Schema as an indexed, required non-null field. See [View paging](view.md#results-and-paging).
156
72
 
157
- `schema.readOnly: true` at the root marks a Procedure-managed collection. Staff MCP emits no `create_*` or `update_*` tool for it, and Admin's generic create, update, status change and delete return `CONFLICT` with the message that the Schema is read-only on generic authoring surfaces. Declared Views and Procedures (builtin or `ref`) keep working.
73
+ `checks` are restricted SQL expressions over the table's columns, emitted in initial DDL. Native databases enforce them; bare database errors are not automatically mapped to input-validation failures. Searchable fields must be plain string fields. SQLite/D1 emit FTS5 trigram tables and maintenance triggers; PostgreSQL uses ILIKE. Short SQLite terms use LIKE. Store search additionally matches exact id and combines with row policy.
158
74
 
159
- ## `uiSchema`
160
-
161
- Closed Admin-only roots: `fields`, `list`, `nav`. Nested keys are closed too. Unknown roots or nested keys are `SCHEMA_UI_INVALID`.
162
-
163
- | Key | Rule |
164
- |---|---|
165
- | `fields.<field>.widget` | Only `textarea`. The field must be a top-level property with a string type (`string` or `[string, null]`). |
166
- | `list.filterField` | Operational Schemas only. A declared property with a non-empty string `enum` that is the first field of some `indexes` or `uniqueIndexes` tuple. Admin renders the enum as sidebar links and list tabs. |
167
- | `list.primaryField` | Operational Schemas only. A non-empty top-level scalar property; rendered as the linked leading column. |
168
- | `list.columns` | Operational Schemas only. Top-level properties or native entry columns, no repeats and not repeating `primaryField`; structured values render as compact JSON. |
169
- | `nav.standalone` | Boolean. `true` also emits a main Admin Nav list entry with a **parent autocomplete filter**. It does not unfold: required `x-mantle-ref` children still compose under the parent. Omit or `false` means fold-only (discover via the parent-entry workbench). Rejected on top-level Schemas, `translates` children, and Schemas with no eligible required-ref parent. |
170
- | `nav.parentField` | Allowed only with `standalone: true`. Names a required `x-mantle-ref` field used as the parent filter. One eligible required ref is inferred; more than one requires an explicit `parentField`. Do not rely on property-order heuristics when multiple refs exist. |
171
-
172
- ```yaml
173
- uiSchema:
174
- list:
175
- primaryField: name
176
- columns: [status]
177
- nav:
178
- standalone: true
179
- parentField: organizationId
180
- ```
75
+ The runtime never creates, alters or checks tables. Initial DDL is for an empty database. Changed fields, checks, indexes and search DDL require [agent-owned native migrations](../concepts/runtime-and-adapters.md#schema-installation-and-migrations), including explicit data migration for destructive/type changes. Mantle drops nothing.
181
76
 
182
- Every violation is `SCHEMA_UI_INVALID`. Without `primaryField` and `columns`, Admin lists an operational collection with platform metadata only. `nav` is operational Admin navigation only — it does not change runtime, MCP, or publishing validation. Parent autocomplete coexists with `list.filterField` enum tabs as a separate control.
77
+ ## Admin uiSchema
183
78
 
184
- Keep implementation-detail children fold-only. Use `nav.standalone: true` when staff also need a cross-parent list; see the [inventory example](../../examples/cf-primitives-commerce-inventory.md).
79
+ A property marked `readOnly: true` in the JSON Schema is server-maintained (a counter, a total): Admin's generic create stores its `default` whatever the input says, Admin edits ignore it, and only Procedures (or server code through the Store) change it afterwards. JSON Schema defaults are applied by Admin's generic create only, not by the Store or the database: initial DDL emits no `DEFAULT` for a field, so server code through the Store and a SQL Procedure that inserts the row set the field themselves. A root `readOnly: true` makes the whole Schema read-only in Admin: a generic Admin write is refused with 403 `AUTH_DENIED` (not a 409 version conflict).
185
80
 
186
- ## Indexes
81
+ `default` does not make a column NOT NULL; `required` does (in an `operational` Schema). For a server-maintained value that is never NULL, list it in both, `required: [name, total]` with `total: {type: integer, readOnly: true, default: 0}`: initial DDL declares `total` NOT NULL, Store and View row types read it as `number` rather than `number | null`, Admin's create still fills the default when the client omits it, and the Store's insert type requires server code to pass it. Without `required` the column stays nullable, and an INSERT that omits it stores NULL. Adding `required` to an existing table is a [migration](../concepts/runtime-and-adapters.md#schema-installation-and-migrations): backfill NULLs, then add NOT NULL.
187
82
 
188
- `uniqueIndexes` and `indexes` are arrays of ordered field tuples. Shape errors are `INVALID_MANIFEST_ENVELOPE`; semantic errors are `SCHEMA_INDEX_INVALID` unless noted. Each index is an array of field names, even when it has one field; a bare string is rejected.
83
+ `fields.<name>.widget` selects a built-in control (`textarea`); `list.primaryField`, `list.columns` and enum `filterField` select list presentation (operational Schemas only; a publishing Schema's list shows its title field and status); `nav.parentField` chooses the parent a child folds under (required when two or more required `id` references exist) and `nav.standalone` lists the child in the sidebar; `nav.group/order/hidden` place it in the sidebar ([sidebar](../guides/native-admin.md#sidebar)). `list.columns` must not repeat `list.primaryField` or itself (`SCHEMA_UI_INVALID`). Generation validates these against declared fields/indexes. Components that render a field, cell or record aside are not manifest references: they live in `defineAdmin` ([customising Admin](../guides/native-admin.md#customising-admin)), and a manifest that still names one (`widget: <extension>/<contribution>`, `widget` `options`, `list.cells`, `panels`) is refused. JSON Schema root `schema.readOnly: true` disables generic Admin writes, not declared Procedures; `uiSchema.readOnly` is rejected with `SCHEMA_UI_INVALID`. `x-mantle-ref` relates a field to another Schema id or single-field unique field. It is not a foreign key: the database does not check that the referenced row exists, and deleting that row leaves the reference dangling. Check existence in the write (a JOIN or `EXISTS` in the Procedure) and guard deletes with `NOT EXISTS` ([SQL patterns](../guides/sql-patterns.md)).
189
84
 
190
- | Rule | Diagnostic |
191
- |---|---|
192
- | When any index is declared, `metadata.name` matches `/^[A-Za-z][A-Za-z0-9_.-]*$/`. | `SCHEMA_INDEX_INVALID` at `/metadata/name` |
193
- | Each tuple is a non-empty array of strings. | `INVALID_MANIFEST_ENVELOPE` (shape) or `SCHEMA_INDEX_INVALID` (empty) |
194
- | No field repeats within a tuple; field names match the same safe pattern. | `SCHEMA_INDEX_INVALID` |
195
- | `uniqueIndexes` fields are data properties. `indexes` fields may also be the native columns `id`, `status`, `version`, `createdAt`, `updatedAt`, `authorId`, which map to their `_mantle_*` columns. | `SCHEMA_INDEX_INVALID` |
196
- | Data fields are exact top-level keys of `properties`. | `UNIQUE_INDEX_FIELD_UNKNOWN` or `SCHEMA_INDEX_FIELD_UNKNOWN` |
197
- | Fields are indexable scalars: exactly one non-null type, optionally nullable. `string` maps to TEXT, `integer` and `boolean` to INTEGER, `number` to REAL. | `SCHEMA_INDEX_INVALID` |
198
- | No tuple repeats within a list; `indexes` does not repeat a `uniqueIndexes` tuple. | `SCHEMA_INDEX_INVALID` |
199
-
200
- On SQLite storage each Schema is a native table and every tuple becomes an
201
- index over its native field columns; queries benefit from a leftmost prefix.
202
-
203
- A public View over a `publishing` Schema is compiled with `status = published`
204
- whether or not the manifest writes it ([View surfaces](./view.md#surfaces)), so
205
- its hot path always starts with an equality on `status`. Lead the index with
206
- it, then the ordered field: `indexes: [[status, publishedAt]]`. A bare
207
- `[[publishedAt]]` does not serve that query on production SQLite (no planner
208
- statistics), which sorts every published row in a temporary B-tree instead
209
- (#962). Declare the index the query needs; Mantle does not derive one (ADR-0025).
210
- Unique indexes are also checked before every write; a conflicting row is
211
- `CONFLICT`. After the first deployment, adding, removing, reordering, or changing
212
- any `uniqueIndexes` tuple is destructive and requires rebuilding the instance
213
- and moving required data manually. Automatic deployment rejects the change.
214
-
215
- ## `searchableFields`
216
-
217
- An array of unique top-level string properties (`string` or `[string, null]`). Non-array or non-string entries are `INVALID_MANIFEST_ENVELOPE`; duplicates and non-string properties are `SCHEMA_SEARCH_INVALID`; unknown fields are `SCHEMA_SEARCH_FIELD_UNKNOWN`. The entry `id` is always searched. Substring search does not use `indexes`.
218
-
219
- ## Lifecycle
220
-
221
- `publishing` is the default state machine.
222
-
223
- | From | To |
224
- |---|---|
225
- | `draft` | `published`, `archived` |
226
- | `published` | `archived`, `draft` |
227
- | `archived` | `draft` |
228
-
229
- `operational` has no transitions. Entries are created with `status: published`, edited in place, and any publish, unpublish or archive request returns `CONFLICT`. Admin hides lifecycle controls; Staff MCP emits `create_record_<segment>` and `update_record_<segment>` instead of the draft tools. A builtin `archive` Procedure cannot target an operational Schema.
230
-
231
- Deleting a `published` entry of a publishing Schema is `CONFLICT` (unpublish first). Operational entries can be deleted in any status.
232
-
233
- ### Write-time locale gate
234
-
235
- Every authoring path (Admin, Staff MCP, builtin Procedures) runs the same guard after stamping, per request, reading the current site locales.
236
-
237
- | Condition | Result |
238
- |---|---|
239
- | Non-localized Schema and `data.locale` is present. | `INPUT_VALIDATION_FAILED` |
240
- | Localized Schema and `data.locale` missing or empty. | `INPUT_VALIDATION_FAILED` (skipped for partial draft saves; publish re-checks). |
241
- | Localized Schema and `data.locale` not in the site locales. | `INPUT_VALIDATION_FAILED` with the enabled locales as candidates. |
242
- | Site locales list is empty. | Locale membership is not checked. |
243
-
244
- Site locales are configured in [Site config](./site-config.md).
245
-
246
- ## TTL
247
-
248
- ```yaml
249
- spec:
250
- ttl: { field: expiresAt, expireAfterSeconds: 0 }
251
- schema:
252
- type: object
253
- properties:
254
- expiresAt: { type: string, format: date-time, nullable: true }
255
- ```
85
+ See [Admin](../guides/admin-ui.md) and [diagnostics](diagnostics.md).
256
86
 
257
- `field` must name one top-level `date-time` string property; `expireAfterSeconds` is finite and nonnegative. An entry expires when its timestamp plus the duration is **at or before** the current instant. Missing or null dates never expire. `SCHEMA_TTL_INVALID` rejects invalid policies.
87
+ ### Field scope
258
88
 
259
- Legacy values that SQLite cannot parse as dates also remain visible and are not swept; correct those rows before relying on TTL. New writes must pass the Schema's date-time validation.
89
+ `scope` is one predicate of terms joined by `AND`: at most one `<column> = auth.uid()` and any number of `<column> IN auth.user('<field>')`, for example `scope: "tenant = auth.uid() AND region IN auth.user('region')"`. Scoped columns are required, non-null, and lead an index. The scope protects every SQL relation, Store, REST/MCP and native Admin access.
260
90
 
261
- Expiry is logical first: Entry, declarative View, Admin, MCP and Web reads stop returning the row at the boundary, even before a sweep deletes it. A native SQL View cannot guarantee that filter and is rejected (`VIEW_TTL_NATIVE_UNSAFE`) while any Schema has TTL. A View over a TTL Schema cannot use shared caching (`VIEW_CACHE_INVALID`). Bun and D1 use the same SQLite predicate; other storage adapters must supply equivalent read filtering or reject the plan.
91
+ A caller whose value for a field is `{ all: true }` drops that field's term only; the other terms still apply. Generated SQL holds one statement per target and selects the form for each caller at run time; values are always bound parameters. Neither roles nor the admin layer widen a field scope or a translation parent's visibility. A Schema whose `x-mantle-ref` points to a field-scoped Schema must carry the same scope terms.
262
92
 
263
- TTL is currently rejected on either side of a `translates` relationship (`SCHEMA_TTL_TRANSLATION_UNSUPPORTED`), because a translation child could otherwise remain visible after its parent expires.
93
+ For inserts, one allowed partition autofills a missing value; multiple values require an explicit allowed partition, and missing/empty values fail with `AUTH_DENIED`. Callers holding `{ all: true }` and system callers always provide an explicit partition. A Procedure `INSERT … VALUES` follows the same rule for user callers, checked before any SQL runs: leave the partition column out to autofill a caller's single value, or take it from an input declared with the column's own type (`VALUES (input.region, …)`) or a matching literal, which must be inside the caller's set; any other expression there is refused. A Procedure that callers holding several values or `{ all: true }` use, such as an Admin create action, takes the partition as an optional input. `INSERT … SELECT` into a field-scoped Schema, and an insert into a Schema the target `restrict`s, run only for system callers, which this check does not cover: they name the partition themselves; use the scoped Store for user writes there. The partition is never writable through SET, including upsert and native Admin patch. An excluded id behaves like a missing row: reads return not found; Store update/delete and row-classified Procedure UPDATE/DELETE affecting zero rows return HTTP 409 (`CONFLICT`). Native Admin's visible-row pre-read returns 404 for either id. SQLite binds a JSON array; PostgreSQL binds a quoted, escaped array. Public Views over field scope warn that anonymous callers are refused.
264
94
 
265
- Physical cleanup is **explicit**. `runtime.sweepExpired({ collection: "events", limit: 50 })` previews one page; add `delete: true` to remove it. Follow `nextCursor` until absent. The limit is 1–100, `scanned` counts expired candidates and `removed` counts successful deletes. A failure throws and the previous cursor is safe to retry. Ref Procedures can call `ctx.sweepExpired`; a Cloudflare schedule may invoke such a Procedure. The sweep does not fire entry lifecycle hooks: expiration already changed logical visibility, and the sweep only reclaims storage (ADR-0028).
95
+ #### References to a scoped Schema
266
96
 
267
- The Developer Console shows declared TTL policies. It does not infer sweep history from a policy; a scheduled Procedure can return `scanned` and `removed` counts to include them in its run observation.
97
+ A non-null `x-mantle-ref` value that points to a scoped Schema (field or owner scope) must name a row of that Schema the caller can read, matched on `id` or on the object form's `field`, and that row must have the same value as the child for every scope field the two share (`ADR-0034`: a reference between scoped Schemas stays inside one owner or partition). A Store insert or update, and a Procedure `INSERT … VALUES`, `UPDATE … SET` or `DO UPDATE SET`, check it in the same statement; a missing, unreadable or other-partition parent behaves like a missing row: a single-row statement returns HTTP 409 (`CONFLICT`), and an `ON CONFLICT` insert or a set update writes nothing for that row. A caller holding several values or `{ all: true }` can still not point a child in one partition at a parent in another. `INSERT … SELECT` that writes such a reference runs only for system callers. A caller's `UPDATE … SET` or `DO UPDATE SET` of such a reference takes no subquery, which could read the parent's columns as its own. Trusted writes (system callers, `runtime.store`) are not checked, like the other row rules, and native Admin's generic create and patch do not check references yet. NULL is always allowed; deleting a parent does not touch its children.
268
98
 
269
- Adding or shortening TTL on an existing Schema immediately changes **read visibility**, but never starts a deletion job. Preview a sweep and review its counts before requesting `delete: true`. Keep a backup when changing the policy on populated data. Physical unique constraints still see expired rows until cleanup, so a reused unique value may conflict before the sweep.
99
+ ## Reserved entry columns
270
100
 
271
- ## Source
101
+ Every Schema row has native columns that a Schema must not declare as data properties: `id`, `status`, `version`,
102
+ `createdAt`, `updatedAt` and `authorId` (SQL `id`, `status`, `version`, `created_at`, `updated_at`, `author_id`).
103
+ Use a domain name for your own fields (`requestStatus`, `submittedAt`). Views read native columns and `spec.indexes`
104
+ can index them without declaring them; `uniqueIndexes` cannot include them. `status` and `published_at` belong to
105
+ the publishing lifecycle; `version` backs `expectedVersion`; `author_id` is the verified creator used by
106
+ `restrict: { <schema>: "author_id = auth.uid()" }`.
272
107
 
273
- - [`packages/mantle-spec/src/domain/model/ManifestGrammar.ts`](../../../packages/mantle-spec/src/domain/model/ManifestGrammar.ts)
274
- - [`packages/mantle-spec/src/domain/service/ManifestParser.ts`](../../../packages/mantle-spec/src/domain/service/ManifestParser.ts)
275
- - [`packages/mantle-spec/src/domain/service/ManifestGraphValidator.ts`](../../../packages/mantle-spec/src/domain/service/ManifestGraphValidator.ts)
276
- - [`packages/mantle-spec/src/domain/service/CrossSchemaChecker.ts`](../../../packages/mantle-spec/src/domain/service/CrossSchemaChecker.ts)
277
- - [`packages/mantle-spec/src/domain/service/SchemaIndexChecker.ts`](../../../packages/mantle-spec/src/domain/service/SchemaIndexChecker.ts)
278
- - [`packages/mantle-spec/src/domain/service/SchemaSearchChecker.ts`](../../../packages/mantle-spec/src/domain/service/SchemaSearchChecker.ts)
279
- - [`packages/mantle-spec/src/domain/service/SchemaAdminUiChecker.ts`](../../../packages/mantle-spec/src/domain/service/SchemaAdminUiChecker.ts)
280
- - [`packages/mantle-spec/src/domain/service/LifecycleStateMachine.ts`](../../../packages/mantle-spec/src/domain/service/LifecycleStateMachine.ts)
281
- - [`packages/mantle-spec/src/domain/service/JsonSchemaToZod.ts`](../../../packages/mantle-spec/src/domain/service/JsonSchemaToZod.ts)
282
- - [`packages/mantle-runtime/src/domain/service/BuiltinProjector.ts`](../../../packages/mantle-runtime/src/domain/service/BuiltinProjector.ts)
283
- - [`packages/mantle-runtime/src/domain/service/io/EntryWriteGuard.ts`](../../../packages/mantle-runtime/src/domain/service/io/EntryWriteGuard.ts)
284
- - [`packages/mantle-runtime/src/domain/service/io/EntryDeleteGuard.ts`](../../../packages/mantle-runtime/src/domain/service/io/EntryDeleteGuard.ts)
285
- - [`packages/mantle-runtime/src/infrastructure/mcp/McpToolCatalog.ts`](../../../packages/mantle-runtime/src/infrastructure/mcp/McpToolCatalog.ts)
286
- - [`packages/mantle-admin/src/mountMantleAdmin.ts`](../../../packages/mantle-admin/src/mountMantleAdmin.ts)
108
+ A seed or other SQL that inserts rows outside Mantle (`wrangler d1 execute --file seed.sql`) sets the native columns
109
+ itself: `id` (text, unique) and `created_at` (integer microseconds since the Unix epoch, e.g. `1767225600000000`);
110
+ `updated_at` and `version` have defaults. Procedures and the Store fill them for you.