oficina / home Public

Pin team ID codec and clarify pending operator authority adapters

Paul Campbell pushed by paul@keymail.dev df93303d2eff0f5a2298aae762dec3f335c57dd7 parent 6dc1e7e
1 file changed, +41 −21
  • implementation/home-operator-seed.md +41 −21

CI passed — run details

diff --git a/implementation/home-operator-seed.md b/implementation/home-operator-seed.md
index 2e71e85..4e42141 100644
--- a/implementation/home-operator-seed.md
+++ b/implementation/home-operator-seed.md
@@ -1,6 +1,7 @@
# Local Home operator seed and provisioning
-Status: proposed internal design, 2026-09-08. Fable approval is required before
+Status: revised internal design, 2026-09-08. Fable R1 ended at a provider quota
+refusal without a verdict; Home discussion 37 records it. Approval is required before
implementation. This branch starts at directory runtime 171f49a. It defines an
application package and a local command protocol; it neither mounts a public
operator endpoint nor authorizes live provisioning.
@@ -41,16 +42,16 @@ missing generation alongside existing consumers is a refusal, never a repair.
Platform discussion 117 owns stopping traffic and all background work, holding
the database lease, selecting the immutable executable and exact database, and
resuming safely. Its private-input/result protocol is generic. The proposed
-entry point is `home operator-v1 --db <platform-selected-existing-db>` with a
-private result file descriptor supplied by the transport. The fixed command and
+entry point is `home operator-v1 --db <platform-selected-existing-db>`, with
+standard output captured as the private result by the transport. The fixed command and
role permissions belong to reviewed deployment configuration. No request chooses
a binary, path, SQL, environment variable, shell fragment or network destination.
The command never starts an HTTP server, sends mail or makes network calls.
Read one UTF-8 JSON object from private stdin with a 64 KiB hard limit including
whitespace, then require EOF. Write one JSON result of at most 64 KiB to the
-private result descriptor only, after transaction commit. Standard output and
-standard error carry no data and the transport discards them. Input and result
+private standard-output channel only, after transaction commit. The transport
+never tees or logs stdout and discards stderr. Input and result
are encrypted at rest by the transport, available only through its authenticated
private result channel, and never included in public status, receipts or logs.
The application does not implement its own remote encryption protocol.
@@ -71,8 +72,9 @@ an immutable operation allowlist and expected role/origin/database identity from
reviewed launch configuration. A request's `operation` only selects within that
allowlist. Package constructors are private to the command adapter or receive an
opaque validated operator context; exported structs cannot fabricate that context.
-The transport's signed operation ID is distinct from Home operation_id. Both are
-bound by the adapter's verified invocation context. No body field can claim an
+The transport's operation ID is distinct from Home operation_id. Both must be
+bound by the adapter's verified invocation context. Current platform source has
+no signed Home invocation receipt, and this design does not assert otherwise. No body field can claim an
operator identity or maintenance state. The platform must provide an authenticated
invocation context or equivalent private launch configuration before command
wiring is approved; an environment boolean supplied by the caller is insufficient.
@@ -98,11 +100,9 @@ Add role-specific operator result tables through additive migrations. Credential
and directory databases never receive each other's tables. Each result row has
operation_id primary key, fixed action, opaque operator reference from verified
invocation context, creation time, a keyed request digest, and a sealed result.
-The request digest is HMAC-SHA256 using a dedicated key derived through the shared
-sealer's supported key separation or, if no derivation API exists, an independently
-provisioned 32-byte idempotency key. No custom KDF is introduced. The chosen
-implementation must use the independent key when the shared API offers only
-Seal/Open. Digest canonical typed operation input, not raw JSON whitespace.
+The request digest is HMAC-SHA256 using an independently provisioned 32-byte
+idempotency key. The actual shared sealer exposes Seal/Open, not a key derivation
+API. No custom KDF is introduced. Digest canonical typed operation input, not raw JSON whitespace.
This prevents a stored bare address/name digest becoming an offline dictionary.
Seal result bytes with the existing role sealer and purpose
@@ -134,9 +134,19 @@ manifest or per-team config exception.
`directory.inspect` accepts no payload and returns only current generation (or
explicit absent), the next proposed team integer, and derived team sqid. It writes
no authority and is not a reservation. Derive next ID from the maximum existing
-team ID and sqlite_sequence, reject overflow, and encode with the suite's pinned
-sqid codec. Before implementation select and cite that actual shared codec;
-there is no random substitute for the integer-encoding sqid required by §10.
+team ID and sqlite_sequence, then add one, refusing signed-64-bit overflow. No
+shared Home/suite codec exists today. Pin official github.com/sqids/sqids-go
+v0.4.1 (upstream commit 2ba95c7920dcf08340e099c7b22beb1178da6106), using
+sqids.New() and that version's fixed default alphabet, blocklist and zero minimum
+length. Encode exactly one positive integer. Require Decode to return exactly
+one integer in 1..MaxInt64 and Encode(decoded) to equal the original string.
+This preserves the integer-encoding sqid required by §10; Docs' random document
+IDs are unrelated. Golden vectors are 1=Uk, 2=gb, 3=Ef, 1000=pnd and
+MaxInt64=AqkYhRmbHpEX. Refuse zero, negative/multiple numbers, alternate encodings
+and reserved DNS labels independently. Dependency/options changes require explicit
+compatibility review and must preserve existing team sqids. The upstream
+[canonical encoding guidance](https://github.com/sqids/sqids-go/tree/v0.4.1)
+requires re-encoding; a disposable local pinned-library probe verified these vectors.
The seed checks this proposal again under the write lock. A concurrent seed makes
the old proposal fail; the operator obtains a new proposal and new owner receipt.
@@ -148,7 +158,10 @@ normalizes and blind-indexes with the same credential helper as sign-in, resolve
or creates the normal opaque person stub, and never mints a session. Synthetic
live previews require already authenticated synthetic identities and an
`existing_only:true` mode; that mode refuses a missing person and sends no mail.
-The directory cannot request address resolution over HTTP.
+The directory cannot request address resolution over HTTP. Refactor the existing
+findOrMintPerson SQL into a transaction-capable internal helper: its current
+a.db.Writer() call cannot participate in the required operator transaction.
+Keep sign-in semantics, blindIndex and day-coarsened created_at unchanged.
The result is `{version:1, operation_id, outcome:"committed", receipt}`. receipt
uses the shared closed `{v,kid,payload,signature}` envelope pattern with canonical
@@ -166,8 +179,13 @@ bootstrap receipt; existing teams/memberships may be retained. Generate a random
32-byte canonical base64url generation once, persist it and a bootstrap receipt
plus sealed result atomically. Require explicit deployment precondition that no
consumer has ever been provisioned; a database which has lost generation/receipt
-history cannot satisfy this precondition based on its own empty tables. Supported
-transport must bind the independently verified initial-install attestation. If
+history cannot satisfy this precondition based on its own empty tables. An independently
+signed external installation record and its monotonic registry floor must attest
+that this exact directory database has never had a roster generation provisioned.
+The record issuer, signature verification and durable external registry are not
+implemented by current Home or platform. They require a separate concrete design
+and approval before the adapter can construct initial-install authority. Platform
+maintenance provides exclusion, not this Home-specific historical evidence. If
that evidence is unavailable, initialization is unavailable. Restore cannot use
this verb. Ordinary boot only applies empty schema and never invokes it.
@@ -215,8 +233,10 @@ attestation. Requery pending binding, consumer enabled state, token, generation
record metadata, then switch only that existing pending binding to live and commit
its audit/result atomically. This package verifies an opaque approved activation
context; it does not fetch a URL or trust arbitrary deployment evidence JSON.
-Until the transport/operator adapter can construct that context, activation remains
-unwired. A compatibility account-link preview is not sufficient for activation.
+Current platform receipts do not attest all these Home-specific facts. The
+external provisioner/verification adapter and its pinned evidence verifier require
+a separate concrete authority design; no constructor may accept caller-controlled
+booleans as a substitute. Until that adapter exists, activation remains unwired. A compatibility account-link preview is not sufficient for activation.
## Transaction and existing-database checks
@@ -258,7 +278,7 @@ synthetic addresses, names, bearer strings, receipt payloads and private results
Prove current Home session acceptance/signout and all existing team ciphertexts
survive applying the additive tables. Mutation tests must fail when signature,
consumed-receipt uniqueness, FK verification or idempotency checks are removed.
-Demonstrate the private-FD command with a disposable local fence fixture only; that
+Demonstrate the private-stdout command with a disposable local fence fixture only; that
fixture is not evidence of platform maintenance correctness. Full repo gates, exact
CI and Fable whole-code review precede integration. Live use additionally requires
approved/shipped platform 117, operator authority and invocation/activation context