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

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 (104) 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/docs/adapter-guide.md +20 -24
  9. package/docs/adr/0008-structured-diagnostic-shape.md +7 -2
  10. package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +100 -0
  11. package/docs/adr/0018-core-starters-repository-boundary.md +3 -0
  12. package/docs/adr/0019-sealed-manifest-runtime-pipeline.md +37 -1
  13. package/docs/adr/0020-builtin-handler-contracts-and-matched-upsert.md +199 -0
  14. package/docs/adr/0021-retire-starter-scaffolding.md +30 -0
  15. package/docs/adr/0022-caller-observed-version-occ.md +212 -0
  16. package/docs/adr/0023-port-failure-contract.md +69 -0
  17. package/docs/adr/README.md +18 -3
  18. package/docs/adr/adr-lite-803-request-diagnostics.md +38 -0
  19. package/docs/adr/adr-lite-808-route-readiness.md +47 -0
  20. package/docs/adr/adr-lite-809-bounded-public-content.md +71 -0
  21. package/docs/adr/adr-lite-812-native-parity.md +149 -0
  22. package/docs/adr/adr-lite-823-home-statistics.md +63 -0
  23. package/docs/adr/adr-lite-842-mcp-authoring.md +30 -0
  24. package/docs/adr/adr-lite-861-admin-webmcp.md +42 -0
  25. package/docs/adr/adr-lite-909-admin-ui-kit.md +37 -0
  26. package/docs/api-mcp-authorization.md +3 -664
  27. package/docs/auth-hosting-model.md +4 -4
  28. package/docs/cloudflare-low-level-composition.md +3 -104
  29. package/docs/deferred-lifecycle-queues.md +2 -243
  30. package/docs/design-atoms.md +16 -796
  31. package/docs/direct-authoring.md +5 -0
  32. package/docs/examples/minimal-worker/README.md +37 -0
  33. package/docs/examples/minimal-worker/manifests/site.yaml +25 -0
  34. package/docs/examples/minimal-worker/package.json +26 -0
  35. package/docs/examples/minimal-worker/smoke.mjs +23 -0
  36. package/docs/examples/minimal-worker/src/index.ts +4 -0
  37. package/docs/examples/minimal-worker/tsconfig.json +17 -0
  38. package/docs/examples/minimal-worker/wrangler.jsonc +22 -0
  39. package/docs/handbook/cloudflare/authentication.md +167 -0
  40. package/docs/handbook/cloudflare/bindings.md +233 -0
  41. package/docs/handbook/cloudflare/conventional-worker.md +162 -0
  42. package/docs/handbook/cloudflare/deferred-hooks-queues.md +171 -0
  43. package/docs/handbook/cloudflare/deploy-and-operate.md +98 -0
  44. package/docs/handbook/cloudflare/low-level-composition.md +169 -0
  45. package/docs/handbook/cloudflare/media-r2.md +216 -0
  46. package/docs/handbook/cloudflare/public-web.md +144 -0
  47. package/docs/handbook/concepts/authorization.md +116 -0
  48. package/docs/handbook/concepts/four-atoms.md +173 -0
  49. package/docs/handbook/concepts/lifecycle-and-locales.md +142 -0
  50. package/docs/handbook/concepts/mcp-and-agents.md +109 -0
  51. package/docs/handbook/concepts/procedures-and-triggers.md +221 -0
  52. package/docs/handbook/concepts/runtime-and-adapters.md +177 -0
  53. package/docs/handbook/concepts/views.md +183 -0
  54. package/docs/handbook/examples/commerce-transaction.md +813 -0
  55. package/docs/handbook/examples/guarded-api.md +427 -0
  56. package/docs/handbook/examples/intake-form.md +319 -0
  57. package/docs/handbook/examples/legal-documents.md +218 -0
  58. package/docs/handbook/examples/procurement-approvals.md +240 -0
  59. package/docs/handbook/examples/publication.md +240 -0
  60. package/docs/handbook/examples/reservation.md +220 -0
  61. package/docs/handbook/navigation.json +63 -0
  62. package/docs/handbook/reference/authorization.md +295 -0
  63. package/docs/handbook/reference/diagnostics.md +183 -0
  64. package/docs/handbook/reference/manifest.md +132 -0
  65. package/docs/handbook/reference/procedure.md +263 -0
  66. package/docs/handbook/reference/schema.md +247 -0
  67. package/docs/handbook/reference/site-config.md +233 -0
  68. package/docs/handbook/reference/surface.md +207 -0
  69. package/docs/handbook/reference/trigger.md +193 -0
  70. package/docs/handbook/reference/view.md +256 -0
  71. package/docs/handbook/start/project-and-cli.md +122 -0
  72. package/docs/handbook/start/quickstart-worker.md +193 -0
  73. package/docs/labels.md +3 -1
  74. package/docs/media-uploads.md +3 -184
  75. package/docs/migration-0.1.2.md +34 -1
  76. package/docs/performance-harness.md +125 -8
  77. package/docs/release-process.md +85 -231
  78. package/docs/schema-indexes.md +3 -180
  79. package/docs/sealed-pipeline-ownership.md +5 -4
  80. package/docs/spec-only-host-adoption.md +158 -0
  81. package/docs/transaction-patterns.md +5 -0
  82. package/package.json +21 -25
  83. package/skills/README.md +4 -4
  84. package/skills/develop/SKILL.md +23 -28
  85. package/skills/install/SKILL.md +55 -147
  86. package/skills/provision/SKILL.md +4 -3
  87. package/skills/theme/SKILL.md +6 -6
  88. package/skills/update/SKILL.md +32 -68
  89. package/dist/cli/create.d.ts +0 -2
  90. package/dist/cli/create.d.ts.map +0 -1
  91. package/dist/cli/create.js +0 -243
  92. package/dist/cli/create.js.map +0 -1
  93. package/dist/cli/update.d.ts +0 -2
  94. package/dist/cli/update.d.ts.map +0 -1
  95. package/dist/cli/update.js +0 -413
  96. package/dist/cli/update.js.map +0 -1
  97. package/dist/provision/renderProvisionBundle.d.ts +0 -70
  98. package/dist/provision/renderProvisionBundle.d.ts.map +0 -1
  99. package/dist/provision/renderProvisionBundle.js +0 -367
  100. package/dist/provision/renderProvisionBundle.js.map +0 -1
  101. package/dist/provision.d.ts +0 -2
  102. package/dist/provision.d.ts.map +0 -1
  103. package/dist/provision.js +0 -2
  104. package/dist/provision.js.map +0 -1
@@ -0,0 +1,71 @@
1
+ # ADR-lite: bounded public content and complete discovery
2
+
3
+ Status: implemented for #809; combined deployment measurements tracked in #812.
4
+ Context: ADR-0010 translation joins, ADR-0019 sealed semantic storage, #792 Web
5
+ transport/cache ownership. No manifest keys or remote Web SDK are introduced.
6
+
7
+ ## Decision
8
+
9
+ Add the semantic `EntryReader.readPublishedPage` operation instead of silently
10
+ capping generic `readPublished`. Forward pages sort by updatedAt and id descending,
11
+ with default 50 / maximum 2,000 rows and a 1-MiB data-JSON budget. A single larger
12
+ entry remains readable and advances the cursor. This budget covers the selected
13
+ canonical data, excluding envelope bytes, joined parents, media and consumer HTML.
14
+ SQLite uses indexed, bounded candidates, a running byte sum and lookahead before
15
+ transfer to Worker memory. Exact locale plus shared entries are merged in SQL.
16
+ Selected data fields retain JSON types and use one bound JSON field list, including
17
+ for projections larger than D1's ordinary bind or SQL-function argument limits.
18
+
19
+ The optional Web use cases return an explicit page object. Cloudflare mounts
20
+ publish `Link: rel="next"` and map cursors to URLs. Web passes `nextPageUrl` to
21
+ the list template; the host renders accessible navigation with its own language
22
+ and design. The adapter does not rewrite template HTML. Existing templates must
23
+ adopt this field to retain visible continuation. Web-owned llms composition
24
+ retains its body link. An empty intermediate/final llms page remains traversable.
25
+ Root llms reads each canonical page once and expands shared entries per locale
26
+ without repeated canonical reads. Unknown/unmapped/no-content rows consume their
27
+ place in the page; they do not prevent reaching later eligible rows.
28
+
29
+ Sitemap parts project path metadata and default to 2,000 entries, expanding shared
30
+ routes per locale. The index walks the same metadata-page boundaries as the parts,
31
+ so a byte-limited part cannot cause skipped URLs. Small sites keep a single urlset.
32
+ Additional routes appear only in the first part. A custom path resolver must declare
33
+ its required data fields to obtain projection; otherwise full bounded data remains
34
+ available. Protocol limits fail explicitly instead of silently truncating URLs.
35
+
36
+ Translation lists request only the newest published parent per join value. Storage
37
+ ranks matching IDs before loading their bodies, preventing duplicate historical
38
+ parents from multiplying transferred rows. Missing/draft parents leave the child
39
+ unchanged. Child data still wins and media resolution remains one batch per page.
40
+
41
+ ## Limits and alternatives
42
+
43
+ Sitemap index generation is O(N) metadata work on an origin MISS. It retains one
44
+ page and the index's URL list rather than all entry bodies; the protocol permits
45
+ at most 50,000 parts. Persisted generation/part boundaries would require an explicit
46
+ publication/invalidation owner and are deferred until index traffic justifies it.
47
+ A hard `LIMIT 500` would lose discovery URLs and is rejected. Offset pages would
48
+ make deep traversal grow with depth and are rejected. Entry caching would leave
49
+ the cold materialization spike and stale-state questions unresolved.
50
+
51
+ Pages reflect live canonical state, not a cross-request snapshot: publishing or
52
+ changing sort keys during a crawl can move entries between pages. Browser-local
53
+ IndexedDB shares the semantic cursor and output budget but still scans a local
54
+ collection. Parent/media data and consumer template expansion have separate costs;
55
+ there is no promise that arbitrary consumer rendering fits 1 MiB.
56
+
57
+ ## Verification
58
+
59
+ Real SQLite tests walk the 18 combinations of 100/10,000/50,000 rows, 64 B/4 KiB
60
+ body and 1/3/10 locales, comparing complete llms/sitemap URL sets. List transfer is
61
+ 21 rows at limit 20 in every case; 50,000 mixed rows and 10 locales retain all
62
+ 275,000 URLs. Tests cover tied sort keys, >1-MiB entries, JSON projection types,
63
+ missing projected keys, parent duplicates/missing/drafts, child overrides, media
64
+ batching and persistence-field privacy. HTTP tests walk visible continuations,
65
+ empty final pages, sitemap indexes and staff-only preview behavior. The portable
66
+ storage conformance suite checks new semantics across adapters.
67
+
68
+ Wrangler-local records native D1 query/row work for list, llms and sitemap alongside
69
+ existing readiness, View, Procedure and Admin gates. Node traversal CPU/RSS includes
70
+ fixture/assertion costs and is not reported as Worker CPU. Combined #812 evidence
71
+ will supply Worker CPU, heap, cache HIT/MISS, remote controls and placement results.
@@ -0,0 +1,149 @@
1
+ # ADR-lite: native and full-facade performance evidence (#812)
2
+
3
+ Status: implemented; local gates passed. The deployment report and per-block
4
+ budget verdicts are maintained in [PR #821](https://github.com/aotter/mantle/pull/821).
5
+
6
+ The existing HTTP harness now records TTFB and full-body timing separately,
7
+ response bytes, and bounded concurrent arrivals. `pnpm bench:wrangler` keeps the
8
+ old row/query regressions and adds a native smoke matrix. `pnpm bench:parity`
9
+ runs the larger matrix, real Better Auth PKCE/OTP/consent/JWT/DPoP issuance,
10
+ revocation/role/replay denials, prepared D1 across fresh workerd processes, and
11
+ R2 transfers. No token, cookie, proof, user ID, SQL, argument or object key enters
12
+ the diagnostic record. Only the secret-protected synthetic fixture has control
13
+ endpoints; never bind it to a consumer database or bucket.
14
+
15
+ ## Controls and boundaries
16
+
17
+ | Layer | Work |
18
+ |---|---|
19
+ | F0 | Fixed fetch response; standalone `floor-worker.ts` measures module/bundle floor. R2 F0 performs HEAD only. |
20
+ | F1 | Hono + native SQL and the same public payload; no authentication. |
21
+ | F2 | Native Worker, shared real Auth/session/consent/fresh-role/DPoP checks, SQL compiler and validators, response envelope. MCP shares protocol dispatch and View execution; unmeasured mutations fail closed. |
22
+ | M | Full `createMantleWorker`, same sealed plan, bindings, data and security policy. R2 uses the production storage commit adapter directly. |
23
+
24
+ Protected parity is F2/M. The View and catalog response bodies must match, drafts
25
+ stay private, and auth/protocol errors must fail correctly. Procedure input errors
26
+ compare status/code, not complete diagnostic wording. Admin/Web are facade coverage,
27
+ not a matched-native claim. R2 measures native stream metadata commits and failure/
28
+ retry; D1 MediaAsset publication is covered by the separate #810 integration test.
29
+ The shared comparison bundle intentionally keeps dependencies/configuration equal;
30
+ it cannot measure the difference between standalone application bundle sizes.
31
+
32
+ The planner runs outside workerd. Route/Schema/View axes each use 1/10/100/1,000;
33
+ extra Schemas are unindexed to keep the index-count axis fixed. D1 has a 100-column
34
+ limit, including generated index columns, so this is not a claim that 1,000 indexed
35
+ Schemas fit one entries table. Body/row axes use 64 B/4 KiB and 100/10,000/50,000;
36
+ locales use 1/3/10, MCP client concurrency uses 1/4/8, R2 uses 1/3/12 variants at
37
+ 1/64/256 KiB. Actual simultaneous arrivals can be below client concurrency. The remote fleet
38
+ can add isolates during a batch. A request is repeat-in-isolate only after that
39
+ exact workload previously completed there; overlapping first arrivals stay in
40
+ the first-for-workload cohort. Two global warmups alone cannot prove a warm fleet.
41
+ First requests retain their raw records and a bounded extra-six-statement setup
42
+ allowance; repeat MCP requests must meet the exact two/three/four-statement gate.
43
+ Parity summaries use repeat cohorts; first-for-workload does not necessarily mean
44
+ cold module startup (another workload may already have used that isolate).
45
+
46
+ ## Stable gates and measured signals
47
+
48
+ - Indexed public View: one statement and at most 100 available rows read at every
49
+ tested data size. MCP catalog: two statements (grant + fresh role), one KV GET;
50
+ View: three statements with Bearer, four with native DPoP replay reservation.
51
+ - Selected Trigger: four segment lookups at every route count in the portable
52
+ regression; native last-route requests retain one statement at 1,000 routes.
53
+ - Public HTML/llms: two warm statements and less than 1 MiB selected JSON. Sitemap
54
+ index remains explicit O(N) metadata work to enumerate complete part links.
55
+ - R2: exactly N GET + N PUT, known full-body bytes, at most three transfers in
56
+ flight; a first-batch failure starts no later batch and a retry succeeds.
57
+ - Fixture HTTP bodies at most 2 MiB; inspector heap after each batch at most
58
+ 96 MiB. This is an observed JS heap ceiling, not instantaneous peak memory or
59
+ retained-after-GC heap. Custom application templates retain their own limits.
60
+
61
+ The default fixture bundle gate is 4,500 KiB raw / 800 KiB gzip (measured
62
+ 3,699.93 / 647.98 KiB). The standalone F0 is 0.52 / 0.34 KiB; a 1,000-route
63
+ fixture is 4,051.18 / 668.60 KiB. Larger manifest-axis builds are reported
64
+ separately. Module startup profiles are a local diagnostic; actual deployed
65
+ startup must remain below the provider limit and is recorded during acceptance.
66
+
67
+ No cross-machine latency gate is used. CDP batch samples estimate local active JS
68
+ (including warmup); they are not per-request or billing CPU. Native Tail CPU/wall
69
+ are correlated by random request ID only in remote runs; unavailable timing stays
70
+ null. D1 metadata sums cover only `metadataStatements`; native Auth `.first()` does
71
+ not return rows/duration, and zero cannot substitute for that missing coverage.
72
+
73
+ The 2026-09-08 full local run contained 2,697 measured requests / 144 cases, no
74
+ unexpected HTTP status, max response 84,185 B, and max observed heap 67,103,480 B.
75
+ The observed F2/M p50 full-body delta for the 50k-row/4KiB View was -0.347 ms
76
+ (95% within-run bootstrap interval [-0.727, 0.128]); MCP catalog +0.903 ms
77
+ [0.470, 1.070]; Bearer MCP View -0.578 ms [-1.235, 0.329]. These are localhost
78
+ measurements, not a remote parity conclusion. Ten orthogonal route/Schema/View
79
+ runs and both extra locale runs also passed. Self-review corrected a fixture that
80
+ accidentally scaled indexes with Schemas, an English-only page assertion in the
81
+ multilingual fixture, and missing D1 metadata incorrectly summarized as zero.
82
+
83
+ ## Remote difference budget (calibrated 2026-09-08)
84
+
85
+ The first complete off-a block (05:44:20–05:57:16 UTC, SDK 1798e78) contains
86
+ 1,385 requests with 100% native CPU coverage, 46 first-for-workload arrivals and
87
+ no unexpected status failures. Public cache returned MISS then HIT; the HIT
88
+ had no invocation record. Warm F2/M CPU medians match at 0 ms health, 2 ms View,
89
+ 1 ms Procedure, 2 ms MCP catalog and 3 ms Bearer MCP View. DPoP medians differ
90
+ by 0–1 ms; the largest within-run CPU delta upper interval is 2 ms. One hundred
91
+ requests per layer/diagnostics mode measure roughly +1 ms median CPU for the
92
+ collector itself on both layers. This is native millisecond-resolution telemetry.
93
+
94
+ Freeze this initial budget before evaluating the on-a/off-b/on-b blocks:
95
+
96
+ - At least 20 repeat-in-isolate samples per layer, equivalent successful payloads
97
+ and current authorization checks; expected denial cases are functional gates.
98
+ - Upper 95% bootstrap interval for M minus F2 median platform CPU: at most 2 ms.
99
+ - Upper 95% bootstrap interval for M minus F2 median full-body latency: at most
100
+ max(15 ms, 5% of the paired F2 median). Compare consistent placement contexts;
101
+ report changes in ingress/execution placement separately.
102
+ - Exact warm statement/binding budgets and zero unexpected outcomes still apply.
103
+ Latency/CPU differences are a matched deployment acceptance budget, not an
104
+ absolute cross-machine CI timer gate. First-for-workload records stay visible;
105
+ the budget makes no blanket claim about cold setup or all native workloads.
106
+
107
+ ## Reproduction and remote acceptance
108
+
109
+ Run from the repository root with built workspace dependencies:
110
+
111
+ ```sh
112
+ pnpm bench:wrangler
113
+ pnpm bench:parity
114
+ BENCH_ROUTES=1000 BENCH_CASES=scaling pnpm bench:parity
115
+ BENCH_SCHEMAS=1000 BENCH_CASES=scaling pnpm bench:parity
116
+ BENCH_VIEWS=1000 BENCH_CASES=scaling pnpm bench:parity
117
+ BENCH_LOCALES=en,fr,de BENCH_QUICK=1 pnpm bench:parity
118
+ node scripts/summarize-wrangler-parity.mjs /path/to/report.json
119
+ ```
120
+
121
+ For remote acceptance, provision dedicated synthetic D1/KV (R2 when enabled),
122
+ put a random 32+ character BENCHMARK_KEY secret, and deploy the fixture with
123
+ BENCH_REMOTE_RECORDS=1. Run with BENCH_ORIGIN, BENCHMARK_KEY, BENCH_ACCOUNT_ID,
124
+ BENCH_PROFILE_NAME, BENCH_BLOCK and BENCH_PLACEMENT in the process environment.
125
+ The runner uses Wrangler's existing named-profile authentication to open the
126
+ same native trace-v1 API used by `wrangler tail`. It retains only the nonce-
127
+ correlated diagnostic fields and native CPU/wall timing in memory, never request
128
+ headers/body/URL, credentials or unrelated logs. The tail session is deleted at
129
+ completion. No paid Tail Worker, sink database writes or elevated log API token
130
+ is needed. Off-mode records also correlate platform CPU to measure overhead.
131
+
132
+ PHSU has no R2 subscription; its remote run uses BENCH_SKIP_R2=1. R2 coverage
133
+ comes from native workerd, with no remote R2 latency claim. A paid Tail Worker
134
+ attempt was rejected by the provider, then replaced by the verified real-time API.
135
+
136
+ Alternate off/on/off/on deployment blocks and BENCH_ORDER=reverse for the second
137
+ pair. Record actual placement status, request `cf-placement` when supplied,
138
+ ingress colo, deployment version, SDK/Wrangler/compatibility date, sampling window
139
+ and errors. Origin timings force private/no-store; a separate probe requires a
140
+ real public MISS followed by HIT with no invocation record. Local runs never
141
+ invent HITs. A deployed Worker with existing D1 is labeled deployment-first.
142
+
143
+ Use `wrangler deploy --dry-run --outfile <bundle>` followed by
144
+ `wrangler check startup --worker <bundle> --outfile <profile>` for module startup.
145
+ Record standalone F0, the full fixture and the actual packed consumer separately.
146
+ Set the remote F2/M CPU/latency difference budget after collecting the baseline,
147
+ then evaluate repeated blocks with bootstrap intervals, explaining shared-host
148
+ and cross-request correlation. Smart Placement provisioning belongs to #803;
149
+ INSUFFICIENT_INVOCATIONS is not evidence of a placement latency improvement.
@@ -0,0 +1,63 @@
1
+ # ADR-lite: collection creation statistics on Admin home
2
+
3
+ Status: proposed with #823; implementation stays in an unmerged demo PR.
4
+ Context: ADR-0019 semantic storage and optional Admin composition.
5
+
6
+ Add one optional `EntryReader.readCreationStatistics` read. SQLite/D1 implements
7
+ it; custom adapters without it return an explicit unavailable state in Admin.
8
+ The staff guard runs before storage access, and successful responses are private,
9
+ no-store. The endpoint accepts only primary, visible collections and four range
10
+ presets. No manifest keys, generic aggregation language or new cache port.
11
+
12
+ Each card independently persists its range and interval/cumulative mode in
13
+ `cms.preference.collection-statistics.<collection>`. Only preferences enter
14
+ localStorage. The chart and CSV describe current retained rows by native
15
+ `createdAt`, all statuses, with current `uiSchema.list.filterField` classification.
16
+ Unknown values share an Other series. Deleted rows are absent: these are creation
17
+ cohorts of retained rows, not an event log or historical inventory. Cumulative
18
+ means a prefix sum inside the selected range, starting from zero.
19
+
20
+ Ranges are 1h/5m, 24h/1h, 7d/6h and 20d/1d. Every interval is half-open; the last
21
+ ends at the observation time. CSV uses ISO UTC bounds while chart labels use the
22
+ browser's timezone. SVG steps preserve exact bucket extents without interpolation.
23
+ The toolbar download exports the current card's mode, current total and series;
24
+ CSV cells are quoted and formula-shaped headers are neutralized.
25
+
26
+ ## Aggregation and freshness
27
+
28
+ A single SQL statement returns a total and sparse grouped counts from one SQLite
29
+ snapshot. `entries(collection, created_at)` is prepared by canonical migration
30
+ 0008. The range branch searches the index, and the total branch counts index
31
+ entries. Payload JSON stays in the database; only count rows reach the Worker.
32
+
33
+ The existing Cloudflare KV decorator caches MCP site configuration, not entry
34
+ queries. Reusing that key/projection would mix unrelated data and mutation
35
+ ownership. Direct aggregation is sufficient for this demo: Wrangler-local with
36
+ 10,000 rows returned 897 bytes with one statement, 30,002 engine rows read and
37
+ p50/p95 of 4.26/5.80 ms (10 samples). A real SQLite test also aggregates 50,000
38
+ 4-KiB rows into at most 40 count rows / 4 KiB and verifies immediate updates and
39
+ deletes. These are local measurements, not remote latency guarantees.
40
+
41
+ There is no server statistics cache to evict or repopulate after a racing write.
42
+ Every Admin/MCP/Procedure committed write is visible on the next read, including
43
+ subtype updates and deletes. React Query data stays in memory, becomes stale
44
+ immediately, and refetches on mount/focus and every 60 seconds while the home is
45
+ active. Successful UI mutations invalidate its common statistics query prefix.
46
+ Changing only cumulative mode reuses the same count data without another query.
47
+
48
+ `ponytail:` exact totals still take O(N) index work and filtered time ranges may
49
+ read JSON for subtype grouping; returned bytes are bounded by bucket/enum count,
50
+ not row count. If measured production read volume makes this expensive, add a
51
+ transactionally maintained collection revision/projection and revision-keyed KV
52
+ snapshots. Plain KV delete-after-write is insufficient because eventual
53
+ consistency and racing miss fills can serve old aggregates. No cron, event store,
54
+ generic cache framework or eager write-through aggregate is justified here.
55
+
56
+ ## Verification
57
+
58
+ Runtime SQLite tests cover lower/upper edges, unknown subtype, collection
59
+ isolation, zero rows, edits/deletes, invalid windows, range index use and 50k rows.
60
+ Admin tests cover 401/403 before storage, invalid collection/range (including
61
+ prototype names), all presets, no-store, and unsupported adapters. UI tests cover
62
+ all preference combinations, zero filling, stacking, prefix sums and CSV safety.
63
+ Browser QA covers independent per-card preferences, reload, both themes and CSV.
@@ -0,0 +1,30 @@
1
+ # ADR-lite #842: Applicable generic MCP authoring
2
+
3
+ Status: Accepted for implementation following maintainer approval.
4
+
5
+ The staff catalog and dispatcher remain shared by remote MCP and Admin
6
+ WebMCP (ADR-0014, ADR-0019, ADR-lite-861). No new manifest switch or tool
7
+ registry is introduced. Adapters retain current staff-role verification;
8
+ declared Procedures and Views retain their own authorization and guards.
9
+
10
+ Generic lifecycle tools are offered only when at least one writable content
11
+ Schema exists. Delete is offered only when a writable Schema exists. Read
12
+ tools list actual collection names, lifecycle, searchable and sortable fields.
13
+ Root readOnly remains the existing way to require Procedure-owned writes;
14
+ declaring a Procedure alone does not disable normal authoring.
15
+
16
+ Discovery is not enforcement: the dispatcher rejects absent catalog names,
17
+ checks the target row for readOnly and lifecycle suitability, and binds
18
+ per-collection updates to their declared collection before mutation. Unsupported
19
+ lifecycle calls return CONFLICT with an explicit reason; wrong-collection IDs
20
+ return NOT_FOUND. Existing status/OCC checks remain in the use cases.
21
+ Generic staff tools also apply Admin's rank table at `tools/call`:
22
+ contributor may create/update drafts; editor+ is required for lifecycle,
23
+ delete, media, and operational record tools. Declared Procedures keep their
24
+ own `requires` predicates. `tools/list` may still show editor tools to
25
+ contributors; a guessed call is `AUTH_DENIED`.
26
+
27
+ Compatibility: operational-only and read-only sites lose unusable generic
28
+ tools. Clients must rediscover tools rather than retaining a global tool list.
29
+ Mixed sites must choose a collection listed in the tool description. Public
30
+ catalogs remain only declared capabilities and gain no collection metadata.
@@ -0,0 +1,42 @@
1
+ # ADR-lite #861: Staff MCP through the Admin session
2
+
3
+ Status: Accepted for implementation following maintainer approval.
4
+
5
+ Admin WebMCP uses the canonical staff MCP catalog and JSON-RPC dispatcher.
6
+ `GET /admin/api/webmcp` supplies the same tool definitions plus UI route hints;
7
+ `POST /admin/api/mcp` carries MCP requests using the current Admin session.
8
+ Both endpoints check the current mutable staff role. POST retains Admin's
9
+ cross-origin mutation rejection and body limit. Procedure predicates still
10
+ see a session credential, never a fabricated OAuth scope. Public/member MCP
11
+ capabilities and HTTP-only staff procedures are not added to this catalog.
12
+ This extends ADR-0014/0019 without changing manifest grammar.
13
+
14
+ Descriptions, input schemas, OCC and error diagnostics come from the existing
15
+ MCP catalog/dispatcher. Media tools appear only with media storage and declared
16
+ purposes. Agents PUT binaries directly to the authorized upload URLs between
17
+ create_media_upload and commit_media_upload; WebMCP carries no binary payload.
18
+
19
+ Admin owns two UI-only tools: admin_get_context and admin_navigate. Successful
20
+ operations invalidate query data and navigate when a known result target is
21
+ available. Unknown custom operations stay on the current page. Failure never
22
+ triggers navigation or an automatic mutation retry. Navigation input must be
23
+ an Admin page, not an external URL or API/auth path.
24
+
25
+ The green indicator appears after document.modelContext registration succeeds.
26
+ Its dialog shows the registered tool catalog and uses Admin i18n with the
27
+ established English fallback. The prompt tells the agent to inspect the catalog;
28
+ tool descriptions own operation-specific guidance. Developer interface docs
29
+ show the same live catalog. The initial translations include English,
30
+ Traditional Chinese and Simplified Chinese.
31
+ Registration uses AbortSignal lifetime cleanup. Browsers without WebMCP retain
32
+ the existing UI. The browser API is feature-detected, not polyfilled.
33
+
34
+ Only the explicitly marked, same-origin sandbox preview accepts the parent
35
+ message-port tool bridge. It reuses the same executor even in browsers without
36
+ native WebMCP. Canonical Admin refuses embedding and installs no parent bridge.
37
+ Builder keeps reset/seed/observe and member/anonymous sandbox tests; owner
38
+ staff calls traverse the iframe Admin executor and existing sandbox HTTP bridge.
39
+ Timeout/cancellation does not imply a write was rolled back; reconcile before
40
+ retry. Preview remains isolated from live network APIs.
41
+
42
+ Reference: https://webmachinelearning.github.io/webmcp/
@@ -0,0 +1,37 @@
1
+ # ADR-lite 909: Mantle Admin UI kit export
2
+
3
+ **Status:** Accepted
4
+
5
+ ## Context
6
+
7
+ Mantle applications need the Admin product's React/shadcn visual language
8
+ without copying components or embedding the full Admin SPA. The Admin package
9
+ previously exposed only static product assets and a server-side token string.
10
+ Its same-origin `preview.html` contract remains the correct boundary for a
11
+ complete embedded Admin or Developer UI.
12
+
13
+ ## Decision
14
+
15
+ `@aotter/mantle-admin-ui/kit` exports the existing domain-neutral shadcn
16
+ primitives and Mantle one-time-code input. `kit.css` contains their compiled
17
+ Tailwind styles and complete Admin theme; `tokens.css` contains only the stable
18
+ Mantle design variables.
19
+
20
+ The kit does not export the Admin application, authenticated layout, router,
21
+ queries, API client, or feature views. Those modules assume Admin routes and
22
+ transport contracts and remain private. Consumers needing the complete product
23
+ use the canonical Admin assets or the explicit same-origin sandbox preview.
24
+
25
+ Copy-owned shadcn recipes may compose the public kit into working defaults.
26
+ They are installed as source in the consuming application rather than exposed
27
+ as another runtime framework. The first recipe is an email OTP page with
28
+ optional legal links.
29
+
30
+ ## Consequences
31
+
32
+ - Applications can share Mantle controls and visual tokens without depending
33
+ on Builder internals or duplicating Admin CSS.
34
+ - The static Admin SPA remains unchanged and optional.
35
+ - New public kit components require package-level contract and rendering tests.
36
+ - Authentication and legal-consent policy remain application concerns, not UI
37
+ primitive behavior.