@aotter/mantle 0.2.0-alpha.9 → 0.2.1-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.
- package/README.md +15 -5
- package/dist/auth/adapter.js +1 -28
- package/dist/auth/admin.js +2 -5
- package/dist/auth/caller.js +0 -27
- package/dist/auth/consent.js +100 -0
- package/dist/auth/hardening.js +0 -7
- package/dist/auth/identity.js +0 -11
- package/dist/auth/oauth.js +0 -32
- package/dist/auth/resource-seeds.js +0 -2
- package/dist/auth/route-http.js +33 -0
- package/dist/auth/routes.js +5 -151
- package/dist/build/compiler.d.ts +19 -609
- package/dist/build/compiler.js +6 -6896
- package/dist/build/spec/domain/model/ManifestGrammar.d.ts +39 -1
- package/dist/build/spec/domain/model/RuntimePlan.d.ts +16 -3
- package/dist/build/spec/domain/model/SqlIr.d.ts +32 -0
- package/dist/build/spec/domain/model/UserFields.d.ts +1 -0
- package/dist/build/spec/kernel/diagnostic.d.ts +1 -1
- package/dist/bun/assets.js +0 -2
- package/dist/domain/adminOrder.js +0 -2
- package/dist/domain/columns.js +7 -20
- package/dist/domain/describe/chunk-P6PP6VVV.js +1 -0
- package/dist/domain/describe/index.d.ts +1 -0
- package/dist/domain/describe/index.js +1 -115
- package/dist/domain/describe/match.d.ts +19 -0
- package/dist/domain/describe/target-hash.js +1 -12
- package/dist/domain/entry.js +0 -14
- package/dist/domain/generated-tools.js +0 -1
- package/dist/domain/input.js +0 -2
- package/dist/domain/paging.js +0 -17
- package/dist/domain/recipes.js +10 -7
- package/dist/domain/userReferences.js +0 -1
- package/dist/domain/wireScalars.js +0 -6
- package/dist/infrastructure/adminEntries.js +27 -8
- package/dist/infrastructure/adminPaging.js +55 -57
- package/dist/infrastructure/artifacts.js +0 -4
- package/dist/infrastructure/authSchema.js +0 -9
- package/dist/infrastructure/bundle.js +45 -38
- package/dist/infrastructure/cli.js +26 -12
- package/dist/infrastructure/generate.js +26 -19
- package/dist/infrastructure/generateAuth.js +1 -9
- package/dist/infrastructure/help.js +55 -0
- package/dist/infrastructure/init.js +50 -0
- package/dist/infrastructure/inputs.js +0 -9
- package/dist/infrastructure/mounts.js +22 -0
- package/dist/infrastructure/wrangler.js +0 -6
- package/dist/kernel/authorization.js +0 -1
- package/dist/kernel/binds.d.ts +34 -7
- package/dist/kernel/binds.js +5 -11
- package/dist/kernel/caller-identity.d.ts +0 -3
- package/dist/kernel/caller-identity.js +0 -15
- package/dist/kernel/caller-mode.d.ts +4 -0
- package/dist/kernel/caller-mode.js +14 -0
- package/dist/kernel/contracts.d.ts +13 -10
- package/dist/kernel/contracts.js +14 -41
- package/dist/kernel/cron.js +0 -4
- package/dist/kernel/dialect/common.js +0 -3
- package/dist/kernel/dialect/postgres.js +0 -2
- package/dist/kernel/dialect/sqlite.js +1 -6
- package/dist/kernel/drain.js +2 -8
- package/dist/kernel/driver/bun-sqlite.js +3 -7
- package/dist/kernel/driver/d1.d.ts +1 -1
- package/dist/kernel/driver/d1.js +6 -4
- package/dist/kernel/driver/postgres.d.ts +2 -1
- package/dist/kernel/driver/postgres.js +12 -22
- package/dist/kernel/driver/transaction-context.js +0 -1
- package/dist/kernel/email.js +0 -4
- package/dist/kernel/host-access.js +2 -3
- package/dist/kernel/host-caller.d.ts +1 -1
- package/dist/kernel/host-caller.js +3 -6
- package/dist/kernel/json-body.js +0 -2
- package/dist/kernel/mcp-apps.js +0 -5
- package/dist/kernel/mcp-call.js +0 -1
- package/dist/kernel/mcp-handler.js +4 -27
- package/dist/kernel/mcp.js +0 -5
- package/dist/kernel/media.js +0 -18
- package/dist/kernel/paging.js +1 -9
- package/dist/kernel/publishing.js +3 -4
- package/dist/kernel/r2-media.js +0 -7
- package/dist/kernel/rest-dispatch.js +0 -1
- package/dist/kernel/rest-router.js +5 -8
- package/dist/kernel/rest.d.ts +2 -1
- package/dist/kernel/rest.js +1 -3
- package/dist/kernel/route-pattern.d.ts +26 -0
- package/dist/kernel/route-pattern.js +34 -0
- package/dist/kernel/scalars.js +1 -9
- package/dist/kernel/search.js +0 -1
- package/dist/kernel/site.js +0 -2
- package/dist/kernel/store.d.ts +26 -2
- package/dist/kernel/store.js +69 -49
- package/dist/kernel/surface-failure.d.ts +10 -0
- package/dist/kernel/surface-failure.js +29 -0
- package/dist/kernel/surface.js +0 -3
- package/dist/kernel/sweep.js +0 -1
- package/dist/kernel/translations.js +0 -1
- package/dist/kernel/user-caller.js +2 -8
- package/dist/kernel/user-fields.d.ts +3 -2
- package/dist/kernel/user-fields.js +9 -9
- package/dist/kernel/validation.js +0 -8
- package/dist/kernel/web-gateway.js +0 -2
- package/dist/kernel/web-head.js +0 -1
- package/dist/kernel/web-index.js +0 -1
- package/dist/kernel/web-response.js +0 -1
- package/dist/kernel/web-serve.js +97 -0
- package/dist/kernel/web.d.ts +1 -1
- package/dist/kernel/web.js +10 -91
- package/dist/kernel/where.js +0 -6
- package/dist/usecase/adminBindings.js +32 -23
- package/dist/usecase/adminClient.js +4 -22
- package/dist/usecase/adminDescriptors.js +2 -9
- package/dist/usecase/generate.js +14 -17
- package/dist/usecase/handlers.js +1 -4
- package/dist/usecase/mcp-media.js +0 -1
- package/dist/usecase/mcp.js +0 -4
- package/dist/usecase/paging.js +1 -3
- package/dist/usecase/publishing.js +20 -11
- package/dist/usecase/rest.js +5 -6
- package/dist/usecase/site.js +0 -1
- package/dist/usecase/stores.js +12 -17
- package/dist/usecase/tool-version.js +0 -3
- package/dist/usecase/translations.js +0 -2
- package/dist/usecase/validation.js +0 -20
- package/docs/examples/README.md +13 -5
- package/docs/examples/app-shell/README.md +91 -12
- package/docs/examples/app-shell/accept.mjs +91 -0
- package/docs/examples/app-shell/gitignore +7 -0
- package/docs/examples/app-shell/package.json +10 -9
- package/docs/examples/app-shell/smoke-kit.mjs +29 -15
- package/docs/examples/app-shell/src/routes.ts +6 -3
- package/docs/examples/app-shell/src/service.ts +2 -1
- package/docs/examples/club-events/README.md +7 -2
- package/docs/examples/club-events/manifests/club-events.yaml +17 -0
- package/docs/examples/club-events/smoke.mjs +7 -1
- package/docs/examples/generated-web/seed.sql +5 -4
- package/docs/examples/purchasing/README.md +12 -3
- package/docs/examples/purchasing/manifests/purchasing.yaml +24 -4
- package/docs/examples/purchasing/smoke.mjs +14 -0
- package/docs/examples/recipes/README.md +5 -3
- package/docs/handbook/cloudflare/media-r2.md +6 -3
- package/docs/handbook/cloudflare/service-entry.md +5 -0
- package/docs/handbook/concepts/lifecycle-and-locales.md +21 -1
- package/docs/handbook/examples/hub.md +1 -1
- package/docs/handbook/guides/admin-ui.md +1 -1
- package/docs/handbook/guides/agent-setup.md +20 -10
- package/docs/handbook/guides/agent-workflow-acceptance.md +225 -105
- package/docs/handbook/guides/local-testing.md +85 -0
- package/docs/handbook/guides/native-admin.md +242 -16
- package/docs/handbook/guides/native-execution.md +10 -8
- package/docs/handbook/guides/public-pages.md +44 -4
- package/docs/handbook/guides/revisions.md +584 -0
- package/docs/handbook/guides/size-and-startup.md +140 -0
- package/docs/handbook/guides/sql-patterns.md +312 -0
- package/docs/handbook/guides/typed-queries.md +146 -3
- package/docs/handbook/navigation.json +20 -0
- package/docs/handbook/reference/admin-descriptors.md +4 -1
- package/docs/handbook/reference/authorization.md +3 -1
- package/docs/handbook/reference/describe.md +42 -0
- package/docs/handbook/reference/diagnostics.md +16 -2
- package/docs/handbook/reference/procedure.md +6 -6
- package/docs/handbook/reference/schema.md +79 -9
- package/docs/handbook/reference/sql.md +65 -0
- package/docs/handbook/reference/surface.md +8 -4
- package/docs/handbook/reference/trigger.md +12 -0
- package/docs/handbook/reference/view.md +11 -3
- package/docs/handbook/releases/index.md +71 -7
- package/docs/handbook/start/agents.md +49 -0
- package/docs/handbook/start/project-and-cli.md +10 -0
- package/docs/handbook/start/quickstart-worker.md +1 -1
- package/docs/skills/develop/SKILL.md +19 -6
- package/docs/skills/integrate/SKILL.md +3 -1
- package/docs/skills/performance/SKILL.md +169 -0
- package/docs/skills/update/SKILL.md +10 -4
- package/docs/upgrade-0.1-to-0.2.md +151 -39
- package/package.json +31 -11
- package/skills/README.md +6 -2
- package/skills/mantle/SKILL.md +53 -120
- package/dist/domain/describe/chunk-ZVXBGP7Y.js +0 -424
- package/skills/mantle/references/local-testing.md +0 -20
- package/skills/mantle/references/web.md +0 -41
- package/skills/mantle/references/website.md +0 -51
|
@@ -13,21 +13,20 @@ carries.
|
|
|
13
13
|
The Mantle plugin carries one OSS authoring skill, `mantle`, and local
|
|
14
14
|
acceptance references. It does not configure a hosted-service connection.
|
|
15
15
|
Install from the Git tag matching the exact SDK version you selected (currently
|
|
16
|
-
`v0.2.
|
|
17
|
-
|
|
18
|
-
instructions. A skill install does not upgrade the application's SDK.
|
|
16
|
+
`v0.2.1-alpha.1`). Pin the tag to keep instructions aligned with the application's
|
|
17
|
+
SDK. A skill install does not upgrade the application's SDK.
|
|
19
18
|
|
|
20
19
|
For Codex, pin the marketplace checkout:
|
|
21
20
|
|
|
22
21
|
```sh
|
|
23
|
-
codex plugin marketplace add aotter/mantle --ref v0.2.
|
|
22
|
+
codex plugin marketplace add aotter/mantle --ref v0.2.1-alpha.1
|
|
24
23
|
codex plugin add mantle@mantle
|
|
25
24
|
```
|
|
26
25
|
|
|
27
26
|
For Claude Code, first clone the release into a directory you will keep:
|
|
28
27
|
|
|
29
28
|
```sh
|
|
30
|
-
git clone --depth 1 --branch v0.2.
|
|
29
|
+
git clone --depth 1 --branch v0.2.1-alpha.1 https://github.com/aotter/mantle.git mantle-plugin
|
|
31
30
|
```
|
|
32
31
|
|
|
33
32
|
Then, in Claude Code, use that checkout's absolute path:
|
|
@@ -41,9 +40,12 @@ Cursor and GitHub Copilot use their plugin manifests from the same tagged
|
|
|
41
40
|
checkout. Without a plugin host, install only the consumer skill by name:
|
|
42
41
|
|
|
43
42
|
```sh
|
|
44
|
-
npx skills add
|
|
43
|
+
npx skills add aotter/mantle@mantle
|
|
45
44
|
```
|
|
46
45
|
|
|
46
|
+
Without a version it follows `main`, the latest stable release. To match the
|
|
47
|
+
application's SDK exactly, add its release tag: `npx skills add aotter/mantle#v0.2.1-alpha.1@mantle`.
|
|
48
|
+
|
|
47
49
|
When upgrading the SDK, update the marketplace ref or local tagged checkout and
|
|
48
50
|
refresh/reinstall the plugin using the host's native workflow. Verify the loaded
|
|
49
51
|
manifest version and skill source. Do not reset a checkout containing local edits.
|
|
@@ -54,10 +56,17 @@ project and copies no handbook.
|
|
|
54
56
|
|
|
55
57
|
## 2. Install the SDK, then read its own docs
|
|
56
58
|
|
|
57
|
-
Use the version the project already pins. For a new project,
|
|
58
|
-
version
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
Use the version the project already pins. For a new project, install this
|
|
60
|
+
handbook's version exactly. 0.2.1-alpha.1 is a prerelease; stable 0.2.0 remains the
|
|
61
|
+
production line, and its own tagged handbook describes it.
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
pnpm add --save-exact @aotter/mantle@0.2.1-alpha.1
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Add optional `@aotter/mantle-ui@0.2.1-alpha.1` and `@aotter/mantle-admin@0.2.1-alpha.1` only
|
|
68
|
+
when the selected surfaces need them. Every selected `@aotter/mantle*` package
|
|
69
|
+
stays at the same exact version. Read, from the application:
|
|
61
70
|
|
|
62
71
|
```text
|
|
63
72
|
node_modules/@aotter/mantle/README.md
|
|
@@ -76,6 +85,7 @@ the skill's GitHub copy and over any online handbook.
|
|
|
76
85
|
| `docs/skills/update/SKILL.md` | upgrading `@aotter/mantle`, including from 0.1.x |
|
|
77
86
|
| `docs/skills/provision/SKILL.md` | deploying, with production sign-in |
|
|
78
87
|
| `docs/skills/media-gc/SKILL.md` | auditing or removing stale R2 uploads |
|
|
88
|
+
| `docs/skills/performance/SKILL.md` | after acceptance converges, or when a page, first request or query is slow |
|
|
79
89
|
|
|
80
90
|
0.2.0 has no `mantle skills` command: nothing is copied into the project.
|
|
81
91
|
An agent reads these files from `node_modules` when the task calls for them.
|
|
@@ -6,12 +6,15 @@ customisations, application pages and web routes, REST APIs used by clients,
|
|
|
6
6
|
MCP tools and MCP Apps. Generation, typechecking, scripted smoke tests and an
|
|
7
7
|
author's replay remain useful; they do not establish independent acceptance. A
|
|
8
8
|
fresh context is not enough if the author still chooses a workflow that mirrors
|
|
9
|
-
the implementation. Every acceptance round gives the evaluator
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
the implementation. Every acceptance round gives the evaluator only a
|
|
10
|
+
role and the entry points that role uses; it derives realistic tasks itself
|
|
11
|
+
and the author scores them against a private rubric. The first delivery gets
|
|
12
|
+
full acceptance; after a repair, the change decides what
|
|
13
|
+
[re-runs](#re-verify-what-a-repair-touches).
|
|
12
14
|
If independent acceptance is not run, report `UNVERIFIED`; if a fresh evaluator
|
|
13
15
|
or authorized test transport is unavailable, report `BLOCKED`; neither outcome
|
|
14
|
-
is done.
|
|
16
|
+
is done. Either way, report the evidence you do have in the
|
|
17
|
+
[layered handoff](#report-done-ness-in-layers).
|
|
15
18
|
|
|
16
19
|
Use the surface the intended user actually uses: a real browser session for
|
|
17
20
|
Admin and application pages; for REST, an HTTP client plus the public API
|
|
@@ -29,8 +32,8 @@ the exercise pass.
|
|
|
29
32
|
Start with the original user brief, business role and explicit requirements,
|
|
30
33
|
not a list of CRUD endpoints or a task derived from what you implemented.
|
|
31
34
|
Before writing manifests or handlers, record the intended jobs and assumptions
|
|
32
|
-
in the existing design note.
|
|
33
|
-
|
|
35
|
+
in the existing design note. The capability map feeds the private rubric
|
|
36
|
+
(below); an evaluator receives only its role and chooses its own tasks and
|
|
34
37
|
observable success criteria. Do not expand application scope or authority
|
|
35
38
|
merely to satisfy an evaluator's newly inferred product wish.
|
|
36
39
|
|
|
@@ -82,101 +85,170 @@ rounds below before claiming the user-facing work is done. Keep the author's
|
|
|
82
85
|
capability map and worked call sequence out of the fresh agent's prompt: an MCP
|
|
83
86
|
evaluator must discover the workflow from public tool descriptions and results.
|
|
84
87
|
|
|
85
|
-
## Run
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
and authority
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
and
|
|
101
|
-
the
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
path, vary the fixtures, not the brief or the steps, or report that path as
|
|
149
|
-
UNVERIFIED. Repeated success on one narrow path cannot establish broader
|
|
150
|
-
readiness. Keep optional wishes, non-material suggestions and external
|
|
151
|
-
BLOCKED gates visible; no finding count proves absence of defects. When the
|
|
152
|
-
round cap or an external blocker stops the loop, report NOT CONVERGED or
|
|
153
|
-
BLOCKED with the remaining work, not acceptance. Setup cleans isolated
|
|
154
|
-
fixtures in `finally` after every round, including failed/aborted rounds.
|
|
88
|
+
## Run role-only acceptance rounds until they converge
|
|
89
|
+
|
|
90
|
+
The evaluator gets a role, not a task list. It works out what that role needs
|
|
91
|
+
to get done from the interface itself; what it derives, and what it misses, is
|
|
92
|
+
the evidence.
|
|
93
|
+
|
|
94
|
+
1. **Write a private rubric first.** From the original brief, the author lists
|
|
95
|
+
what each role must be able to do on each surface (Admin, application
|
|
96
|
+
pages, REST, MCP), with observable success criteria, explicit exclusions
|
|
97
|
+
and the authority each role must not have. The rubric stays with the author;
|
|
98
|
+
no evaluator ever sees it, its wording or its order.
|
|
99
|
+
2. **Hand each evaluator only its role.** Supply the business role and context
|
|
100
|
+
in one or two sentences, the entry points that role really uses (Admin URL,
|
|
101
|
+
site URL, REST base URL and API reference, MCP endpoint), a signed-in browser
|
|
102
|
+
session or client token from setup, the interaction/time/write budget,
|
|
103
|
+
permitted fake-data actions and what is forbidden (source, SQL, internal
|
|
104
|
+
docs, the database, other roles' credentials, blind retries of uncertain
|
|
105
|
+
writes). Withhold the brief's requirement list, capability maps, tool names,
|
|
106
|
+
precomputed IDs and earlier reports. Seed realistic fixtures: other owners'
|
|
107
|
+
records, several states and more than one page of results. Run the evaluator
|
|
108
|
+
outside the project directory, without Mantle skills or project instruction
|
|
109
|
+
files, and record that isolation.
|
|
110
|
+
3. **Let it derive the work, then do it.** Before any interaction the evaluator
|
|
111
|
+
writes down what this role would need to accomplish and how it would know
|
|
112
|
+
each one succeeded. It then refines that list as it discovers the interface
|
|
113
|
+
(at least once after a first look, again after its first attempts), executes
|
|
114
|
+
it, and reports PASS/FAIL/BLOCKED per goal with readbacks, rejected writes,
|
|
115
|
+
recovery attempts and interaction counts. Zero findings is a valid result.
|
|
116
|
+
4. **One fresh agent per role, every surface.** In the first round, and in any
|
|
117
|
+
round the [re-verification rule](#re-verify-what-a-repair-touches) widens
|
|
118
|
+
to all of them, cover every role and surface. For the default two roles, run
|
|
119
|
+
an `admin` evaluator and a `user` evaluator in the same round on shared live
|
|
120
|
+
data, in the brief's natural order. Between them they cover every surface
|
|
121
|
+
the app exposes to each role: Admin for `admin`, pages for visitors and
|
|
122
|
+
members, REST for client developers, MCP for both roles' AI clients. A
|
|
123
|
+
surface no evaluator reached stays UNVERIFIED.
|
|
124
|
+
5. **Score against the rubric outside the evaluator.** The author compares the
|
|
125
|
+
evaluator's derived goals and results with the rubric. A rubric item the
|
|
126
|
+
evaluator never thought of is itself a finding: the interface did not make
|
|
127
|
+
that job discoverable. Classify every finding P0 (data loss, authority or
|
|
128
|
+
integrity defect, uncertain write), P1 (a rubric item FAIL, BLOCKED or not
|
|
129
|
+
discoverable), P2 (friction) or P3 (suggestion), with evidence and the
|
|
130
|
+
smallest repair. Separate a violated explicit requirement, a demonstrated
|
|
131
|
+
defect and a newly inferred product wish; a wish is not permission to grow
|
|
132
|
+
the product. A goal the evaluator's own environment stopped (its tool
|
|
133
|
+
approval, sandbox or network, not an app refusal) is not a finding: record
|
|
134
|
+
it as an [environment block](#report-done-ness-in-layers) and rerun that
|
|
135
|
+
role once it is lifted.
|
|
136
|
+
6. **Repair outside the evaluator's context, then re-verify what it touches.**
|
|
137
|
+
The author keeps the findings ledger, makes the smallest in-scope repair,
|
|
138
|
+
adds focused regressions (authorization, OCC, atomicity), and freezes a new
|
|
139
|
+
revision. The next round re-runs the roles and surfaces the
|
|
140
|
+
[re-verification rule](#re-verify-what-a-repair-touches) names, with new
|
|
141
|
+
agents and new fixtures, and passes them nothing from earlier rounds.
|
|
142
|
+
7. **Converge or stop.** A round converges when it has no P0 or P1 and
|
|
143
|
+
evaluator-observed results cover every rubric item visible to their roles:
|
|
144
|
+
from this round, or reused from an earlier round under the
|
|
145
|
+
re-verification rule. Items outside any role's view (another caller's
|
|
146
|
+
isolation, hidden state) need author regressions, reported under that
|
|
147
|
+
label. Run at most three
|
|
148
|
+
rounds. If the third still has a P0 or P1 or an uncovered rubric item, report
|
|
149
|
+
BLOCKED with the remaining ledger, not acceptance. Setup cleans fixtures in
|
|
150
|
+
`finally` after every round, including aborted ones.
|
|
155
151
|
|
|
156
152
|
If a fresh agent or authorized test transport is unavailable, record independent
|
|
157
|
-
acceptance as BLOCKED and report the scripted checks
|
|
153
|
+
acceptance as BLOCKED and report the scripted checks on their own
|
|
154
|
+
[layers](#report-done-ness-in-layers). Do not invent
|
|
158
155
|
an independent result. Do not deploy or publish merely to obtain acceptance.
|
|
159
156
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
157
|
+
Acceptance proves the behavior, not its speed. Once a round converges, the
|
|
158
|
+
[performance skill](../../skills/performance/SKILL.md) decides which performance
|
|
159
|
+
checks apply and holds them to their targets; a performance repair that changes
|
|
160
|
+
what a role sees or can do returns here, scoped by the
|
|
161
|
+
[re-verification rule](#re-verify-what-a-repair-touches).
|
|
162
|
+
|
|
163
|
+
## Re-verify what a repair touches
|
|
164
|
+
|
|
165
|
+
The first delivery always gets full acceptance: every role, every surface.
|
|
166
|
+
After a repair, the change itself decides what runs again, not the finding
|
|
167
|
+
that prompted it. Rounds before convergence are not accepted, so diff against
|
|
168
|
+
evidence, not rounds: for each item you want to reuse, diff the current
|
|
169
|
+
revision against the revision it was observed at, and pick the widest row that
|
|
170
|
+
diff matches. A chain of repairs adds up; a page-only repair followed by a
|
|
171
|
+
handler repair has to re-run what the handler repair reaches.
|
|
172
|
+
|
|
173
|
+
| The repair changes | Re-run with fresh evaluators | May reuse |
|
|
174
|
+
| --- | --- | --- |
|
|
175
|
+
| Only presentation: page or Admin layout, CSS, copy, client-side display | Blind acceptance of the affected UI, for each role that uses it. A shared component or layout affects every page that renders it. | REST and MCP evidence from the same business-rule version |
|
|
176
|
+
| A public contract: a tool or route description, input, output or error shape; the generated client or other `generated/` output it changes | That surface for each role that uses it, plus every UI that consumes it | Other surfaces at the same business-rule version |
|
|
177
|
+
| Authentication, sessions, roles, `requires`, row or tenant scope | Every surface that the changed rule guards, for every affected role | Nothing those surfaces depend on |
|
|
178
|
+
| A SQL Procedure or View, a `uniqueIndexes` entry, a check or lock, a migration that changes results, a handler's business rule | Every surface that reads or writes that data | Nothing those surfaces depend on |
|
|
179
|
+
| A shared transport: the service entry, routing, the HTTP or MCP mount, a shared error envelope | Every surface on that transport | Nothing on that transport |
|
|
180
|
+
|
|
181
|
+
The business-rule version is the revision of the manifests, SQL, migrations,
|
|
182
|
+
handlers, authorization and service entry. A repair that changes none of
|
|
183
|
+
them keeps that version, so evidence collected at it still stands for
|
|
184
|
+
surfaces the repair did not reach. A repair that changes any of them
|
|
185
|
+
starts a new business-rule version, and looking at the UI alone is not
|
|
186
|
+
enough. One exception: a repair that only adds or drops a non-unique Schema
|
|
187
|
+
`indexes` entry and its migration keeps the version. It changes speed, not
|
|
188
|
+
which rows a read returns or which writes are refused. A `uniqueIndexes`
|
|
189
|
+
entry, a check or a lock does change which writes succeed, so it falls in the
|
|
190
|
+
SQL row. When the diff is unclear, widen.
|
|
191
|
+
|
|
192
|
+
Every row still runs the author's regressions on the new revision (layers 1
|
|
193
|
+
and 2 of the [layered report](#report-done-ness-in-layers)): `pnpm check`,
|
|
194
|
+
`pnpm smoke`, `pnpm test` and the focused regressions for the repair.
|
|
195
|
+
|
|
196
|
+
A re-run evaluator is as fresh as the first: a new agent, new fixtures, only
|
|
197
|
+
its role and the entry points under re-test. Do not tell it what was
|
|
198
|
+
repaired, what to check or what an earlier evaluator did. No previous
|
|
199
|
+
answers, rubric or precomputed steps.
|
|
200
|
+
|
|
201
|
+
For every rubric item that was not re-run, record the round and revision its
|
|
202
|
+
evidence comes from and why the changes since that revision could not affect
|
|
203
|
+
it. Never report a
|
|
204
|
+
reused item as observed in a later round.
|
|
205
|
+
|
|
206
|
+
## Hand each role to its evaluator
|
|
207
|
+
|
|
208
|
+
Setup signs each role in; the evaluator receives the role's access, never a credential it could reuse or widen.
|
|
209
|
+
This is the authorized test transport the BLOCKED rule above refers to.
|
|
210
|
+
|
|
211
|
+
- **Local session URL (the app shell's default).** `pnpm accept` in an app written by `mantle init` starts the app
|
|
212
|
+
on a fresh local D1, signs the admin in, runs an optional fixtures module, signs the user in and prints one local
|
|
213
|
+
URL per role. Each URL forwards every request with that role's session and refuses `/api/auth/*`. Give the
|
|
214
|
+
evaluator only its URL: MCP at `<url>/mcp` (user) or `<url>/mcp/admin` (admin) for any streamable HTTP MCP client,
|
|
215
|
+
Admin at `<url>/admin` and member pages at `<url>/` in a browser, REST at `<url>/` with no credential. An evaluator
|
|
216
|
+
without an MCP client uses `node accept.mjs mcp <endpoint> [tool [json]]`, which prints the raw result including
|
|
217
|
+
`isError`. The app README's "Independent acceptance" section shows the fixtures module.
|
|
218
|
+
- **An external MCP host over OAuth.** To accept the connection a real client uses (Claude, ChatGPT or another host
|
|
219
|
+
that supports MCP OAuth), deploy or tunnel the app as you would for that host, add `<origin>/mcp` or
|
|
220
|
+
`<origin>/mcp/admin` to the host in setup, and complete sign-in and consent as the role's fictional identity. The
|
|
221
|
+
evaluator then works in that already-connected host. Its token stays in the host; the evaluator neither sees nor
|
|
222
|
+
requests it. Record this as OAuth evidence, separate from the local session URL (see
|
|
223
|
+
[OAuth](oauth.md)).
|
|
224
|
+
|
|
225
|
+
Either way, the evaluator's prompt names the URL or the connected host, never a cookie, token or sign-in step.
|
|
226
|
+
|
|
227
|
+
If you cannot start a fresh agent yourself (for example, you are a subagent without that tool), prepare everything
|
|
228
|
+
else: the rubric, the fixtures module, `pnpm accept` running, and one filled-in role prompt per role (below) naming
|
|
229
|
+
its URL. Hand the prompts to whoever can start agents (the person or the orchestrating agent), keep the app running,
|
|
230
|
+
and report acceptance as BLOCKED with the prompts attached until their reports come back. Score those reports as
|
|
231
|
+
usual.
|
|
232
|
+
|
|
233
|
+
## Give the agent a role
|
|
234
|
+
|
|
235
|
+
Fill this in per role. It names the role and the doors, never the jobs:
|
|
236
|
+
|
|
237
|
+
> You are [role, for example "a purchasing manager"] at [business context in
|
|
238
|
+
> one sentence]. You use [entry points for this role from `pnpm accept`: Admin
|
|
239
|
+
> URL, site URL, REST base URL and reference, MCP endpoint]; setup has already
|
|
240
|
+
> signed you in as [fictional identity]. Budget: [interactions/time/writes]. You may create and
|
|
241
|
+
> change fictional records; [owner] cleans up. Do not read source, internal docs
|
|
242
|
+
> or a database, use anyone else's access, or retry a write whose outcome you
|
|
243
|
+
> do not know.
|
|
244
|
+
> First, write down what someone in this role needs to get done with this
|
|
245
|
+
> service and how you would tell each one worked. Refine that list after a
|
|
246
|
+
> first look at the interface and again after your first attempts. Then do the
|
|
247
|
+
> work and report each goal as PASS/FAIL/BLOCKED with what you read back,
|
|
248
|
+
> what was refused, what it cost you, and the smallest change that would have
|
|
249
|
+
> helped. For BLOCKED, say whether the service refused you or your own tools
|
|
250
|
+
> or permissions stopped you. Report what you covered and what you could not reach; finding nothing
|
|
251
|
+
> wrong is acceptable.
|
|
180
252
|
|
|
181
253
|
The author separately verifies isolation between callers, stale-version
|
|
182
254
|
refusal, unknown-outcome handling and effects hidden from the evaluator's role
|
|
@@ -184,23 +256,71 @@ through authorized test fixtures. Do not grant the evaluator extra authority
|
|
|
184
256
|
just to observe hidden state. Keep author regressions distinct from what the
|
|
185
257
|
fresh agent actually observed.
|
|
186
258
|
|
|
259
|
+
## Report done-ness in layers
|
|
260
|
+
|
|
261
|
+
Report a handoff in four layers, in this order, each for the exact commit. Each
|
|
262
|
+
layer proves something the others do not; a passing layer neither replaces nor
|
|
263
|
+
is invalidated by another layer's result.
|
|
264
|
+
|
|
265
|
+
| Layer | What it proves | Evidence |
|
|
266
|
+
| --- | --- | --- |
|
|
267
|
+
| 1. Generation and types | Manifests compile, `generated/` is current, the app typechecks and builds. No handler runs. | `pnpm check` (includes `generate --check`), `pnpm build` |
|
|
268
|
+
| 2. Business rules and permissions | Handlers on a fresh local D1 over HTTP: each operation at its edges, refusals, caller isolation, visitor pages, MCP discovery, the Admin MCP App loading. Author's evidence. | `pnpm smoke`, `pnpm test`; [Local HTTP checks](local-testing.md) |
|
|
269
|
+
| 3. Independent acceptance, per role | A fresh agent given only its role and entry points finds and finishes that role's work on each surface it uses. | Per role: the [rounds](#run-role-only-acceptance-rounds-until-they-converge) verdict and surfaces covered, naming the round and revision of any [reused](#re-verify-what-a-repair-touches) evidence |
|
|
270
|
+
| 4. External platform | A real MCP host connects over OAuth; the production origin serves the deployed app. Local cookie sessions prove neither. | Host and version, identity, origin, observed result |
|
|
271
|
+
|
|
272
|
+
Give each layer, and each role on layer 3, one status:
|
|
273
|
+
|
|
274
|
+
- **verified**: the evidence above, with its command or host and result.
|
|
275
|
+
- **failed**: the product is wrong. Name the failing check or finding.
|
|
276
|
+
- **BLOCKED**: the layer could not run. Give the reason, what refused or is
|
|
277
|
+
missing, and what would unblock it.
|
|
278
|
+
- **not applicable**: with the reason. Layer 4 is not applicable unless the
|
|
279
|
+
requested work includes an external host connection or a deployment.
|
|
280
|
+
|
|
281
|
+
A layer nobody attempted is UNVERIFIED, as above. A block from the execution
|
|
282
|
+
environment (an agent's approval policy refusing fictional writes, no browser,
|
|
283
|
+
no network, a sandbox) is BLOCKED on that layer only. It is never a failed
|
|
284
|
+
layer or a product finding, and it does not invalidate the evidence on other
|
|
285
|
+
layers. Do not work around it by widening the evaluator's authority, faking a
|
|
286
|
+
result or deploying; ask whoever controls the environment and rerun only that
|
|
287
|
+
layer on the same revision.
|
|
288
|
+
|
|
289
|
+
The work is done only when layers 1 to 3 are verified for every role and
|
|
290
|
+
surface, and layer 4 is verified or not applicable. Partial evidence is still
|
|
291
|
+
reported, layer by layer; it is not done:
|
|
292
|
+
|
|
293
|
+
```markdown
|
|
294
|
+
| Layer | Status | Evidence |
|
|
295
|
+
| --- | --- | --- |
|
|
296
|
+
| 1. Generation and types | verified | `pnpm check`, `pnpm build` at <commit> |
|
|
297
|
+
| 2. Business rules and permissions | verified | `pnpm smoke` (<n> checks), `pnpm test` |
|
|
298
|
+
| 3. Acceptance: admin | BLOCKED: evaluator's approval policy refused to create fictional records; needs <permission> | round 1 stopped at goal <n> |
|
|
299
|
+
| 3. Acceptance: user | verified: CONVERGED in round <n> | member pages in round <n>; MCP reused from round <m> at <revision> (page-only repair) |
|
|
300
|
+
| 4. External platform | not applicable: no deployment or external host requested | |
|
|
301
|
+
```
|
|
302
|
+
|
|
187
303
|
## Record evidence in the existing issue or handoff
|
|
188
304
|
|
|
189
305
|
Use ordinary Markdown; no new receipt schema or framework is required:
|
|
190
306
|
|
|
191
|
-
- Original brief,
|
|
192
|
-
|
|
307
|
+
- Original brief, the private rubric, roles, environment, per-round budgets
|
|
308
|
+
and round cap.
|
|
193
309
|
- Setup assistance and what each agent could access; identify distinct rounds.
|
|
194
|
-
- Per round: revision,
|
|
310
|
+
- Per round: revision, business-rule version, the roles and surfaces re-run
|
|
311
|
+
and why (the [re-verification rule](#re-verify-what-a-repair-touches) row),
|
|
312
|
+
each evaluator's derived goals (first list and
|
|
313
|
+
refinements) and criteria, the gaps between them and the rubric, per-goal
|
|
195
314
|
PASS/FAIL/BLOCKED, actual readbacks and interaction references,
|
|
196
315
|
request/page/tool counts
|
|
197
316
|
and negative/recovery attempts, with their differing scope stated.
|
|
198
|
-
- Findings ledger with
|
|
317
|
+
- Findings ledger with P0–P3, owner, disposition, minimal repair and
|
|
199
318
|
regression commands/results.
|
|
200
|
-
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
319
|
+
- Coverage of each rubric item (evaluator-observed in this round,
|
|
320
|
+
evaluator-observed and reused from round <n> at <revision> with the reason,
|
|
321
|
+
author regression only, or UNVERIFIED); the final CONVERGED / BLOCKED / UNVERIFIED verdict and rounds
|
|
322
|
+
used, which is layer 3 of the [layered report](#report-done-ness-in-layers).
|
|
323
|
+
Retain every failed report.
|
|
204
324
|
- Fixture cleanup result and every remaining limitation.
|
|
205
325
|
|
|
206
326
|
Keep credentials, raw auth logs, full resource HTML and private operational
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Scripted local checks before acceptance - handlers over real HTTP, public pages without JavaScript, MCP discovery, Admin's MCP App, and how to account for every surface.
|
|
3
|
+
---
|
|
4
|
+
# Local HTTP checks
|
|
5
|
+
|
|
6
|
+
`pnpm check` proves that the manifests compile and the app typechecks; it runs no handler. Before you report an app
|
|
7
|
+
or a feature ready, run it on a fresh local D1 and drive it over HTTP. In an app written by `mantle init`, that is
|
|
8
|
+
`smoke.mjs` on the shell's `smoke-kit.mjs` (`pnpm smoke`): it applies `generated/schema.sql` and `seed.sql`, starts
|
|
9
|
+
`wrangler dev --local`, signs users in with the console email code and deletes everything afterwards.
|
|
10
|
+
These checks are the author's evidence: layers 1 and 2 of the
|
|
11
|
+
[layered handoff report](agent-workflow-acceptance.md#report-done-ness-in-layers). [Independent
|
|
12
|
+
acceptance](agent-workflow-acceptance.md) comes after them and does not replace them, nor they it.
|
|
13
|
+
|
|
14
|
+
## What smoke covers
|
|
15
|
+
|
|
16
|
+
- **Every Procedure and HTTP Trigger the app declares:** valid input with the expected status and body (a status
|
|
17
|
+
below 500 is not success), invalid input, an anonymous call to a protected operation, the other role, and the
|
|
18
|
+
stored result read back. Use only the generated routes, inputs and permissions.
|
|
19
|
+
- **Business rules at their edges:** the oversell, the stale `expectedVersion`, the second approval, a refusal that
|
|
20
|
+
must leave nothing behind (check the rows with the kit's `sql`), and two concurrent calls where a race matters.
|
|
21
|
+
- **Each caller sees only its own rows:** a second member's records are absent from lists and refused by id.
|
|
22
|
+
- **Visitor pages:** the checks in [public pages](public-pages.md#check-before-you-report-done), requested without
|
|
23
|
+
JavaScript.
|
|
24
|
+
- **MCP:** `assertMcpDiscovery(endpoint, { tools, headers })` from `smoke-kit.mjs` for `/mcp` and `/mcp/admin`, with
|
|
25
|
+
the expected tools taken from generated code (the app-shell README shows it), plus a separate assertion that an
|
|
26
|
+
anonymous call and a member calling `/mcp/admin` are refused. Discovery needs no business `tools/call`.
|
|
27
|
+
- **Admin:** `pnpm build`, then `pnpm test` (`generated/admin-mcp-app.check.mjs`) loads the Admin MCP App in an MCP
|
|
28
|
+
host and fails on a network error, console error or exception. It needs `playwright-core` and Chrome
|
|
29
|
+
(`npx playwright-core install chromium`, or `MANTLE_TEST_CHROMIUM=<executable>`). With no browser it fails: report
|
|
30
|
+
that check as BLOCKED on layer 2, not skipped and not as a product failure.
|
|
31
|
+
|
|
32
|
+
Better Auth allows 3 one-time-code requests per minute per client IP; the kit gives each user its own
|
|
33
|
+
`cf-connecting-ip`. Credentials come only from the kit's sign-in: a check never scrapes another session or builds a
|
|
34
|
+
Caller by hand.
|
|
35
|
+
|
|
36
|
+
## Seed data
|
|
37
|
+
|
|
38
|
+
Create test records through the app itself: in `smoke.mjs` or the `pnpm accept` fixtures module, call the app's own
|
|
39
|
+
REST, MCP or Admin operations as a signed-in user (`call("POST", "/admin/api/operations/create-event", { cookie: admin,
|
|
40
|
+
body })`), or insert through the Store (`store(db, caller).collection("events").insert(...)`). Mantle then fills every
|
|
41
|
+
system column (`id`, `version`, `created_at`, `updated_at`, `author_id`, and on a publishing Schema `status` and
|
|
42
|
+
`published_at` through its publish Procedure) and enforces the Schema's checks, scope and references, exactly as for
|
|
43
|
+
real data.
|
|
44
|
+
|
|
45
|
+
Keep `seed.sql` for static reference data that no surface writes, such as categories or department budgets.
|
|
46
|
+
`pnpm db:seed` and `smoke-kit.mjs` apply it as native SQL, which bypasses all of the above, so the seed sets each
|
|
47
|
+
system column itself:
|
|
48
|
+
|
|
49
|
+
| Column | SQLite and D1 (`cloudflare-d1`, `bun-sqlite`) | PostgreSQL | If the seed omits it |
|
|
50
|
+
|---|---|---|---|
|
|
51
|
+
| `id` | text, unique | text, unique | the insert fails |
|
|
52
|
+
| `version` | `1` | `1` | `1` |
|
|
53
|
+
| `created_at` | integer microseconds since the Unix epoch | `timestamptz` | the insert fails |
|
|
54
|
+
| `updated_at` | integer microseconds; the same as `created_at` | `timestamptz` | SQLite and D1 store `0`: Admin shows 1970-01-01. PostgreSQL stores `now()` |
|
|
55
|
+
| `author_id` | the creator's user id, or `NULL` for system rows | the same | `NULL`: under `restrict: { <schema>: "author_id = auth.uid()" }` no member sees the row |
|
|
56
|
+
| `status` (publishing) | `'draft'`, `'published'` or `'archived'` | the same | `'draft'` |
|
|
57
|
+
| `published_at` (publishing) | microseconds when `status` is `'published'`, otherwise `NULL` | `timestamptz`, otherwise `NULL` | `NULL` |
|
|
58
|
+
|
|
59
|
+
A field- or owner-scoped Schema also needs its scope column. Use fixed instants for repeatable fixtures
|
|
60
|
+
(`1767225600000000` is 2026-01-01T00:00:00Z), or the moment the seed runs (`unixepoch() * 1000000` on SQLite and
|
|
61
|
+
D1, `now()` on PostgreSQL). For a publishing `posts` Schema on D1:
|
|
62
|
+
|
|
63
|
+
```sql
|
|
64
|
+
INSERT INTO posts (id, version, created_at, updated_at, author_id, status, published_at, title, body) VALUES
|
|
65
|
+
('welcome', 1, 1767225600000000, 1767225600000000, NULL, 'published', 1767225600000000, 'Welcome', '# Welcome'),
|
|
66
|
+
('draft-note', 1, unixepoch() * 1000000, unixepoch() * 1000000, NULL, 'draft', NULL, 'Draft', '# Draft');
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The same rows on PostgreSQL:
|
|
70
|
+
|
|
71
|
+
```sql
|
|
72
|
+
INSERT INTO posts (id, version, created_at, updated_at, author_id, status, published_at, title, body) VALUES
|
|
73
|
+
('welcome', 1, '2026-01-01T00:00:00Z', '2026-01-01T00:00:00Z', NULL, 'published', '2026-01-01T00:00:00Z', 'Welcome', '# Welcome'),
|
|
74
|
+
('draft-note', 1, now(), now(), NULL, 'draft', NULL, 'Draft', '# Draft');
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
A seed is local test data; never apply it to an existing production database.
|
|
78
|
+
|
|
79
|
+
## Account for every surface
|
|
80
|
+
|
|
81
|
+
In the app's README or handoff, list each declared surface (Admin, each MCP endpoint, REST, each visitor page type)
|
|
82
|
+
as verified (command, identity and result), intentionally not exposed, or UNVERIFIED with a reason. Local cookie
|
|
83
|
+
sessions do not prove an external MCP host's OAuth connection or a production origin; those are layer 4. Record the
|
|
84
|
+
commands and their results for the exact commit in the layered report, fix failures and rerun the affected checks. A
|
|
85
|
+
check the environment prevented (no browser, no network, a refused approval) is BLOCKED with its reason, not failed.
|