> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tuturuuu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Wave-1 native publishers

> Owner-provisioned staging, sealed native publication profiles, production holds and rollback evidence.

## Scope and admission

Land the production hold before these publisher changes. Meet, Calendar, Mail and
Apps production publication remains **held for wave-1 cutover**. The production
planner holds in `tuturuuu.ci.ts` remain authoritative. Native Calendar/Mail/Apps
jobs additionally report the source hold in `scripts/ci/wave1-native-profiles.json`;
removing either hold alone does not authorize publication. A later explicit cutover
PR must reconcile both policies and its exact production promotion range.

These workflows add no automatic schedule and perform no provider or DNS setup.
PR profile qualification has read-only deployment permission. Each caller grants
`deployments: write` only to its separate staging publication job, after successful
profile qualification and staging policy admission on a main push or dispatch.
The reusable qualification workflow never calls a publisher, so read-only callers
do not need to grant nested write permissions. `wave1-native-permissions.test.js`
covers this boundary, including same-repository PR events.

Main pushes and trusted main dispatch can publish **staging only**, after provisioning
the repository enable flag and an exact source/artifact admission. PRs and other branches qualify artifacts without
publication. Existing Vercel deployments, project framework settings and disabled
Git deployment remain unchanged. Existing central APIs and scheduler/provider owners
stay authoritative; a native frontend is not a completed Vercel exit.

## Identities and resource continuity

Owner decision: staging stays in the production Cloudflare account. The
`stagingAdmission` record in `scripts/ci/wave1-native-profiles.json` records this
exception as `same-account-staging-only`, with `shared-account` residual risk and
a required scoped token. The account identity is supplied by the repository variable
`CLOUDFLARE_STAGING_ACCOUNT_ID`; publication compares its value with the reviewed
profile account and fails closed if absent or different. No new account is created.
This is resource and credential isolation within one account, with shared account
administration, account-wide limits and billing risk. A secret name cannot prove
its actual permission scope: the owner must provision and review a token limited
to the staging operations/resources supported by Cloudflare, and acknowledge any
remaining account-level Worker permission exposure before admission.
`CLOUDFLARE_WORKERS_SUBDOMAIN` is the owner's actual account subdomain, not a guessed
hostname. Configure it as a repository variable. Staging hosts are the corresponding
Worker name followed by `.<CLOUDFLARE_WORKERS_SUBDOMAIN>.workers.dev` as an identity
only; those URLs are disabled for serving.

| App | Staging Worker | Held production Worker / canonical host |
| - | - | - |
| Calendar | `tuturuuu-calendar-wave1-staging` | `tuturuuu-calendar` / `calendar.tuturuuu.com` |
| Mail | `tuturuuu-mail-wave1-staging` | `tuturuuu-mail` / `mail.tuturuuu.com` |
| Apps | `tuturuuu-apps-wave1-staging` | `tuturuuu-apps` / `apps.tuturuuu.com` |

Publication profiles are derived explicitly from the original Void-emitted config;
the source configs are retained. The derived config, original modules/assets and
manifest are sealed together, then restored without rebuilding. Nonempty source
resource bindings, routes and unreviewed vars fail qualification rather than being
dropped. Frontends have only ASSETS; Calendar and Mail preserve central API ownership.
There is no D1, KV, DO, queue or scheduler binding for these three frontends.
The publisher uses a separate owner-provisioned D1 control database; it is never
bound to application Workers.

Staging uses `https://staging.tuturuuu.com` and staging Supabase/public configuration.
It does not activate production callbacks or processors. Mail's production R2 S3
access continues to the existing `tuturuuu-mail` bucket; its staging descriptor names
`tuturuuu-mail-wave1-staging` with separate credentials. Never repoint the existing
`tuturuuu-mail-email-routing` ingestion Worker, signing identity, bucket, MX records
or canonical webhook as part of frontend staging. Preserve optional SES credentials
for legacy attachment reads before production admission.

Apps staging has no canonical routes, `APPS_CANONICAL_HOST_ENABLED=0` and noindex.
Its separately built production profile sets the fence to `1` and declares its
canonical Custom Domain. That configuration is qualified by original/restored
workerd checks while publication remains held. Merely attaching the staging profile
to the canonical host would return 503 and is forbidden.

## One-time owner provisioning

1. Retain the production hold. Create protected GitHub environments
   `wave1-<app>-staging` and `wave1-<app>-production` for Calendar, Mail and Apps.
   Production needs explicit release-owner approval. Use a least-privilege
   `CLOUDFLARE_STAGING_API_TOKEN` for staging only; this is the only deploy-token
   secret referenced by staging publication. Never store a production token under
   that name. The workflow never reads `secrets.CLOUDFLARE_API_TOKEN` or production
   token secrets. Only the staging token is mapped to Wrangler's standard
   `CLOUDFLARE_API_TOKEN` process variable, after admission. Never copy credential
   values into source or evidence. Set `CLOUDFLARE_STAGING_ACCOUNT_ID` to the reviewed
   shared account identity. Missing or mismatched identity denies publication.
   Provision `WAVE1_CONTROL_READ_TOKEN` with repository Variables read permission
   for the fresh stop-fence observation. Do not assume `actions: read` supplies
   that permission; see [GitHub's variable API permissions](https://docs.github.com/en/rest/actions/variables#get-a-repository-variable).
   Both reusable workflows declare and explicitly forward only these two staging
   credentials plus the two public Supabase inputs; neither uses secret inheritance.
   Only the protected publisher step receives deploy/control process variables.
   Keep deploy/control values exclusively in the protected staging environment,
   restricted to main and owner approval; never give PR jobs a repository-level copy.
   The staging deploy token also needs D1 write access to the staging control database.
   GitHub job tokens and the Variables-read token must have no D1 authority.
2. Set the actual `CLOUDFLARE_WORKERS_SUBDOMAIN` repository variable. Provision the
   three staging Workers with `workers_dev=false`, `preview_urls=false`, no routes,
   and an accepted initial version. The publisher intentionally refuses a missing
   Worker or missing rollback deployment instead of bootstrapping resources.
   Bootstrap through the owner's reviewed infrastructure procedure with the identities
   and resource descriptors in `wave1-native-profiles.json`; do not use canonical configs.
3. Provision Mail's isolated staging R2 bucket and scoped S3 credentials according to
   that descriptor. Never reuse production storage/resource IDs or encryption/signing
   keys in staging. Grant only staging access to staging secrets. Confirm the existing staging central
   issuer/API and Supabase instance are admitted for disposable acceptance.
4. Provision Worker secret **names** from each app's `secrets` list in the profile
   file. Values stay in the provider. The workflow checks names through the API and
   never uploads secrets. Calendar additionally requires the registered Google and
   Microsoft callback URLs declared in the profile vars. Mail's ingestion secret,
   connected-account encryption key and storage credentials preserve the owning
   environment's identity. Optional names are listed separately; provider acceptance
   must identify which are required for the configured transports and old attachments.
5. Supply GitHub build/publication secret names `STAGING_SUPABASE_URL` and
   `STAGING_SUPABASE_PUBLISHABLE_KEY`. Held production builds retain fixtures and
   read no production inputs. Only public Supabase inputs reach staging builds.
   Missing values allow source-only fixture artifacts, which cannot publish: the
   publisher rejects fixture URLs, different public-input fingerprints or a different
   account subdomain. Environment overrides must agree with the qualified artifact.
6. After owner review, set the exact `WAVE1_STAGING_PUBLICATION_ADMISSION` record
   described below and repository variable `WAVE1_STAGING_PUBLISH_ENABLED=true`.
   Only that admitted main source and artifact can publish once; later sources
   default to denied. Retain the same qualified archive when resuming a failed
   publication job after updating admission.
   Turning it off is the durable stop fence for subsequent writes; the publisher reads
   it freshly immediately before its sole deployment. This cannot cancel a write
   already accepted by Cloudflare. No resources, settings, secrets or DNS were created
   by authoring these workflows.

## Exact artifact and publication gates

`wave1-native-app.yaml` builds staging and held production profiles in exact-source
CI. Each runs original workerd acceptance, Wrangler dry-run, seal, bounded archive,
separate-job restore, repeated workerd acceptance/dry-run and final seal verification.
Mail has its own original/restored native Worker checks. Calendar and Apps keep their
existing deeper SSR/offline/RPC/browser gates; the new checks do not replace them.

The native public `/api/build-info` endpoint reports bundled full SHA, app and
environment before session middleware, accepts only GET/HEAD/OPTIONS, and is no-store.
It exposes release metadata only; the shared [product contract](https://docs.tuturuuu.com/platform/applications/native-release-identity.md) records scope and exceptions. Original/restored checks compare this identity,
actual static asset bytes, anonymous private-page login handoff for Mail/Calendar,
and Apps' staging canonical refusal versus admitted production fence behavior.
Runtime credentials are disposable and network egress is denied. This finite fixture
is not hosted provider, signed-in browser, or complete SDK descendant-cleanup proof.
CI step/job timeouts fail a stuck runtime rather than relaxing assertions.

The publisher restores the same-run archive and rechecks runtime before credentials
are introduced. It observes [Cloudflare's deployment/version APIs](https://developers.cloudflare.com/api/resources/workers/subresources/scripts/subresources/deployments/methods/list/) and captures the existing deployment's weighted rollback versions,
checks expected secret names, rechecks the fresh stop fence and seal, then invokes
Wrangler once against the sealed config. The version tag is the complete artifact
receipt digest and its message is the source SHA. The hosted active version/tag
and disabled workers.dev/preview state must match before recording a GitHub
deployment marker. Original/restored CI proves the HTTP build identity locally.
Staging and production marker environments remain distinct.

## Finite publication admission and uncertain outcomes

`WAVE1_STAGING_PUBLISH_ENABLED=true` alone authorizes zero uploads. The owner must
also set the repository variable `WAVE1_STAGING_PUBLICATION_ADMISSION` to one exact
app/source/artifact record after reviewing the qualified artifact receipt. All
fields are required, unknown fields are refused, and the account is named by
variable reference, never copied into the admission JSON:

```json theme={null}
{
  "schema": 1,
  "app": "mail",
  "sourceSha": "<full admitted source SHA>",
  "artifactSha256": "<SHA256 from artifactDigest of wave1-artifact.json>",
  "isolation": "same-account-staging-only",
  "accountIdEnv": "CLOUDFLARE_STAGING_ACCOUNT_ID",
  "tokenSecret": "CLOUDFLARE_STAGING_API_TOKEN",
  "scopedTokenRequired": true,
  "residualRisk": "shared-account",
  "publicationVariable": "WAVE1_STAGING_PUBLICATION_ADMISSION",
  "maxUploadsPerArtifact": 1
}
```

This admits at most one upload for that artifact, with zero application retries.
Later main pushes and other apps are denied until the owner explicitly replaces
this record. Deleting the record or disabling the enable variable stops future
uploads. Both are freshly read from GitHub before preflight and again immediately
before upload; deletion, malformed data, denial or timeout fails closed. The earlier
policy job checks source admission; the publisher additionally checks the exact
restored digest. These controls stop publication, not invocations of an already
serving Worker; the owner must separately disable serving to stop its runtime spend.

Before enabling publication, the owner must provision a dedicated staging D1
control database and set `WAVE1_STAGING_ATTEMPT_D1_ID`. This is option (a): D1 SQL
supports atomic comparison against the previous record, whereas KV visibility can
lag, and repository Deployments remain writable/deletable by PR job tokens.
No new GitHub App/bot credential or public control Worker is needed. The table is:

```sql theme={null}
CREATE TABLE wave1_attempts (
  app TEXT PRIMARY KEY,
  record TEXT NOT NULL
);
```

Seed one row per app (`wave1-mail-staging`, `wave1-calendar-staging`,
`wave1-apps-staging`) through the owner's separately reviewed infrastructure
procedure. The `record` value is the output of exported `signAttemptState(data,
stagingToken)` from `scripts/ci/wave1-native-attempt.mjs`, with data shaped as:

```json theme={null}
{
  "schema": 1,
  "scope": {
    "databaseId": "<WAVE1_STAGING_ATTEMPT_D1_ID>",
    "repository": "tutur3u/platform",
    "app": "mail",
    "worker": "tuturuuu-mail-wave1-staging",
    "accountId": "<CLOUDFLARE_STAGING_ACCOUNT_ID>"
  },
  "entries": []
}
```

The token must come from private environment injection, never command arguments,
source or logs. The signed envelope contains serialized data plus a domain-separated
HMAC-SHA256, using only the staging deploy token as signing authority. Each entry
binds the original GitHub run ID/attempt, full admission, SHA, digest, account,
Worker and rollback versions to progress. Only a genuinely unused app may be seeded
with empty history. Never reseed an existing app to retry: migrate/reconcile prior
GitHub attempt records and provider versions first, preserving all consumed and
uncertain identities. Token rotation requires owner verification and re-signing
of the existing complete ledger, never resetting its history.

The publisher only SELECTs and conditionally UPDATEs the existing app row; it never
creates a missing row/table or inserts a replacement. Before any upload it persists
signed pending state with a compare-and-swap and authenticates the readback. A
lost write response remains consumed/uncertain on restart. Missing/deleted records,
invalid signatures, wrong scopes, failed queries and concurrent changes block upload.
An ordinary GitHub deployment/status, including a forged terminal or newer record,
has no authority over this ledger. The ordinary success marker remains diagnostic.
The exact owner admission remains a separate fresh GitHub Variables observation;
a valid D1 ledger alone grants no upload.

A definitive final fence/seal refusal records failed and consumes admission. Upload
exceptions remain pending, and failures after a returned upload stay uploaded.
Any preceding unresolved entry blocks a different artifact; terminal entries remain
in the signed history, so consumption cannot be erased by renewing the admission.

Reruns load this ledger and inspect the [Worker versions API](https://developers.cloudflare.com/api/resources/workers/subresources/scripts/subresources/versions/methods/list/),
including inactive versions. Each listed version is read by ID because the list
response does not include artifact annotations. Exactly matching SHA plus digest is
reconciled against active 100% deployment, version annotations and disabled
workers.dev/preview URLs without uploading or activating anything. Public HTTP
identity probing is deliberately absent while ingress is disabled; real workerd
identity and behavior acceptance remains required on original/restored bytes in CI.
An inactive match remains uploaded until the owner resolves
activation under separate authority. A previous attempt with no matching version is
blocked, even after failed status; absence is not proof that the original write did
not happen. Preserve the original operation identity, inspect provider/audit evidence,
and obtain a new explicitly reviewed artifact admission only after resolving an
uncertain outcome. A lost Wrangler receipt does not permit a second upload.

Reads have 15-second deadlines, 1 MiB response bounds and no application retry.
The signed ledger is at most 512 KiB and fewer than 100 retained entries. A full
ledger blocks publication and requires reviewed archival/reconciliation; it is never
automatically truncated. Each SQL query uses the app primary key and at most one
row; a normal success uses seven D1 queries (one read, three conditional updates
and three readbacks), six other provider reads with empty version history, and four
GitHub variable reads. Version history has one page of fewer than 100 entries;
a full/additional page blocks, and each version needs one detail read. There is no
application retry. The publication step has a five-minute watchdog; each single
Wrangler invocation has a 180-second limit. Wrangler's internal asset requests/retries
are additional, bounded by that watchdog and the 50,000-member / 1 GiB artifact
ceiling. Non-cancelling app/environment concurrency and SQL conditional updates
protect consumption across runners. A new owner admission is required for another
artifact. No recurring producer, automatic renewal or public control endpoint exists.

## Serving cost and emergency stop

All staging profiles, including the prepared Meet frontend/realtime profiles, set
`workers_dev=false`, `preview_urls=false` and `routes=[]`. These
[Wrangler controls](https://developers.cloudflare.com/workers/wrangler/configuration/)
remove public ingress rather than charging for a secret-header check on each request.
No public identity exception, shared-secret gate, paid Access product or rate-limit
product is required. The publisher also observes disabled subdomain and preview
serving before marking an upload accepted. Do not attach a Custom Domain, zone Route,
external service caller, cron or queue to these identities. The owner must verify
that existing hosted identities have no such attachment before enabling publication;
source configuration alone is not hosted-topology evidence. The disabled workers.dev
URLs retained in app vars are identity placeholders, not usable callback/media URLs.

With no public ingress or scheduled/queue producers, arbitrary Internet traffic
cannot invoke these Workers; finite publishing and owner-controlled private probes
are the remaining work. This does not cap shared-account spend or an independently
added service binding/producer. Browser/provider callback/media acceptance needs a
separately approved private access plan; do not re-enable workers.dev to make it pass.

For emergency stop, first set `WAVE1_STAGING_PUBLISH_ENABLED=false` and remove the
exact admission to fence future uploads. In Cloudflare, disable workers.dev/preview
serving and remove any unexpected Routes/Custom Domains. If execution continues or
its ingress cannot be established, delete **only the named staging Worker** in the
Workers dashboard (Settings / Delete) under release-owner custody; include both Meet
staging Workers if used, never a production identity. Verify its disabled/deleted
state and absence of further executions. Preserve the D1 ledger and provider/audit
receipts: deleting a Worker does not restore consumed admission or permit replay.
No deletion or other provider mutation is performed by these source tests.

## Meet off-canonical profile

`apps/meet/void.staging.config.ts` is selected only by
`MEET_DEPLOYMENT_PROFILE=staging`; ordinary source CI retains its existing default.
It uses `tuturuuu-meet-wave1-staging`, no routes, isolated `MEET_LIVE` namespaces,
self-reference to that same staging Worker and bucket
`tuturuuu-meet-wave1-staging-cache`. Realtime's separate
`apps/meet-realtime/wrangler.staging.jsonc` uses
`tuturuuu-meet-realtime-wave1-staging`, no canonical route and its own local DO
namespaces/migration history. Its secret names retain the protocol contract but must
refer to disposable staging SFU/TURN credentials, never production resources.
The staging frontend omits the account-level Images binding; shared production
Images access is not admitted.

The owner must provision those staging identities, the isolated cache bucket,
self-service binding, stage Supabase/central issuer and disposable
SFU/TURN app/key before CI building/qualifying/publishing this profile. Meet staging
publication is not automated by these three frontend publishers. This is a defined
profile, not a deployed or workerd-qualified Meet staging claim and not a no-staging
exception. Before any canonical Meet release, retain original/restored gates, qualify
this profile off canonical traffic and exercise hosted two-participant media/reconnect.
Meet's production workflow captures rollback versions for both frontend and realtime.

## Remaining cutover and rollback

Require all applicable exact-main tests/type/lint/native builds, original/restored
artifacts and shared-supplier checks. After a separately approved private ingress plan, collect real signed-in EN/VI session,
refresh/MFA/logout/privacy and app-specific hosted evidence: Calendar provider/
recurrence/offline/Tasks; Mail provider sends with original-operation readback,
webhook/attachments; Apps catalogue anchors/redirects/query/RPC; Meet real media/DO/
SFU/TURN. workers.dev does not itself prove shared canonical-domain cookie continuity.

Before a later cutover PR, capture authoritative DNS/proxy/Route/Custom Domain IDs,
immutable Vercel fallbacks, current Worker versions, rollback operator, explicit
promotion range and compatible secrets/state. Production configs currently declare
Custom Domains: their eventual publication is a traffic switch, not just code upload.
Do not enable `WAVE1_PRODUCTION_PUBLISH_ENABLED`, remove holds or attach routes until
that later release is expressly approved. Retain Vercel framework/domain settings.

Rollback uses the retained publication receipt's exact prior version(s), not a new
build. Under release custody, restore frontend code and Meet realtime when changed.
For Vercel exits, restoring code alone does not restore traffic: reverse the exact
captured Route/Custom Domain and DNS/proxy topology to the saved deployment. Observe
Apps for 14 days and Meet/Mail/provider-critical Calendar for 30 days and relevant
business cycles. Provider side effects and persistent data do not roll back with code.

## Source-only validation

Run `ttr resources run -- node --test scripts/ci/wave1-native-publishers.test.js`
and `scripts/ci/wave1-native-publication.test.js` for resource/profile isolation,
exact bytes and relocation, unsafe archive rejection,
production holds, source/ref admission, fresh-stop failure, one-write bounds, unknown
outcome retention, rollback shape, identical-version identity and workflow gate order.
The real `main` publish entrypoint runs with sealed fixtures and bounded counting
GitHub/Cloudflare/CLI transports. Tests cover post-preflight disable/delete/deny/
timeout/admission changes, fresh-runner restart, inactive versions and lost receipts.
`wave1-native-attempt.test.js` executes the conditional SQL against SQLite and covers
concurrent consumers, deletion, authentic recovery and scope binding. The publisher
fixtures reject forged terminal/newest records, signatures made with a PR token,
missing/deleted state and deletion during consumption, always with zero uploads.
Workflow contracts assert exact staging credential forwarding at every call boundary.
A copied entrypoint with its final fresh check removed must fail the same zero-upload
assertion; it reaches exactly one forbidden fake upload. These are source regression
proofs, not hosted token-scope, emitted app or deployment evidence.
Real app builds and workerd gates run only in CI. No local build or production
workflow dispatch is part of this validation.

## Held validation and staging admission

The shared fail-closed `production-publication-policy.ts` decision also applies to
native publisher entrypoints, alongside the profile hold. Production profile builds
use disposable public inputs and no production credentials. Staging build inputs are
read only for a trusted main push or dispatch; PRs use fixture inputs. The reusable
publisher itself admits only staging on those trusted events, even if a caller tries
to pass a production profile. Publication remains non-cancelling. Regression evidence
lives in `production-publication-policy.test.js`, `production-publisher-secrets.test.js`
and `wave1-native-publishers.test.js`.

Meet's app TypeScript project includes both Void configs because the default config
imports the staging config; keep that imported tooling file in the same project.

## Mail Node builtin startup compatibility

Both Mail profiles preserve the source compatibility date `2026-10-19` and flags
`nodejs_compat` and `global_fetch_strictly_public`. They share one Vite configuration;
profile derivation changes routing and resource identity after bundling. A staging
startup failure in a `failed-recipients` chunk exposed a CommonJS `require("path")` through
`sanitizeMailHtml` -> `sanitize-html` -> PostCSS,
not a difference in those compatibility flags. Void 1.1.12 skips its builtin require
adapter for its default SQLite dialect, including applications with database
inference disabled. Node compatibility does not define a global CommonJS `require`
inside an emitted ESM chunk.

The Worker entry also includes `iconv-lite` through inbound group authentication ->
`mailauth/lib/dkim/verify` -> `mailauth/lib/tools` -> `libmime/lib/charset`. Its
streaming API initialization uses a bare CommonJS `require("stream")`. The conservative
emitted-byte guard also matches that spelling in its fallback diagnostic. In a Linux
preimage reproduction, the remaining emitted match was the diagnostic example rather
than an executable call (the browser mapping disables its optional stream import).
The workerd-only plugin adapts the stream import to native `node:stream` and rewrites
only that diagnostic to describe passing the module without a CommonJS call example.
The emitted-byte guard remains unchanged; tests execute the transformed installed
iconv-lite entry and check charset decoding and stream construction.

The same graph also uses `node:buffer` throughout DKIM and libmime, plus
`node:dns`, `node:crypto` and `node:https` in mailauth tools. Charset decoding
reaches `string_decoder`; bundled stream/deprecation helpers and document preview
reach `util` and `events`. Adapt these imports through the same ESM protocol.

Mail's build plugin resolves CommonJS `buffer`, `crypto`, `dns`, `events`, `fs`,
`https`, `path`, `stream`, `string_decoder`, `url` and `util` imports in
the workerd server build to native ESM adapters, matching Void's adapter protocol. Client, development,
ESM and unrelated builtin imports keep their existing resolution. Both profiles use
this same plugin. Before original or restored runtime acceptance, the artifact gate
rejects emitted server assets containing static CommonJS Node builtin calls, including
Rolldown's `__require` helper. The conservative byte check covers bare and
`node:`-prefixed names with quoted or backtick strings. An additional AST check
follows the exported Rolldown require helper into renamed imports, so minified
calls such as ``t(`node:buffer`)`` also fail before startup. ESM imports remain
allowed. Scan every server JavaScript module, including `.mjs` and `.cjs`.
Unit and profile tests cover the adapter, the unchanged
compatibility settings and both profile rejection paths. Exact-head CI must still prove
original/restored emitted Worker startup; config tests are not emitted-byte proof.
Email-service memory rate-limit and credential-cache expiry cleanup runs lazily
during use, at most once per minute. Importing those modules must not start timers:
workerd forbids global-scope `setInterval`. TTL checks remain authoritative on
every read; the worker-import regression covers timer-free import and expiry.
The unadapted dependency graph is not specific to the staging profile; production builds share it.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.