@rubytech/create-maxy-code 0.1.490 → 0.1.491
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/package.json
CHANGED
|
@@ -22,6 +22,10 @@ Auth for every `wrangler`/API call is the **reused per-scope narrow token** of `
|
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
25
|
+
> **Client accounts on a multi-tenant install — every Cloudflare call in this skill runs through the storage broker.** A client sub-account is issued no Cloudflare credential: after the 1631 storage isolation its `secrets/cloudflare.env` carries no master, and `cf-token.sh` denies it the `pages` scope with `reason=not-house`. That denial is the boundary working, not a broken token, and it is never worked around by minting, by sourcing the house env, or by asking anyone for a token. Read every `cf-token.sh` and `wrangler d1 execute` line below as the **house / single-tenant** path; each one names its client substitute beside it. The map is one-to-one — `storage-d1-create` for a new database, `storage-d1-query` for every SQL statement, `storage-pages-create` to claim a brand-new Pages project, `storage-pages-deploy` to publish it. `storage-d1-query` runs `wrangler d1 execute <name> --remote --json` house-side, so every SQL statement in this skill transfers verbatim and the result is always JSON. The one exception is § 1a Access gating, which needs an Access-scoped token the broker does not offer: a client account that needs a gated document asks the house to apply the gate.
|
|
26
|
+
>
|
|
27
|
+
> **Never ask a client, a signer, or any client contact to create or send a Cloudflare token.** Provisioning a master is an operator action on the house account. A credential request sent to the person you are building the document for is a failure of this skill, not a remediation for one.
|
|
28
|
+
|
|
25
29
|
## 0. Pre-flight — block on each prerequisite
|
|
26
30
|
|
|
27
31
|
Do **not** deploy until all three pass. Each failure has one exact remediation; stop and give it.
|
|
@@ -31,7 +35,13 @@ Do **not** deploy until all three pass. Each failure has one exact remediation;
|
|
|
31
35
|
|
|
32
36
|
Dispatch (§ 6) sends through `email-send`; without a configured inbox the acceptance is captured but never delivered.
|
|
33
37
|
|
|
34
|
-
2. **The Cloudflare master token must exist.**
|
|
38
|
+
2. **The Cloudflare master token must exist — house and single-tenant accounts only.** Which case you are in is a property of the account, so read it rather than assume it:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
jq -r '.role // "unset"' "${ACCOUNT_DIR}/account.json"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`client` means the broker path (the callout above): the master is absent by design, this item does not apply, and you go straight to item 3. Anything else is the house or single-tenant path, which runs the check below. If that command instead errors `Could not open file /account.json`, `ACCOUNT_DIR` is unset — that is item 3's failure surfacing early, so settle item 3 first and come back rather than guessing which path you are on. With `SECRETS_DIR` per `api.md` (`~/<brand>-code/data/accounts/<accountId>/secrets`):
|
|
35
45
|
|
|
36
46
|
```bash
|
|
37
47
|
( test -s "${SECRETS_DIR}/cloudflare.env" && grep -q '^CLOUDFLARE_API_TOKEN=' "${SECRETS_DIR}/cloudflare.env" ) \
|
|
@@ -41,6 +51,8 @@ Do **not** deploy until all three pass. Each failure has one exact remediation;
|
|
|
41
51
|
On `missing`, stop:
|
|
42
52
|
> "There's no Cloudflare master token. Provision it once per `cloudflare/references/api.md` § Provisioning the master token, then ask me again."
|
|
43
53
|
|
|
54
|
+
That provisioning is an operator action on the house account. Never relay it onward, and never ask anyone outside the operator seat to create or send a Cloudflare token — not a client, not a signer, not a client's own hosting contact.
|
|
55
|
+
|
|
44
56
|
3. **The account directory must be set (attachment capability).** `email-send` attaches the signed PDF by absolute path under the account directory, and § 5 persists the base PDF there. If `ACCOUNT_DIR` is unset, the attachment silently degrades to a **text-only** send — neither party receives the PDF — and there is nowhere to persist the base render. Assert it before any deploy or sweep:
|
|
45
57
|
|
|
46
58
|
```bash
|
|
@@ -298,6 +310,8 @@ document.getElementById("esign").addEventListener("submit", async (e) => {
|
|
|
298
310
|
|
|
299
311
|
Follow `d1-data-capture.md` for creating the database, the `wrangler.toml` binding, and the both-Pages-Edit-**and**-D1-Edit token. The schema here is generic — it imposes no business fields; operator-defined fields live in `captured_json`:
|
|
300
312
|
|
|
313
|
+
> **Client account:** create the database with `storage-d1-create` if `storage-d1-list` does not already show it, then run the exact statement below through `storage-d1-query` (`name` is the database, `sql` is the statement verbatim). The schema, the column order, and both uniqueness guards are unchanged — including the "keep `doc_ref` defined before `token`" rule below, which is a property of the SQL, not of how it is executed.
|
|
314
|
+
|
|
301
315
|
```bash
|
|
302
316
|
CLOUDFLARE_API_TOKEN="${MINTED_PAGES_D1}" wrangler d1 execute <db-name> --remote --command \
|
|
303
317
|
"CREATE TABLE IF NOT EXISTS acceptances (
|
|
@@ -426,6 +440,8 @@ export const onRequestGet: PagesFunction<Env> = async ({ request, env }) => {
|
|
|
426
440
|
|
|
427
441
|
Deploy the document + both Functions via `hosting-sites.md`, with the both-Pages-Edit-and-D1-Edit token. The `[[d1_databases]]` binding in `wrangler.toml` is what wires the deployed Functions to the `acceptances` database.
|
|
428
442
|
|
|
443
|
+
> **Client account:** claim a brand-new Pages project with `storage-pages-create`, then publish it with `storage-pages-deploy` from a folder under the account's own `sites/`. Create first — a `storage-pages-deploy` against a project with no owner on record fails at `reason=unregistered`. A project that already exists on Cloudflare and was not created by this account is the house-adopt case (`storage-pages-adopt`, house admin only), so ask the house rather than re-creating it under a second name. The deploy itself runs house-side, so the Pages credential never enters the account. Keep `wrangler.toml` with its `[[d1_databases]]` binding at the root of that site folder exactly as the house does: the broker copies the tree to a staging dir with any root `wrangler.toml` filtered out and points wrangler at the copy, so the binding stays fully in force while the config is never published (a published `wrangler.toml` discloses the D1 database id and the R2 bucket name, both of which embed the account id). The site name is a single path segment; a name containing `/` is refused. Everything after the deploy — the base render, reading every rendered page, the handed-back `https://` URL — is unchanged.
|
|
444
|
+
|
|
429
445
|
**Gated sites also ship the neutral root `index.html` (§ 1a).** When the document is Access-gated, the neutral portal goes in the **same Pages output dir** as the document(s), so the production deploy serves it at `/` in the same shot — no separate deploy. Redeploying *only* the root portal needs a **Pages-Write-only** token: the portal touches no database, so no D1 scope is minted for it.
|
|
430
446
|
|
|
431
447
|
**Render the base PDF once, here, keyed by `DOC_REF`.** Immediately after the deploy, render the live document to PDF a single time and persist it under the account directory (§ 1). This is the *only* place the browser is used — `browser-navigate` to the deployed document URL, then `browser-pdf-save`, the `invoicing.md` step-4 pattern:
|
|
@@ -447,7 +463,9 @@ Before persisting, **read every rendered page** of `base.pdf` — full-bleed pag
|
|
|
447
463
|
|
|
448
464
|
Dispatch runs **only** inside a live operator session on the account's own device — when the operator asks for new acceptances, or when an in-session watcher running inside a still-live session performs the sweep. There is no off-device dispatcher; never register a Claude Code `/schedule` routine or any headless/cloud scheduler to run it (§ 8.2 says why). Mint one **D1-Edit** token here — `${MINTED_D1_EDIT}` — per `api.md` § Minting a narrow token, resolving the permission-group id as `d1-data-capture.md` § 0 does. Reads use the Edit token too: the D1 **query** endpoint rejects a D1-Read token (`d1-data-capture.md`), so a separate read-scoped token is not minted.
|
|
449
465
|
|
|
450
|
-
|
|
466
|
+
> **Client account:** mint nothing. Both statements in this section run through `storage-d1-query` against the same database, executed house-side, and the read returns JSON either way. Everything else about dispatch is identical: it still runs only inside a live operator session, it still stamps the persisted base, and it still flips `swept` one row at a time after both sends verify.
|
|
467
|
+
|
|
468
|
+
1. **Read the unswept rows** with `${MINTED_D1_EDIT}` (client account: the same `SELECT` through `storage-d1-query`):
|
|
451
469
|
|
|
452
470
|
```bash
|
|
453
471
|
CLOUDFLARE_API_TOKEN="${MINTED_D1_EDIT}" wrangler d1 execute <db-name> --remote --json --command \
|
|
@@ -495,7 +513,7 @@ Dispatch runs **only** inside a live operator session on the account's own devic
|
|
|
495
513
|
|
|
496
514
|
**Owner-copy visibility.** The owner copy only *arrives* if the agent's mailbox actually receives mail addressed to the business address. A recipient-filter that drops mail to the business address (the bug fixed in `rubytech-shared-catchall-mailbox`) makes the owner copy vanish while the signer copy arrives — check that filter first if the owner reports a missing confirmation.
|
|
497
515
|
|
|
498
|
-
- **Mark this row — and only this row — swept, once both sends return a verified result**, keyed by its `id
|
|
516
|
+
- **Mark this row — and only this row — swept, once both sends return a verified result**, keyed by its `id` (client account: the same `UPDATE` through `storage-d1-query`):
|
|
499
517
|
|
|
500
518
|
```bash
|
|
501
519
|
CLOUDFLARE_API_TOKEN="${MINTED_D1_EDIT}" wrangler d1 execute <db-name> --remote --command \
|
|
@@ -512,6 +530,8 @@ The acceptance flow is proven end-to-end on the **live** Pages deployment — th
|
|
|
512
530
|
|
|
513
531
|
**When the document is Access-gated (§ 1a), `/api/*` is gated too** — so the `curl` POSTs to `/api/accept` and the `GET /api/status` below are themselves **Access-challenged (302 to login), not direct 200s**. Run this end-to-end verification either **before** the gate is applied, or from a context that can authenticate to Access — the same authenticated-session requirement § 5's base render already carries. The `wrangler d1 execute` rows reach D1 through the Cloudflare API, not the gated host, so they verify unchanged.
|
|
514
532
|
|
|
533
|
+
> **Client account:** the `curl` steps are unchanged — they hit the public Pages host and need no credential. Every `wrangler d1 execute` step below runs through `storage-d1-query` with the same SQL, and the row counts it must return are the same. The contract is the D1 row either way, never the POST status.
|
|
534
|
+
|
|
515
535
|
```bash
|
|
516
536
|
# 1. POST a first acceptance to the live Function.
|
|
517
537
|
curl -sS -X POST -H "Content-Type: application/json" \
|
|
@@ -547,7 +567,7 @@ Surface every step as verb + target ("inserting a test acceptance", "sweeping un
|
|
|
547
567
|
|
|
548
568
|
## 8. Failure modes and the signal for each
|
|
549
569
|
|
|
550
|
-
The flow has no application logging — the signal surface is the **D1 row state** plus the persisted-artifact filesystem, reconciled by standing checks. Every `wrangler d1 execute` below uses the **D1-Edit** token. The failure modes that emit no event are the ones this section exists to cover.
|
|
570
|
+
The flow has no application logging — the signal surface is the **D1 row state** plus the persisted-artifact filesystem, reconciled by standing checks. Every `wrangler d1 execute` below uses the **D1-Edit** token; on a client account every one of them runs through `storage-d1-query` with the same SQL instead, and § 8.9 is the house's to run because Access has no broker tool. The failure modes that emit no event are the ones this section exists to cover.
|
|
551
571
|
|
|
552
572
|
### 8.1 POST silently 500s at the insert (token missing D1 Edit)
|
|
553
573
|
|
|
@@ -559,7 +579,7 @@ The sweep never ran, or `email-send` failed after the row existed — no log, be
|
|
|
559
579
|
|
|
560
580
|
> Dispatch runs **only** inside a live operator session on the account's own device. Never register a Claude Code `/schedule` routine, a `RemoteTrigger`, a `CronCreate` durable job, or any off-device/headless scheduler to run the sweep. `/schedule` spawns a fresh agent on **claude.ai's cloud**, which has none of this account's D1 token, `email-send`, `stamp.mjs`, or `ACCOUNT_DIR` — it physically cannot stamp or send. It is a Claude Code capability, not a Maxy one, and it is not a substitute for the in-session sweep. Monitoring and dispatch happen in-session, while the session is live. That is the only path.
|
|
561
581
|
|
|
562
|
-
The reconciliation query, run inside a live session at open and before close:
|
|
582
|
+
The reconciliation query, run inside a live session at open and before close (client account: through `storage-d1-query`):
|
|
563
583
|
|
|
564
584
|
```bash
|
|
565
585
|
CLOUDFLARE_API_TOKEN="${MINTED_D1_EDIT}" wrangler d1 execute <db-name> --remote --command \
|
|
@@ -585,7 +605,7 @@ d="${ACCOUNT_DIR}/e-sign/<DOC_REF>"
|
|
|
585
605
|
|
|
586
606
|
### 8.4 Duplicate-acceptance row by token (same-signer idempotency regressed)
|
|
587
607
|
|
|
588
|
-
Signal: a `token` appears more than once — the `token`-UNIQUE handling regressed.
|
|
608
|
+
Signal: a `token` appears more than once — the `token`-UNIQUE handling regressed (client account: through `storage-d1-query`).
|
|
589
609
|
|
|
590
610
|
```bash
|
|
591
611
|
CLOUDFLARE_API_TOKEN="${MINTED_D1_EDIT}" wrangler d1 execute <db-name> --remote --command \
|
|
@@ -596,7 +616,7 @@ Healthy signature: re-POSTing a token leaves its count at one.
|
|
|
596
616
|
|
|
597
617
|
### 8.5 More than one acceptance per `doc_ref` (the lock failed — primary standing check)
|
|
598
618
|
|
|
599
|
-
The lock's failure is a **no-event** failure: an extra row appears silently — the `doc_ref` guard was dropped on a redeploy, never applied to a pre-existing table, or a race slipped through. This is the primary lock check; run it on the same cadence as the § 8.2 reconciliation, reusing the same D1-Edit token:
|
|
619
|
+
The lock's failure is a **no-event** failure: an extra row appears silently — the `doc_ref` guard was dropped on a redeploy, never applied to a pre-existing table, or a race slipped through. This is the primary lock check; run it on the same cadence as the § 8.2 reconciliation, reusing the same D1-Edit token (client account: through `storage-d1-query`):
|
|
600
620
|
|
|
601
621
|
```bash
|
|
602
622
|
CLOUDFLARE_API_TOKEN="${MINTED_D1_EDIT}" wrangler d1 execute <db-name> --remote --command \
|
|
@@ -635,7 +655,7 @@ CLOUDFLARE_API_TOKEN="${MINTED_ACCESS}" curl -sS \
|
|
|
635
655
|
|
|
636
656
|
Run on the same cadence as the § 8.2 reconciliation, but with an **Access-scoped** token — not the `${MINTED_D1_EDIT}` the other §8 checks share (this is a `curl` to the Access API, not a `wrangler d1` query). Two adjacent failures are **not** this one and need a different fix: a signer **refused after** the login page offered One-Time PIN is an allowlist miss (their email is absent from the policy `include`, § 1a); a signer who never receives the code despite the method being offered is an email-deliverability problem, not a gate defect. Gating is configuration state, so dispatch is unaffected — the sweep still stamps the persisted base (§ 1a, § 6), never the gated page.
|
|
637
657
|
|
|
638
|
-
**Ground-truth lifeline** for one document's whole acceptance lifecycle:
|
|
658
|
+
**Ground-truth lifeline** for one document's whole acceptance lifecycle (client account: through `storage-d1-query`):
|
|
639
659
|
|
|
640
660
|
```bash
|
|
641
661
|
CLOUDFLARE_API_TOKEN="${MINTED_D1_EDIT}" wrangler d1 execute <db-name> --remote --json --command \
|