Specify explicit pending-consumer standing verification amendment
1 file changed,
+95
−0
implementation/pending-consumer-verification.md+95 −0
CI passed — run details
diff --git a/implementation/pending-consumer-verification.md b/implementation/pending-consumer-verification.md| new file mode 100644 |
| index 0000000..ddf0ee8 |
| --- /dev/null |
| +++ b/implementation/pending-consumer-verification.md |
| @@ -0,0 +1,95 @@ |
| +# Pending consumer verification window |
| + |
| +Status: proposed focused amendment, 2026-09-08. Home37's core/provisioner design |
| +was approved at898fe21; this document seeks explicit approval for the change to |
| +the producer's live-only rule before any code. Producer32fb49c and roster contract |
| +4e7b3ff remain the source contracts. No live consumer activation is authorized. |
| + |
| +A pending Docs instance cannot complete actual TeamMode acceptance while call8 |
| +refuses pending bindings. Add an audited, temporary standing window for precisely |
| +one pending consumer. During that window, current team members can gain actual app |
| +standing, subject to the existing item-permission checks and60-second roster lease. |
| +The chooser still shows only live bindings. This is a bounded authorization change, |
| +not a read-only probe or a cosmetic navigation flag. |
| + |
| +Use new additive directory tables: immutable verification_attempts keyed by operation |
| +ID, and verification_active keyed by consumer ID with a foreign key to its attempt. |
| +An attempt binds consumer/team/app/origin/generation, exact provisioning record |
| +sequence/digest, expected current roster epoch and owner person_ref, issued_at, |
| +expires_at and the signed authorization digest. Completion/rejection/activation |
| +history uses an additional append-only outcome table. Preserve the existing |
| +roster_operator_receipts CHECK enum unchanged. No schema boot creates a window. |
| + |
| +`directory.verify-consumer` uses the approved signed-private-input verifier and |
| +fresh console-owner maintenance approval. The exact signed payload sets absolute |
| +issued_at/expires_at, with positive lifetime at most600 seconds. The app never |
| +adds600 seconds at execution/retry time. The transaction checks positive clock, |
| +no future issuance, unexpired request, generation equality, pending exact registry |
| +binding, enabled consumer, matching record sequence/digest and epoch, and current |
| +owner membership matching the signed expected owner. It requires no active attempt; |
| +an expired attempt may be removed only from verification_active while its immutable |
| +attempt/outcomes remain. Never overwrite/delete its history. Write attempt, active |
| +pointer and sealed idempotent result with the operator receipt/sequence advancement |
| +in the same immediate transaction on a verified-FK-ON connection. |
| + |
| +Exact operation replay returns its prior result without extending any time. Different |
| +payload under the same operation ID refuses. A new deliberately approved attempt |
| +needs a new signed operation and actual fresh console approval; opening while the |
| +previous attempt is active refuses. Failure, timeout, consumer requests, hint, browser |
| +assertion, GET, polling and retry cannot open or renew a window. No sibling instance |
| +can select this consumer's window or supply its own expiry. |
| + |
| +The producer's existing one-read-transaction authorization first resolves the exact |
| +current/approved-overlap bearer hash, enabled consumer and matching registry. Keep |
| +all challenge/cursor/epoch/generation/compiled-route checks. For state=live the |
| +behavior remains unchanged. For state=pending it additionally joins the active |
| +attempt and requires exact consumer/team/app/origin/generation/provisioning record |
| +sequence/digest, valid positive stored times, issued_at<=now<expires_at, and matching |
| +still-current owner membership. Refuse disabled or any other state. Pending without |
| +that exact valid attempt returns the same existing fixed503 as unsupported pending. |
| +Wrong or foreign bearer/team retain existing401/404 behavior. A window grants no |
| +other pending binding, account, alias, consumer or route access. Browser chooser |
| +queries remain live-only. |
| + |
| +Every page, including cursor pages, rechecks the window and consumer state under the |
| +same read transaction. Neither a signature nor a cursor bypasses expiry. Epoch |
| +changes retain the ordinary signed409 pagination behavior; a completed new snapshot |
| +can observe current membership during the window. Activation requires new evidence |
| +if its expected epoch changed. Owner removal stops further pending reads immediately |
| +at the next source check. Producer sign/HTTP/privacy requirements remain those of the |
| +approved shared roster and HTTP integration; no new wire fields, cache-age shortcut |
| +or unsigned response is added. |
| + |
| +Expiry, disable or owner removal prevents subsequent successful fetches. Existing |
| +consumer leases retain at most the approved60 seconds from their last successful |
| +fetch start, including the fetch duration; this also applies to pending instances. |
| +Measure this bound in actual Docs request, commit and quiet-SSE tests. The window's |
| +absolute end is therefore not an instantaneous revocation guarantee: residual |
| +standing may last until that established lease ceiling. The producer has no timer |
| +or request path that renews the window. An accepted generation change still fences |
| +consumer standing according to the approved roster contract. |
| + |
| +`directory.activate-consumer` accepts the exact verification attempt ID and signed |
| +bounded activation evidence from the provisioner collectors: expected epoch/owner, |
| +record digest, generation, app release/artifact, checked protected environment binding, |
| +credential consumer manifest digest and materialized canonical alias. It requires |
| +that attempt to be active and unexpired and all current bindings/owner/epoch to match |
| +under its transaction lock. Mark only that binding live, remove its active pointer, |
| +append completion history, and commit its sealed result/sequence together. Exact |
| +replay returns the same result. Changed evidence refuses. New verification for an |
| +already-live binding refuses. A failed activation leaves pending unchanged and does |
| +not extend the active attempt. Expired evidence requires a distinct newly approved |
| +attempt; no automatic activation exists. |
| + |
| +Tests use actual additive schemas and real signed operator inputs plus shared roster |
| +signing/verifier. Cover 0/599/600-second boundaries, future/negative/overflow times, |
| +partial/corrupt rows, wrong token/team/generation/record/owner, current and overlap |
| +bearers, owner removal, disable, epoch changes between pages, cursor crossing expiry, |
| +no-other-pending-instance access, unchanged live path and hidden chooser. Exercise |
| +simultaneous open/activate, changed-payload replay, expired retry and lost-result |
| +recovery with exact byte-identical result. Mutations removing exact scope, expiry, |
| +owner or active-pointer checks must fail. Actual TeamMode canary proves member |
| +standing and item isolation during the window,60-second residual revocation under |
| +failed refresh, and final two-team chooser isolation after activation. Full gates, |
| +CI and Fable code review precede integration; approved/shipped platform117 and real |
| +fresh-owner approval precede any live operation. |