Infrastructure Reference¶
Canonical reference for all external platform accounts, entity details, and infrastructure IDs. This doc is the single source of truth — if a value appears here and somewhere else, this doc wins.
Last updated: 2026-09-18 (HYPERDRIVE-01 — the library's Postgres host behind Hyperdrive; rtopacks.com.au's zone id corrected after DOMAIN-MOVE-01; new external-service reference binary-lane-db-01.md). Prior 2026-09-18 (ADMIN-FIRST-DEPLOY-01 — the Product account's admin surface, its padlock and its two scoped tokens). Prior 2026-09-16 (COUNT-RECONCILE-01 — the NRT store-of-record lists gain tga-nrt-content-legacy and tga-history)
Legal entities¶
UCCA Inc (US)¶
- Legal name: UCCA Inc
- DBA: Universal Capability Certification Authority
- Structure: Delaware C-Corp
- EIN: 84-4522608
- Role: Parent / platform entity. US-facing. Holds US software subscriptions, US credit program enrolments, US-denominated contracts.
⚠️ "United Community Colleges of America Inc" is dead. Do not use it anywhere.
United Central Colleges of Australia Pty Ltd (AU)¶
- Legal name: United Central Colleges of Australia Pty Ltd
- ABN: 59 168 872 535
- Trading as: RTOpacks
- Role: Australian operating entity. Trades as RTOpacks. Holds AU customer contracts, AU-denominated invoicing, AU regulatory exposure.
Entity separation principle¶
US-centric credit programs and subscriptions → UCCA Inc. AU-facing commercial activity → RTOpacks / UCCA Australia Pty Ltd. Do not mix invoicing or subscriptions across entities without a clear reason.
Cloudflare¶
Accounts¶
- RTOpacks PRODUCTION CF account ID:
c93403113c55c1df41d43e4c878d3054— the truth. New work lands here. - RTOpacks Prototype CF account ID:
f95d45376ebeeeaf011a4f0ec0fb7b38— the frozen estate. Not touched. (A4, Tim 2026-09-05; CANON-PASS-02-DELIBERATE. The same fact is in the CLOUDFLARE-FIRST RULE instanding-rules.md.) - Legacy UCCA CF account ID:
e5a9830215a8d88961dc6c80a8c7442a(connected via MCP; limited active use)
THE TWO-ACCOUNT SPLIT (owed since 2026-08-15, landed at A1-PARSE-LOAD-01 Gate 5)¶
There are TWO RTOpacks Cloudflare accounts, both under admin@rtopacks.com.au. There is no
FENCE-PROTOCOL-01 issue; they are a deliberate prototype/rebuild split.
| account ID | what it holds | |
|---|---|---|
| "RTOpacks Prototype" | f95d45376ebeeeaf011a4f0ec0fb7b38 |
the frozen estate, still serving. rto-nrt-db (128 tables, 6.19 GB) + 17 R2 buckets. Read-only morgue for new work. The second bullet above is this account. |
| "RTOpacks Product" | c93403113c55c1df41d43e4c878d3054 |
the rebuild's home. pith-index-01 (capture ledger), pith-assets-01 (raw TGA bodies), pith-register-01 (the first application-shaped tables). |
Operational consequence, measured: the Cloudflare client-API limit of 1,200 requests per five minutes is documented as per API USER, not per account or per token. Both accounts sit under one email, so a bulk read on either contends with governed work on the other. This is why the A1-CORPUS-01 census owned the R2 lane exclusively while it ran.
1Password vaults mirror the account names.
Platform migration from UCCA account → RTOpacks account completed early April 2026. 9 D1 databases migrated to APAC, 25+ Workers deployed, DNS migrated, CF Access policies established, security audit completed (SEC-AUDIT-MIGRATE-01, 40 checks, 0 failures).
API tokens¶
- Account-owned
cfat_tokens validate via a scoped live call, NEVER/user/tokens/verify. Cloudflare's account-owned API token format (cfat_…, ~53 chars) returnsInvalid API Token(code 1000) from/user/tokens/verifyeven when the token is valid and active — that endpoint only verifies user tokens. To check an account token, make a real scoped call (e.g.GET /zones/<zone>/rulesets) —success: trueis the authoritative signal. (Cost ~hours during FLAG2-IAC-01, 2026-06-03, before this was understood — theterraform import401 was the real signal, not user-verify.) - R2 S3 credentials (Access Key ID + Secret Access Key, for the Terraform state backend) come from the R2 → Manage R2 API Tokens creation screen, not the generic Account API tokens page. The
cfat_"Token value" shown there is the Bearer form and is NOT what the S3 backend uses. Need Object Read & Write (Object Read only can read state but can't write the lock/state → 403 onterraform import).
Token register — the RTOpacks account (f95d4537…7b38)¶
Census taken 2026-08-27 from the account audit log (action.type=token_create|update|delete|roll,
since 2026-01-01) plus GET /accounts/{id}/tokens. Population stated: this covers ACCOUNT-owned
tokens only. User-owned tokens could NOT be enumerated — /user/tokens returns 9109 to the
cfat_ token and 403 to the wrangler OAuth token. Three tokens are active; six have ever existed.
| token | account | id | issued | status | purpose |
|---|---|---|---|---|---|
rtopacks-alex-automation |
Prototype f95d4537…7b38 |
76eb6809…f3d |
2026-04-08 | active | the broad automation token — Terraform provider + every op read script |
rtopacks-terraform-state-rw-2 |
Prototype f95d4537…7b38 |
3a8d0574…299 |
2026-06-03 | active | Terraform state R2 backend |
claude-desktop-api-access |
Prototype f95d4537…7b38 |
4743c9c5…559 |
2026-08-17 | active | Claude desktop MCP |
⚠ BRIEF-NAMES-ITS-ACCOUNT-01: this table is the PROTOTYPE account only. The Product account
has never been enumerated — its token population is UNKNOWN, not zero, and no row here says
anything about it. Owed: a screen-only census at Tim's next dashboard sitting.
No RTOpacks token has ever been named RTO_API_TOKEN. That is a secret-binding name on the
other house's Workers, not a token name — see below.
Planned least-privilege replacements — specced 2026-08-27, NOT YET MINTED (minting needs
Account API Tokens Write, which no credential in this estate holds; it is a dashboard action).
Full permission-group IDs and resource strings:
outputs/RTOP-SPEC-LEAST-PRIVILEGE-TOKEN-ROTATION-2026-08-27.md.
| planned token | scope | replaces, for |
|---|---|---|
rtopacks-terraform |
11 permission groups, account + all zones | the Terraform provider |
rtopacks-publish-artefacts |
2 groups, one bucket (rtopacks-gate-artefacts-tooling) |
scripts/publish-artefact.sh |
rtopacks-clone-backfill |
D1 Write (account) + bucket-item R/W on tga-content, radar-screenshots |
the 4 nrt-clone stages, radar-backfill-local.mjs, keyed-cardinality-baseline.mjs |
⚠ Least privilege has a hard ceiling here, and the register should say so. Cloudflare offers only
four resource scope types — account, account.zone, edge.r2.bucket, and flagship.app. R2 scopes per
bucket; D1 does not scope below the account. D1 Read/D1 Write/D1 Metadata Read are all
account-scoped, so any token carrying a D1 permission reaches all 33 RTOpacks databases.
rtopacks-clone-backfill cannot be narrowed to the two databases it uses. What it does drop is
Workers Scripts Write, Registrar Domains Admin, DNS Write, Access Write and account-wide R2 — real,
but not a reduction in D1 blast radius. Do not record it as one.
⚠ CROSS-ACCOUNT GRANT — RTO_API_TOKEN on UCCA's Workers¶
RTO_API_TOKEN is the binding name under which an RTOpacks credential was placed into the UCCA
Cloudflare account (e5a98302…442a), on Workers ucca-backup (cron 0 3 * * *) and
ucca-backup-large. This was deliberate RTOpacks-side engineering, not a leak — RTO-BACKUP-01
(2026-04-08, docs/docs/ops/rto-backup-01-report.md) built it so UCCA-account Workers could call the
D1 HTTP export API against eight RTOpacks databases and write dumps to ucca-backups/rtopacks/.
rto-nrt-db was deferred there (export >60 min), which is why its 2026-06-01 backup was taken by
hand instead.
Which credential: rtopacks-alex-automation — by elimination, not by reading the secret. It was
created 2026-04-08T07:46:37Z and was the only token on this account on the day the cross-account
path was built; no token named for UCCA or backup has ever existed.
Why this matters — the grant is far wider than a backup needs. That token carries, on this
account: D1 Read and Write (all 33 databases, rto-nrt-db included), R2 Storage Read/Write,
KV Read/Write, Workers Scripts Write, Registrar Domains Admin, DNS Write,
Access: Apps and Policies Write, Zone Write/WAF Write, Logs Write. A read-only D1-export
grant would have been three permissions; this is effectively full control of RTOpacks production,
resident in another company's account.
⚠ DO NOT DELETE THIS TOKEN. RTOpacks production holds the same credential: the Terraform provider
(infra/terraform/variables.tf), scripts/publish-artefact.sh,
scripts/keyed-cardinality-baseline.mjs, tools/radar-backfill-local.mjs, and four
scripts/nrt-clone/stage-* loaders all read it from 1Password cloudflare-api-token. The correct
action is a ROLL, not a revoke — same id, same permissions, new value — followed by updating the
1Password item. A roll kills the copy held in the other account without breaking anything here.
Rolling requires the dashboard: this token holds Account API Tokens **Read** and cannot roll itself.
STANDING RULE, from this incident: no RTOpacks credential is issued to another account without a
register row here naming the account, the scope, and the expiry — and the scope is the minimum the
job needs, never a general-purpose token. RTO_API_TOKEN had no row for four and a half months.
Status 2026-08-27: NOT YET ROLLED. Owed to Tim.
DNS zones¶
- rtopacks.com.au — Zone ID:
129bbb1240d4212f4e51525de87c72b6, on the Product account - ⚠ The id changed and the old one is still quoted elsewhere. DOMAIN-MOVE-01 moved this zone
between accounts, and a zone move mints a new id.
691d4282eaafd5ab612da6a2204b5729is the Prototype-era id — it is whatinfra/freeze-record-2026-08/records and what this line said until HYPERDRIVE-01 Gate 1 measured the live value with two different keys. Both zones (rtopacks.com.au,rtopacks.dev7a6bb25cff0fe59ae3401ab956bdf1d7) are now on Product. db-01.bne.rtopacks.com.au— A record, DNS-only (grey cloud), Terraform-owned ininfra/terraform-product/. The library's Postgres host. Seebinary-lane-db-01.md.staging.rtopacks.com.auis the production front-page surface — served byrtopacks-site-prod(not a dev surface), CF Access–gated until go-live. The apexrtopacks.com.au/wwware served byrtopacks-prelaunch-produntil cutover. Cutover landmine:rtopacks-site-prodalready holds custom-domain bindings on the apex +wwwbeneath the prelaunch route; removing/repointing prelaunch could promote the site onto the live apex immediately, so treat cutover as one deliberate, sequenced action. (Confirmed live, PUBLIC-FRONT-PAGE-AUDIT-01.) Seeinfrastructure/cloudflare-resource-inventory.md.
D1 databases¶
Categorised per MANDARIN DATA TAXONOMY (see standing-rules.md). Per-env Peel + Intake DBs have dev twins (D1 names retain -staging suffix per ADR-027 D1-name lag).
RTOpacks PRODUCT account (c93403113c55c1df41d43e4c878d3054) — 3, as at 2026-08-19:
| database | uuid | role |
|---|---|---|
pith-index-01 |
12f38f46-6696-45f6-a488-f7aeb68be6a7 |
capture custody — fetch_ledger, raw_index, checkpoints, edition_registry, errors_store, population_*, run_manifest. Holds no unit, qualification or organisation. |
pith-register-01 |
3db7cae9-2381-4257-b735-12dd03b9b87e |
the first application-shaped tables. Created 2026-08-17T06:24:19.915Z at A1-PARSE-LOAD-01 Gate 3. |
tga-history-01 |
2f433d5a-6985-44bf-89cd-b482817cc1e4 |
derived — the sequencing history store (SEQ-MODEL-01). Created 2026-08-19T11:36:16.651Z at TGA-HISTORY-STORE-01 Gate B. |
pith-register-01 — created, region and colo MEASURED from a live query, not from the create call:
location_hintocrequested at create (create-time only; never a customer-facing guarantee). Note the create response does not echoprimary_location_hint, so the hint is unverifiable from the database object —served_by_regionon a live query is the measurement.- served
region OC,served_by_primary true.size_after154,722,304 B. - Eleven tables, 310,495 rows:
training_component125,996 ·organisation13,146 · nine child tables. Re-derived byCOUNT(*)on both sides at Gate 5. - FOREIGN KEY ENFORCEMENT IS A GUARANTEE — SCOPED. A deliberately violating insert was refused
by D1 (
SQLITE_CONSTRAINT_FOREIGNKEY), so the nine constraints are enforced on write, not merely reported byPRAGMA foreign_keys. That result is established on the D1 HTTP query path, on this database, at Gate 4. It does NOT establish that a Worker binding enforces the same, and a constraint enforced on some connections and not others is worse than one enforced on none. - Repeatedly dropped and rebuilt by design. The DDL opens every table with
DROP TABLE IF EXISTS. A single-edition guard refuses a second distinctsource_sha256in either parent table — it is the only thing preventing one edition silently overwriting another row-for-row, since the primary keysource_row_indexis unique only within one body.
Two D1 statement limits, both measured, both operational:
- 100 bound variables per statement (probed at A1-CORPUS-01 Gate 1).
- A ~400,000-byte statement is refused —
SQLITE_TOOBIG, D1 code 7500. 80,000 bytes works. The exact ceiling lies in (80,000, 400,000] and is unmeasured. Loaders here use literal multi-rowINSERTrather than bound parameters because of the first limit, and batch under the second. - Trap:
d1_list_databasesreportsnum_tables: 0for a database holding ten. The listing'snum_tablesis stale metadata, not a measurement — querysqlite_master, never quote the listing. - Trap: the
d1ListAPI returns the database ARRAY itself (numeric keys), not{result:[…]}. Readinglist[0]yields the first database object. This cost a failed create on 2026-08-17.
RTOpacks PROTOTYPE account (10):
rto-nrt-db— Pith — nationally recognised training data (TGA corpus, AQF quals). Post NRT-DB-DEPOLLUTE-01 (18 May 2026): contains only TGA reference + sync-pipeline support tables.rto-abs-db— Sync-output — ABS labour-force / reference data (abs-sync pipeline)rto-licensing-db— Sync-output — licensing / entitlements (teqsa-sync)rto-radar-db— Sync-output — digital footprint intelligence (radar-crawl)rto-ops-db— Peel — internal business ops (UCCA staff, internal-ops surface only)rto-workspace-db— Peel — workspace / studio / canvas / RTO end-user identitiesrto-landscape-db— Peel — VET vendor competitive intelligencerto-calendar-db— Peel — scheduling / calendarrto-micro-db— Peel — microcredentials (non-accredited) contentrto-intake-db— Intake — public-form submissions (contacts, contact_enquiries, subscribers). Post INTAKE-DB-EXTRACTION-01 (16 May 2026).
UCCA account (1):
ucca-mcp-db— MCP integration data
HARD SEPARATION RULE reminder¶
- Regulated training → the NRT stores of record (
tga-nrt·tga-nrt-content·tga-nrt-content-legacy·tga-nrt-packaging·tga-rto·tga-scope·tga-history,store-register.md) [2026-09-15, NAME-RETIRE-02, R-NR-4] [2026-09-16, COUNT-RECONCILE-01] - Non-regulated training →
rto-micro-db - Business ops →
rto-ops-db(never surfaced)
See standing-rules.md for full rule.
Worker inventory (as of March 2026)¶
28 Workers on RTOpacks account, 20 on UCCA account.
Scheduled Workers:
tga-sync— Sat 16:00 UTC / Sun 2am AEST (0 16 * * SAT)cricos-sync— 1st of month, 07:00 UTC (0 7 1 * *). Cron restored 2026-07-03 (SYNC-REVIVAL-01) — was never configured our side after the 2026-04-08 migration, so it silently stopped producing (last write 2026-03-02).ops-tender-sync— daily 6pm + Sat 8pm AESTstats-cache— every 6 hours (0 */6 * * *)enrich-sync— Sat 12:00 UTC (0 12 * * SAT); RTO enrichment (writesrtos.enriched_at). CORRECTED (SYNC-REVIVAL-01, 2026-07-03): it had never run on cron — the cron was deployed but thescheduled()handler was left commented out (commit0526f948, a "wire up later" TODO never completed), so every weekly fire errored. 100% RTO coverage was reached by manual/trigger(Apr-13, May-25). Handler restored 2026-07-03; liveness is now run-gated (a 0-candidate run still writescompletesteps). Registered in the stall detector (9d).- ~~
qual-enrichment— daily 3am AEST~~ CORRECTED (SYNC-REVIVAL-01, 2026-07-03): there is no deployedqual-enrichmentworker. Units/qualification KN enrichment (the 15,128→15,200 transition) has no writer in this repo — it was an external process that ceased at the migration (last write 2026-04-02). No rebuild: The prototype's KN corpus is retired (NAME-RETIRE-01, 2026-09-15; Tim's ruling of 2026-09-09; ADR-079): no surface readskn_*orregulatory_context, and the Knowledge Navigator name now means the AI/RAG companion. [2026-09-15, NAME-RETIRE-01] rtopacks-internal-api— hourly (0 * * * *); invite-expiry sweep (BRIEF-INVITE-EXPIRY-01, 2026-06-26) — lapses pending portal_invites past the 7-day window tostatus='expired', freeing the reserved seat (ADR-058 "or expired" release path)rtopacks-db-backup-tooling— weekly Sun 04:00 UTC (0 4 * * SUN); off-substraterto-nrt-dbbackup (KN-BACKUP-AND-REGIME-AUDIT-01, live 2026-07-03).rtopacks-stall-detector-tooling— hourly (0 * * * *); liveness sweep — alarms when any registered scheduled worker has no successful run within its window (SYNC-REVIVAL-01 §2.3).
All 5 stat-sync scheduled Workers need ops.ucca.online status stubs (pending).
Artefact-carry proxy (OUTPUTS-PROXY-01, 2026-07-03)¶
rtopacks-artefact-proxy-tooling— GET-only read proxy so Claude fetches gate-review bytes directly instead of Tim hand-carrying terminal output (the carriage was the bottleneck; one clipped-carry incident). Alex→Claude artefact carriage only — every instruction still travels Tim→Alex verbatim; FENCE-PROTOCOL-01 untouched.- Base URL:
https://rtopacks-artefact-proxy-tooling.dark-firefly-3289.workers.dev. Routes:GET /{token}/manifest-<UTCstamp>.json(versioned),GET /{token}/{filename}. Anything else → 404 — including any_-prefixed key and any..traversal. There is NO standingmanifest.json(deleted 2026-07-03; a fixed URL is cache-pinned on Claude's side, so it inevitably lies). - The path token is a worker secret (
ARTEFACT_TOKEN), not committed here — the full tokened URL lives in thereference_proxy_urls.mdmemory ref (docs-proxy convention) and is carried to Claude out-of-band by Tim. - Bucket
rtopacks-gate-artefacts-tooling; publish is a deliberate per-file act viascripts/publish-artefact.sh(secret-scans, puts, appends{filename, sha256, bytes, published_at}to the manifest). Claude verifies the fetched digest against the manifest entry — digest check is structural. - Stale-manifest defence = unique paths, not
?cb=. Claude's fetch pipeline strips query params, so cache-busting a fixed URL fails. Each publish writes (a) an internal_manifest_base.json— the read-modify-write base, read by KEY (R2 GET is strongly consistent, so no list-race drops a rapid prior publish's entry) and unfetchable via the proxy (the worker 404s_-prefixed keys), so it can't lie to anyone; and (b) an immutablemanifest-<UTCstamp>.jsonfor Claude. At every gate close, carry the VERSIONED manifest URL plus each artefact's file URL — full, token and all — so one paste puts fetchable links into Claude's conversation. Guard keys/artefacts against re-use (an overwritten key is cache-pinned stale on Claude's side);PUBLISH_INSPECTED_OVERRIDE=1skips the secret-scan for inspected false positives (e.g. a binding reference, not a value). The script prints the confirm-back URLs, reading the token from thertopacks-artefact-proxy1Password item.
Store charters (DATA-STORE-BOUNDARY-01 §2.1)¶
A store without a charter cannot receive a table. A charter is a boundary, not a description: if a proposed table makes the charter need rewording, that is the signal for a new store. Prototype stores are frozen and dying (proto-to-product register §3) and are not retrofitted.
| store | substrate | data class | owner | write authority |
|---|---|---|---|---|
pith-assets-01 |
R2, Product account | pith | A1 corpus programme | rtopacks-mirror Worker (queue consumer) — sole writer |
pith-index-01 |
D1 12f38f46…, Product |
pith (capture custody) | A1 corpus programme | rtopacks-mirror Worker; Mac-side instruments read-only |
pith-register-01 |
D1 3db7cae9…, Product |
derived | A1 corpus programme | the parse-load runner, the A1-ORG-PARSE-01 detail loader and the A1-SCOPE-PARSE-01 scope loader (the same runner extended to the od_ family, then to od_scope*), at edition rebuild only |
regulatory-sources-01 |
R2, Product account | pith (capture custody) | sequencing programme | manual capture acts, each with a manifest entry |
tga-history-01 |
D1 2f433d5a-6985-44bf-89cd-b482817cc1e4, Product |
derived | sequencing programme | the sequence-build runner, at edition rebuild only |
pith-assets-01 — pith. The TGA response bodies exactly as fetched, content-addressed at
{prefix}/{sha256}.{ext}. Nothing is written here that was not received from source. Measured
2026-08-19: 390,098 distinct objects, 7.43 GB indexed. R2 has no platform cap; projected
end-state ~7.6 GB over the population the full A1 mirror: 6,921,518 planned calls across all
declared families, because content addressing dedupes DNH bodies 6.9× at 77 B mean. Cost line, not
a wall: ~US$0.13/month at R2 storage pricing. Watch: none required for a ceiling; the figure
is restated at each programme close.
pith-index-01 — pith. Capture custody: the ledger and index that make the R2 objects
addressable and the mirror provable. Eight tables — raw_index, fetch_ledger, checkpoints,
edition_registry, errors_store, population_artefacts, population_members, run_manifest.
Holds no unit, qualification or organisation. Measured 2026-08-19: 1,352,893 rows, 0.481 GB of
the 10 GB D1 cap (95% free). Projected end-state ~5.2 GB, 48% headroom, over the population
the 6,667,950 calls remaining in A1-MIRROR-DEPTH-01 and A1-DNH-01, at 2 rows per call and a measured
356 B/row that has held stable across 43% table growth. Watch: outputs/a1-corpus-01/monitor-depth.mjs
prints D1 size and headroom on every 15-minute sample and flags below 25%; a failed read prints
D1=UNREAD (not a reading) so a broken instrument cannot read as headroom. Banked ab69bfe7.
tga-history-01 — derived. The ordered, dated, recomputable model of the National Register —
entities, validity intervals, edges and rule sets sufficient to evaluate operational rights for any
(RTO, component, date) — and nothing application-shaped beyond that evaluation (charter sentence,
SEQ-MODEL-01 §0). Rebuilt whole per edition, stamped with the export-sync timestamp; an edition row
is written only by a build that passes its checks — a build with BLOCKING findings is a diagnosis,
not an edition (SEQ-SCHEMA-01 §4). Capacity: projected end-state < 2 GB upper bound of the 10 GB
cap over the population one edition: 125,996 components + 12,867 organisations plus intervals,
edges, scope events and rule rows parsed from held bodies — magnitudes unmeasured until first parse,
which restates the bound as a figure. delivery_notification is the named swing factor; pre-named
cure: split to tga-history-dnh-01 (SEQ-SCHEMA-01 §1.6). Watch: each edition rebuild states
store size and headroom at close. Created 2026-08-19 at TGA-HISTORY-STORE-01 Gate B.
pith-register-01 write authority, amended 2026-08-20 at A1-ORG-PARSE-01 Gate 5. The store now
carries two families under one lifecycle: the eleven register-sourced tables and the eighteen od_
detail-sourced tables (420,949 rows, parse_run_id org-parse-01-2026-08-20T00-30-34-787Z). Both are
written by the same drop-and-rebuild parse authority at edition rebuild only; the two families are
never merged and either may be ruled canonical later — this act does not rule it. A store whose
charter no longer names its writers has a stale charter, which is why this line moved rather than the
loader being treated as covered by silence.
Extended 2026-08-20 at A1-SCOPE-PARSE-01 Gate 5. A third writer joins the same
drop-and-rebuild authority: the scope loader, which writes od_scope (6,505,733 rows) and
od_scope_declared (13,034 rows), parse_run_id
scope-parse-01-2026-08-20T05-32-00. The store now carries three families under one
lifecycle — eleven register-sourced tables, eighteen od_ detail tables, and the two od_scope*
tables — still none of them ruled canonical. od_scope_declared exists because the source's
own count field disagreed with its own array in 34 of 13,034 bodies (total delta 385): a figure
that is not derivable from the rows carries information, so a faithful mirror stores it, and the
discrepancy stays queryable as declared_count <> COUNT(*) rather than being reconciled away.
regulatory-sources-01 — pith (capture custody). Non-TGA regulatory sources: legislation
instruments and regulator registers. Content preserved exactly as fetched; every object carries
its source URL, capture timestamp (UTC), sha256 and bytes in the bucket's own MANIFEST.sha256.
Created 2026-08-19T10:38:11.588Z at RELAY-SEQ-CAPTURES act 3. It exists because
pith-assets-01's charter is TGA-only — the boundary held, and this is the compliant path under
DATA-STORE-BOUNDARY-01 §2.2 rather than an exception to it. Capacity: R2, no platform cap; the
population is the regulatory instruments and registers the sequencing model cites — at first
capture 12 objects / 45,823 B, and it grows only by deliberate capture acts, never by a run. Watch:
each capture act restates object count and bytes in the bucket README; there is no ceiling to breach.
pith-register-01 — derived. The first application-shaped tables, parsed from pith bodies:
eleven tables — training_component, organisation, and nine children. Recomputable by
construction — the DDL opens every table with DROP TABLE IF EXISTS and the store is rebuilt per
edition, which is precisely §2.5's "mistakes cheap by design". ~~Measured 2026-08-19: 0.155 GB of the
10 GB cap (98% free), 11 tables.~~ Restated 2026-08-20 at A1-SCOPE-PARSE-01 Gate 5, read from the
store's own file_size: 1,956,777,984 B — 1.957 GB of the 10 GB cap, 19.5678% used, 80.4322% free,
31 tables (32 including _cf_KV). The 2026-08-19 figure is struck rather than deleted because the
growth between the two is the record of what the od_ and od_scope* families cost. Projected end-state is not cumulative — the population is one register
edition: 125,996 training components + 12,867 organisations (13,146 rows — 279 duplicate-code pairs,
measured 2026-08-19 at the Architect seat, no code appearing more than twice; byte-identity of pair
members still owed), and a new edition replaces rather than appends. Watch: each edition rebuild states store size and headroom at close — the watch for a
replace-not-append store is the rebuild itself. First stated at the next rebuild.
Class ruling, and one flag that stands¶
pith-index-01 — class ruled 2026-08-19 (Architect): capture custody — the fetched record and
everything required to prove it. checkpoints, run_manifest, errors_store are capture
provenance, not platform ops: same writer, same lifecycle, part of the mirror's provability. Ruled
on class, expressly not on migration cost. See DATA-STORE-BOUNDARY-01 §6.
⚠ pith-register-01 is named pith- and is class derived. This collides with
SUBSTRATE-NAME-MATCHES-SHAPE. The name says custody-of-source; the content is parsed,
recomputable, drop-and-rebuild. Anyone reading the store list will mis-class it on the name alone —
which is exactly the failure that rule exists to prevent. Not renaming it: a live D1 rename is a
real act with binding consequences and is outside a charter retrofit. Flagged so the charter and the
name disagree visibly rather than silently.
R2 buckets¶
rtopacks-terraform-state— Terraform state backend (R2; renamed at STATE-MIGRATE-01 —ucca-terraform-statewas stale). Backend creds in 1Passwordterraform-r2-backend(RTOpacks vault) viaop run --env-file=infra/terraform/.env.op, NOT~/.zshrc. Terraform ratified 1.15.8 (pin~> 1.15.0, TERRAFORM-VERSION-ALIGN-01). 115 resources / 9 types (+78 parked v5 schema-rep changes → TERRAFORM-V5-RECONCILIATION-01).rtopacks-llnd-instrument-assets-{dev,prod}— published instrument-asset custody (content-addressed audio/media referenced by packaudio_ref; served read-path-only through the tokened candidate session,GET /s/:token/asset/{digest}; never public, no signed URLs). Distinct custody class from evidence and capture — the classes do not mix. Created: LLND-LLN-ASSETS-01 (2026-07-11), dev at G3 / prod (empty, inert) at G5, outside Terraform (wrangler); IaC debt owed toTERRAFORM-V5-RECONCILIATION-01(ADR-068).- Versioned snapshot buckets (see Observatory config).
CF Access bypasses¶
/billing/webhook— Stripe webhook endpoint/billing/qb-callback— QuickBooks OAuth callback
Product account — admin behind the padlock¶
Hostname: admin.rtopacks.dev · Worker: rtopacks-admin-dev, env.product-dev in
apps/admin/wrangler.jsonc · Account: RTOpacks Production. Route admin.rtopacks.dev/* on the
rtopacks.dev zone, sitting on a Terraform-owned proxied placeholder record
(AAAA admin 100::, ttl = 1). Not a Custom Domain: a Custom Domain would have the deploy step
create DNS outside Terraform's state, and the deploy token deliberately holds no DNS permission.
Access on Product is Terraform's, owned by infra/terraform-product/ — a directory that shares
nothing with infra/terraform/ (Prototype's). State: rtopacks-product-terraform-state (R2), key
admin-first-deploy-01/terraform.tfstate, native S3 lockfile. Terraform ~> 1.15.0, provider
cloudflare/cloudflare 5.19.1, .terraform.lock.hcl tracked. The padlocks are declared from a
map of hostnames, one Access application + policy + DNS record each, so every hostname gets its
own aud; today the map has one entry. app_launcher_visible is pinned false rather than left
at the provider default — a one-person door has no launcher tile. Nothing in that directory is made
by hand or by API beside it, and nothing carries lifecycle { ignore_changes = all } — the
prototype's 87-resource drift is what that posture buys.
The library's database is not on Cloudflare. db-01.bne.rtopacks.com.au is a Binary Lane VPS in
Brisbane running Postgres 17 + pgvector, reached from Workers on Product through the Hyperdrive config
library-ro at sslmode=verify-full against a private CA of ours. The box, both its fences, the
certificate chain and its renewal, the Hyperdrive config, and the by-hand tunnel read-back form are all
in binary-lane-db-01.md — the external-service reference for it. Start there, not here.
⚠ Token split, so it is not rediscovered: the broad alex-build-full-token holds Hyperdrive Write
and Account: SSL and Certificates Write but not Workers Routes Write; the narrow
product-admin-deploy key is the one that holds Workers Routes Write. That is the split working as
designed, not a gap to fill.
EXT-API — the Access certs endpoint. At runtime the Worker fetches
https://rtopacks-product.cloudflareaccess.com/cdn-cgi/access/certs (the Zero Trust organisation's
auth_domain, never its auto-generated name) to verify the Access token's RS256 signature on
every request. Cached in module scope for one hour, re-fetched once on an unknown kid. If the key
set cannot be had the Worker answers 503 and serves nothing — it fails closed.
Session duration — 720h (30 days), Tim's ruling of 2026-09-18, set explicitly in TWO places and
inherited in the third: the Access policy and the Access application, both in
infra/terraform-product/access.tf. The Zero Trust organisation's global session duration is
deliberately left UNSET, reading "Same as application session timeout", so it inherits the
application's 720h; no third value is stored and none needs maintaining. ⚠ That state was read
from the dashboard (Cloudflare One → Access controls → Access settings, not the older
Settings → Authentication path), not by API: the padlock key carries
Access: Apps and Policies Write and cannot read organisation settings
(measured: GET /accounts/{id}/access/organizations → 403 under that key, and under the
Product vault's other reachable key). The clocks return to 24h on the first non-Tim human or the
first customer row.
Identity providers and the MFA posture — the pre-launch resting state, ruled 2026-09-18. The
organisation carries two login methods. Cloudflare is the dashboard identity, and it admits
nobody: the allow-listed address is the .dev admin mailbox while the dashboard identity is the
.com.au one, so it answers "That account does not have access". It is left in place deliberately
— that refusal is the padlock's negative control, a real authenticated identity on this account
being turned away. One-time PIN was added by Tim on 2026-09-18 and is the padlock's working
login. Every Access-side MFA method is off — Biometrics, Security key, Authenticator
application, PIV, FIDO2. The door therefore rests on control of the .dev mailbox alone, and one
successful code yields a 720h session. ⚠ The mailbox's own second factor, at its own provider,
is the actual front door. It is Tim's to hold, and it is not measured here — nothing in this
repo can read it. Lock-down trigger, the same one already ruled for the keys and now applied to
the door: on the first non-Tim human or the first customer-owned row, an Access MFA method goes on
and the sessions return to 24h. That clause belongs to the lock-down brief, drafted ahead of the
need. We lock down a running system; we do not refuse to start one.
Tokens (names and permission groups only — no values, no ids):
| token | groups |
|---|---|
product-admin-deploy |
Workers Scripts Write (account) · Account Settings Read (account) · Workers Routes Write (zone, both Product zones named explicitly) |
product-terraform-padlock |
Access: Apps and Policies Write (account) · DNS Write (zone) · Zone Read (zone) |
Neither carries any D1, KV, R2-admin, token-minting, billing or member permission. Both are reached
only through the read-write service account rtopacks-product-sa-rw2 — the successor of
rtopacks-product-sa-rw, revoked 2026-09-18 in PRODUCT-KEYS-ROTATE-01, whose 1Password item
remains in the vault as a leftover for 1PASSWORD-TIDY-01 to archive, never delete — in one
1Password vault (RTOpacks Product), via the pointer file
~/.config/rtopacks/product-keys.refs.env, with ~/.config/rtopacks/op-sa-product-rw.env supplying
the service-account token. No value is ever typed, echoed or written to disk.
credential-discipline.md's "wrangler auth is OAuth-only" line is overridden for Product by
ADMIN-LIFT-RECON-01's verdict ruling 2: scoped tokens, because the cached OAuth login spans both
accounts.
⛔ A wrangler config that deploys to Product must not carry a Prototype account_id at top level.
apps/admin/wrangler.jsonc does today, and it is the single thing the two deploy-product.sh
repairs exist to defend against: both opennextjs-cloudflare build (when a token is in the
environment) and the opennextjs-cloudflare deploy delegate that plain wrangler deploy hands off
to resolve their platform proxy from the top-level account_id, ignoring --env, and send a
Product credential at Prototype. deploy-product.sh therefore builds with the credential unset and
deploys with OPEN_NEXT_DEPLOY=true. Guard 1's account-digest check cannot see either path — it
checks the account the deploy resolves to, and these read a different id out of the same file; a
guard above a transport it does not control is not a guard. When Prototype goes dark and the
top-level id becomes Product's, both repairs become belt-and-braces rather than load-bearing —
but until then they are load-bearing, and the top-level id is the reason.
Three gotchas, each earned:
op whoamianswers on the user path. A service-account env can be sourced andop whoamiwill still report the user account, so it is not proof the service account is in use. Check what the command actually resolved, not whoopsays you are.- Cloudflare's Access list endpoints answer an unpermitted key with
200and an empty list. A narrow key's "0 applications" proves nothing. Any absence claim about Access must be read with a key proven to see a known-present Access object. - Wrangler prefers a config's
account_idtoCLOUDFLARE_ACCOUNT_ID.env.product-devtherefore declares Product's account explicitly, andscripts/deploy-product.shrefuses to run unless the resolved config for the named env matches Product bysha256[:8]— the environment variable is set too, but it is not the guard.
The Access identity stand-in is TEMPORARY under RULING-PADLOCK-THEN-THE-ROOM-01: allow-list of
one; no second human, no customer-owned data, no live my.; removed by the identity build brief.
It is active in one environment by one setting (ACCESS_AUD), labelled in both code sites
(apps/admin/lib/access-identity.ts, apps/admin/lib/admin-auth.ts), and its removal is an
acceptance line of that brief. While it is active the Worker verifies identity before anything
else on every request — pages, API routes, /_health, /_build and static assets alike
(assets.run_worker_first) — so no route is reachable on cookie presence alone. /_health and
/_build now resolve the Cloudflare context before answering: the bytes they return are
unchanged, but the order is not, and the dependency is one every other path already had. No module in this environment has a data binding. 19 of the 20 board modules therefore read
not connected and name what they wait for; the one that does not — /marketing — reads connected
because it genuinely requires none (bindings: [] in the generated manifest). The root path is the
connections board.
Product account — KN behind the padlock¶
Hostname: kn.rtopacks.dev · Worker: rtopacks-kn-dev, env.product-dev in
apps/kn/wrangler.jsonc · Account: RTOpacks Production. Route kn.rtopacks.dev/* on the
rtopacks.dev zone (7a6bb25c…, not the Prototype id 7564855c… that apps/admin's env.dev
still carries), sitting on a Terraform-owned proxied placeholder record (AAAA kn 100::, ttl = 1)
— the same route-on-placeholder pattern as admin, and not a Custom Domain. The config names the
zone by zone_name and carries no CF_ZONE_ID: a zone move mints a new id, and that number has
already been wrong once. Live 2026-09-19 (KN-FACE-01). Keys, unchanged and unextended:
product-terraform-padlock applied the padlock, product-admin-deploy created the Worker and its
route; neither was modified and nothing was minted.
aud = 5ae92d4efbf80a2165b3cb6adb65e306c20e67152d8463d953fb6af989d136ab — its own Access
application, so its own audience tag, different from admin's 98ea9bde…. Not a secret: it is
public in the Access login redirect. ACCESS_TEAM_DOMAIN is the organisation's shared
rtopacks-product.cloudflareaccess.com. The verifier is apps/kn/lib/access-identity.ts, a
byte-identical copy of admin's (sha256 be691c36ff0bbf41…); admin's own test harness, repointed
at KN's file, passes 15/15 including wrong aud → 401 bad-aud.
⛔ The separation between admin and KN is CRYPTOGRAPHIC, NOT INTERACTIVE — measured, and it is the
opposite of what was assumed. Cloudflare Access does not hold a per-application login; it holds a
sign-in session for the whole organisation. An identity that already satisfies a second
application's policy is admitted to it without being asked to log in again. Measured at
KN-FACE-01 Gate 4: signed into admin.rtopacks.dev, opening kn.rtopacks.dev rendered the page
immediately — no login screen, no one-time PIN, no interstitial. What keeps the two rooms apart is
that each application checks for its own aud, and a token issued for admin is refused by KN
(bad-aud, 401). Do not assume a second login stands between these two surfaces. It matters the
moment the allow-lists differ: someone allow-listed on admin but not on KN is refused by KN's policy
or by the Worker's not-allow-listed, never by being made to sign in again. Today both lists are the
same one address, so the point is latent — it becomes live at the lock-down brief's "first non-Tim
human" trigger.
⚠ "Face only — it binds nothing" was true here until KN-LAB-03 and is corrected rather than
deleted. That paragraph read: "Evidence is the deployed binding table … env.ASSETS, env.ENV,
env.ACCESS_AUD, env.ACCESS_TEAM_DOMAIN — no D1, KV, R2, service, AI, queue, Hyperdrive or
Durable Object. No model is called … Sending a message returns one fixed, labelled reply saying KN is
not connected yet." KN-LAB-02 wired a model and KN-LAB-03 added a second one with a store. What
is still true of it: nothing is stored beyond a date and a number, no search is run, no chat is
saved, and KN never invents an answer (ABSENT-NOT-DEFAULT-01).
Two models, hand-picked, and a counter — KN-LAB-03, live 2026-09-20. The deployed binding table,
printed by wrangler at the deploy, is six rows and nothing else: env.KN_COUNTER (Durable
Object), env.AI (Workers AI), env.ASSETS, env.ENV, env.ACCESS_AUD, env.ACCESS_TEAM_DOMAIN
— still no D1, KV, R2, service binding, queue or Hyperdrive.
- The picker holds two live entries and Tim chooses between them; KN never switches by itself.
@cf/qwen/qwen3-30b-a3b-fp8on Workers AI (in-account, no token anywhere on the Worker) andnvidia/nemotron-3-nano-omni-30b-a3b-reasoning. KN opens on Qwen3 and NVIDIA is labelled "free · often slow" — RULING-KN-NVIDIA-SLOW-01, and both are measurements, not preferences: Qwen3 answered on the deployed surface in 2.5 s on the day NVIDIA gave nothing in 30 s. - ⛔ The client sends a KEY, never a model id.
apps/kn/lib/models.tsis the one allow-list; a free-form model string never reaches a provider call. - The cap is a Durable Object,
KnDailyCounter, boundKN_COUNTER, holding{date_utc, count}and nothing else — no chat, no user, no IP. 50 Workers AI questions a UTC day, and the 51st is refused in KN's own words. It fails closed: in a production build with no binding the Qwen3 arm refuses rather than falling back to an in-memory counter, and the fallback is not merely unreachable but absent from the shipped bundle.GET /api/kn-countpeeks without consuming. - Neuron arithmetic and the account-wide rule are in
workers-ai-reference.md, extended and re-dated at this brief. The short of it: 0.0306–0.0315 neurons per completion token, a worst-case capped day of ~6,120–6,300 neurons against an allowance of 10,000 that is shared with every other job on the account, so ≈ US$0.07 at worst. A surface may meter what it measures and may not draw the shared allowance as if it were its own. - ⛔ A timeout is its own reason class. NVIDIA's free tier queues rather than refusing —
measured 2026-09-20 at 23.9 s to first byte, then twice nothing in 120 s. KN's deadline is 45 s
on the first byte; exceeding it is
timed-out, which says "NVIDIA's free service is queueing", retries at most 3 times with a countdown and Cancel, and is notunreachable. The two are told apart by a flag our own timer sets, so a host that genuinely does not resolve still reads "can't reach". Before KN-LAB-03 Gate 4b both were the same synthetic status and the page said "can't reach its model" about a host whose TLS handshake had finished in 0.3 seconds. - The four lab knobs (
KN_LAB_MAX_TOKENS,KN_LAB_FORCE,KN_LAB_FIRST_BYTE_MS,KN_LAB_NVIDIA_BASE) exist to force failure states against real upstreams at a gate. They are declared in no config and removed from the production bundle at build time — 0 occurrences each, checked with a known-present control. - Entry point:
mainisworker-entry.ts, not.open-next/worker.js. A Durable Object class must be exported from the deployed script and that file is generated on every build, so the entry re-exports OpenNext's own exports and addsKnDailyCounterbeside them.
middleware.ts runs the verifier on every path with matcher: ["/(.*)"] and
assets.run_worker_first: true, so not even a static file is readable without Access — proved by
refusing a real 172,500-byte chunk. It carries no fallback branch at all: admin's else arm
drops to a cookie gate when ACCESS_AUD is empty, and KN deliberately has none, because an
unreachable fallback is still a fallback one deleted variable can reach. Unconfigured, KN answers
allow-list-unset/401 to everything and serves nothing.
EXT-API — three, all server-side. The Access certs endpoint shared with admin
(https://rtopacks-product.cloudflareaccess.com/cdn-cgi/access/certs, fetched to verify the token
signature), and NVIDIA's API Catalog (https://integrate.api.nvidia.com/v1) since KN-LAB-02 —
see nvidia-api-reference.md, which is the reference doc the EXT-API RULE requires and which was
committed before the deploy. Third since KN-LAB-03: Workers AI, reached through the in-account
AI binding — see workers-ai-reference.md, likewise committed before that deploy. The
browser reaches none of them: it calls only KN's own /api/chat, the NVIDIA key exists solely in
the Worker, and the Workers AI path carries no key at all.
⚠ The page is not silent off-origin, and an earlier line here said it was. Corrected at KN-LAB-02 Gate 4: the deployed page loads one off-origin script — see the Cloudflare beacon paragraph below. The "zero off-origin" measurements that preceded it were taken against local builds and were true of those; a network control on a local build does not certify the browser's behaviour on the deployed page (RULING-CF-BROWSER-INSIGHTS-01 §4). Deployed-page controls are run on the deployed page.
⛔ https://backend.assistant-api.com is compiled into the bundle, is unreachable, and must never
acquire a caller. It is assistant-cloud's default API host, reached only inside
AssistantCloudAPI's constructor on its apiKey branch; nothing in apps/kn ever constructs an
AssistantCloud, and the constructor throws without credentials, so it cannot be built by accident.
It is not an EXT-API — nothing calls it, so it needs no reference doc — it is a recorded
forbidden caller. Standing guard for every KN brief: the assistant-ui cloud option is forbidden
by name. One option would switch this on; that is the thing to refuse.
Wired to one model, and it stores nothing — KN-LAB-02, live 2026-09-19. KN answers from
nvidia/nemotron-3-nano-omni-30b-a3b-reasoning on NVIDIA's free hosted endpoint, lab only,
never customer-facing under NVIDIA's API Trial Terms. The browser talks only to KN's own
same-origin /api/chat; the Worker holds the key and calls NVIDIA. One secret was added,
NVIDIA_API_KEY (1Password item nvidia-build-kn-lab, vault RTOpacks Product) — the binding table
is otherwise unchanged and still binds no database of any kind. Nothing is saved: no chat, no
log, no history; the history rail still reads "Chats are not saved yet." A$0 by construction —
no payment method on the NVIDIA account, no paid provider key, and no Workers AI binding
(RULING-KN-LAB-ZERO-DOLLAR-01). Only what Tim types is sent: no document, no retrieved passage, no
personal data, and the system prompt is one plain line. Quirks, failure modes, the measured 503 rate
and the trial terms are in nvidia-api-reference.md — read that before changing anything here.
⚠ Cloudflare Web Analytics (Browser Insights) is ON for these hostnames, and it is ruled.
RULING-CF-BROWSER-INSIGHTS-01 (Tim, 2026-09-19: "Keep it, write it down"). Cloudflare injects
static.cloudflareinsights.com/beacon.min.js into the HTML at the edge, after our Worker has
run — it is not in apps/kn, and it does not appear in any local build. It executes
(window.__cfBeacon), carries page views and timings, and never a chat, an answer or a key.
It is on admin.rtopacks.dev too and predates KN, so nobody should read it as something KN
introduced. Every network control on a deployed page names it as the one expected exception and
still fails on anything else off-origin.
Documentation surfaces¶
All Cloudflare-proxied.
- knowledge.ucca.online — UCCA knowledge base
- docs.ucca.online — UCCA docs
- docs.rtopacks.com.au — RTOpacks product docs
- trust.rtopacks.com.au — RTOpacks trust / compliance surface
Apple Developer¶
- Team ID:
B29TSCBPHD - Pass Type ID:
pass.online.ucca.credential - Bundle ID:
online.ucca.authenticator - Renewal: 2 March 2027
- Entity name change: submitted
GitHub¶
- Monorepo:
uccaonline— contains ucca-project and rtopacks-project. Auth viaghCLI OAuth, auto-refreshes. - UCCO repo:
ucco-project(on hold). Auth via PATucco-foundation-push, expires 14 March 2027. - 2FA: enabled (deadline was April 29 — met).
Project structure (local)¶
All projects under ~/projects/:
ucca-project/— containsengine/anducca-docs/(MkDocs)rtopacks-project/ucco-project/(on hold)
ucca-project and rtopacks-project share one git repo (uccaonline). ucco-project has its own repo.
Financial / accounting¶
- Bank: Mercury (US, under UCCA Inc)
- Accounting (AU): QuickBooks Online AU
- QuickBooks sandbox company ID:
9341456854400409 - Accountant: Kevin (CPA)
- Stripe: integrated, webhook bypass configured
External APIs¶
All external APIs must have a reference doc in docs/ops/ before deploy (EXT-API RULE).
TGA (training.gov.au)¶
- Reference doc:
docs/ops/tga-api-reference.md - Swagger: https://training.gov.au/swagger/index.html
- Unit content endpoint:
GET /api/training/{code}/releases/{releaseNumber}/document-bundle - TLS note: Node.js
fetchworks.curland CF Workers are blocked by TGA's TLS fingerprint. Use a Node-based Worker runtime or proxy if calling from CF.
Other APIs¶
Add entries here as they're integrated. Each entry must link to its reference doc in docs/ops/.
Machine / local setup¶
- Primary machine: Mac Mini M2 Pro
- Display: 49" Samsung ultrawide
- Storage: LaCie external, Rclone + Spotlight configured
- Shell env: no credentials in
~/.zshrc(emptied at ENV-TOKEN-HYGIENE-01/02); Terraform R2 backend creds in 1Passwordterraform-r2-backendviaop run --env-file=infra/terraform/.env.op
Wrangler version operating constraint¶
The repo carries two wrangler versions:
- Global install (used when running
npx wranglerfrom any directory without a localnode_modules/wrangler): currently4.94.0. - Per-worker pinned: e.g.
scripts/workers/tga-sync/uses3.114.17via localnode_modules;apps/admin/uses4.77.0.
Refined picture (post MANDARIN-VIOLATION-02-market-snapshot, 2026-05-24):
Wrangler v4's resource-by-name resolution is asymmetric between resource types:
| Resource type | v4 from project root | v4 from worker dir w/ local config | v3 from worker dir w/ local config |
|---|---|---|---|
| Queue (by name) | ✅ resolves | ✅ resolves | ✅ resolves |
| D1 (by name) | ❌ "Couldn't find DB with name X" | ✅ resolves | ✅ resolves |
D1-by-name on v4 from project root fails even with --database-id alone — v4 wants both the positional name AND the --database-id flag, OR the local config context. The cleanest D1 command paths for ad-hoc remote queries:
cdinto a worker dir with the binding in local config + use wrangler 3.x pinned (e.g.,scripts/workers/tga-sync/):cdinto a worker dir with the binding + use wrangler 4 (e.g.,apps/admin/):- D1 REST API or D1 MCP (skips wrangler discovery entirely — uses UUID directly).
Discipline note: when a prescribed wrangler command fails in a credential-touch flow, halt and surface with the working alternative — do not route around to a different tool on your own authority. The choice of execution path is part of the credential rule, not just the credential bytes.
D1 UUIDs are listed under the D1 databases section above for use with --database-id or for direct MCP/REST calls.
What goes where — quick reference¶
| Item | Entity / location |
|---|---|
| US software subscriptions | UCCA Inc |
| US startup credit programs | UCCA Inc |
| AU customer contracts | RTOpacks / UCCA AU Pty Ltd |
| AU tax and accounting | UCCA AU Pty Ltd (Kevin) |
| Regulated training data | the NRT stores of record (tga-nrt · tga-nrt-content · tga-nrt-content-legacy · tga-nrt-packaging · tga-rto · tga-scope · tga-history, store-register.md) [2026-09-15, NAME-RETIRE-02, R-NR-4] [2026-09-16, COUNT-RECONCILE-01] |
| Non-regulated training data | rto-micro-db |
| Business ops data | rto-ops-db (never surfaced) |
| Terraform state | R2 rtopacks-terraform-state |
| RTOpacks DNS | Cloudflare, Zone 129bbb1240d4212f4e51525de87c72b6 (Product) |
| Primary docs surface | docs.rtopacks.com.au |
| Trust / compliance surface | trust.rtopacks.com.au |
Change discipline¶
This doc is canonical. When IDs, entities, or infrastructure change:
- Update this doc first
- Then update anything that references these values
- Commit under
docs/ops/infrastructure-reference.md - Note the change date at the top of the doc
Never let this doc drift from reality. If you find a discrepancy, fix this doc before anything else.