# Platform authority facts: owner review contract HUB-WP-0012 T01/T02, reviewed 2026-10-04. Hub-side composition and User Engine HTTP client are implemented; **no real Hub caller admission or complete live account/tenant composition is claimed**. The current client contract and remaining owner requirements are in [the October 4 update](#implemented-account-reader--2026-10-04); the earlier sections preserve the initial review. ## Historical source review — 2026-09-28 - User Engine `b4cef6446bc10555b598ea74de1743bc9b03e7ba`: `service.py::me` creates user/account/tenant-account/identity records for unknown `(issuer, subject)`. It cannot be an authorization lookup. `identity_context` reads linked identity/account and membership evidence without this provisioning, but accepts an actor or target user ID, not an admitted Hub workload's lookup of an arbitrary immutable identity. It does not establish Hub's root entitlement. `PLATFORM_TENANT` is `platform:root`; token `platform-operator` roles are not evidence of a live root grant. - Tenant Engine `4ce89969c0cc0ab4ba111f1b4009aa137c94a68b`: `GET /tenants/{tenant_id}` exposes lifecycle/version and accepts an `actor` query for authorization. `/roles/live` returns tenant roles, not a person's root entitlement. These route handlers do not authenticate a Hub workload. An admitted authenticating gateway could supply that boundary, but no such composition is established by these sources. These are source findings, not probes of deployed configurations. The follow-up User Engine commit `686da7c` adds `UserEngineService.lookup_account_authority`: an authorized exact issuer/subject/tenant lookup that never provisions a missing identity, returns current global and scoped account status (missing scoped state is explicit), and separates caller from target. The new policy action is `account.authority.read`; existing generic read grants are not assumed sufficient. Its result includes source observation time, identity/account references and the policy decision reference, but no root entitlement or profile data. This closes the read-only **service primitive**, not the wire contract or admitted Hub workload. USER-WP-0037 owns root-grant/mapping disposition and authenticated HTTP exposure/private acceptance. No database, live grant or credential changed. ## Initial contract for owner disposition — 2026-09-28 | Requirement | Owning decision | | --- | --- | | Side-effect-free lookup by exact issuer and subject | User Engine: existing identity only; unknown identity denies without provisioning | | Current account state and explicit root grant | User Engine + NetKingdom: identity link, global and scoped account state, grant source/revocation/version, independent of JWT roles and Hub root-subject configuration | | Platform naming | Both owners: explicit reviewed mapping of User Engine scope to canonical `tenant:platform`; no string substitution inferred by Hub | | Current tenant lifecycle | Tenant Engine: canonical identifier bound to immutable record and version | | Caller authentication | Each owner: dedicated Hub workload audience/identity and narrowly scoped read authorization; no end-user bearer forwarding | | Freshness and evidence | Each owner: source observation timestamp and durable evidence/version reference; no stale cache on failure | | Producer aliases | Account/identity owner: explicit current bindings, or an empty set; no aliases derived from display names | Owners must specify the actual route, request/response schema, authentication mechanism and scoped grants before HTTP reader implementations can be written. The Python types below are an internal normalization seam, **not a proposed HTTP endpoint that already exists**. Missing/unknown/ambiguous results must raise and deny; they must never synthesize an active account. ## Initial composition — 2026-09-28 `hub_core.security.facts.PlatformFacts` implements `FactSource` with injected `AccountReader` and `TenantReader`. The account reader returns a typed `AccountObservation`; the tenant reader returns a `TenantObservation`. Readers own authentication and wire verification. `account_active` must include the current identity link, global account and required scoped-account validity; a globally active account alone is insufficient. They receive identity references only, not the end-user token. No concrete network reader or automatic environment activation is provided. The host supplies the reviewed account-tenant identifier and mapping evidence reference explicitly. That mapping is not an entitlement grant. This candidate admits only human actors in `tenant:platform`; workload and cross-tenant lookups remain separately scoped work. The shared controller still verifies the exact root issuer/subject before consulting this source. Every request rereads both owners within one three-second budget. Results must match exact identity/tenant bindings, contain strict booleans and nonempty evidence, and be no older than five seconds or in the future. The result retains the oldest source timestamp, so slow joining/policy/audit cannot refresh authority. Inactive or withdrawn state remains a valid observation and is denied by the controller. Failures expose only a sanitized 503 and never fall back to an earlier allow. Cancellation propagates to the pending lookup. The evidence join is SHA-256 over canonical JSON containing the account, tenant and mapping references. Readers/owners must retain the referenced evidence for reconstruction; this hash is a join identifier, not a signature or independent proof of owner authenticity. No account payload or credential enters the join. ## Initial acceptance cases and remaining work — 2026-09-28 Local tests cover exact bindings, malformed state, stale/future observations, oldest-timestamp preservation, bounded outages, repeated lookup, entitlement and account suspension, tenant inactivity, and refusal before policy after withdrawal. Fixtures implement the internal readers; they do not prove owner API acceptance. T01/T02 remain open for owner disposition of the table above, implementation of real authenticated readers, and isolated owner-source integration tests proving unknown lookups create nothing. Private acceptance must then demonstrate root allow, ordinary/forged identity denial, next-request revocation and owner outages with real admitted callers. No public exposure follows from this contract. ## Implemented account reader — 2026-10-04 The historical missing-endpoint assessment above is superseded by User Engine `a9360842f84fae89857c2b1a298efc64d079ee7b`, USER-WP-0037 and accepted NetKingdom ADR-0017 revision 2 (`45a189a39167eef62709df0e857309f7ddc59029`). `UserEngineAccountReader` implements the existing `POST /api/v1/platform/account-authority/lookup` wire contract. Its independently configured bearer maps to the fixed admitted workload at User Engine; it never forwards the human's Hub token or invents root entitlement. A host injects a `UserEngineAccountReader(base_url=..., token_file=Path(...), client=...)` into `PlatformFacts(accounts=..., tenants=reviewed_tenant_reader, account_tenant="platform", mapping_evidence="NK-ADR-0017:2")`. The HTTP client must be lifecycle-owned, with `trust_env=False` and no ambient authorization or cookies (as in the existing security composition). The token file is dedicated to this User Engine caller, not the PDP/audit/browser credential. Nothing is automatically enabled by environment variables or this documentation example. The reviewed custody adapter and its real service integration fixture require lookup tenant **`platform`**. This differs from User Engine's legacy operator context `platform:root`; neither is silently normalized by the reader. The canonical Hub actor/target remains `tenant:platform`. Before live enablement, owners must confirm the real account has the intended scoped account and that this exact mapping is admitted; a missing scoped account is inactive. The response must bind issuer, subject and lookup tenant, identity/account/user references, decision reference, known global/scoped status, and timezone-aware observation time. `root_grant:null` means no entitlement. A non-null grant must match exact issuer/subject, `scope_type:tenant`, `scope_id:platform`, relation `platform-root-custodian`, owner `net-kingdom-custody`, source record `nk-custody:platform-root`, positive integer revision and valid timestamps. Unknown/expired/revoked or differently scoped observations fail closed. Hub deliberately keeps its stricter five-second source age on every read/write, even though the canon permits up to fifteen minutes elsewhere. The earliest account/custody timestamp is retained, and the grant's absolute expiry travels through AccountObservation and LiveFacts to the final post-audit check. The reader trusts User Engine's authenticated observation; User Engine owns durable custody revision/rollback validation. A content digest identifies retained account/grant evidence but does not independently authenticate the publisher. No producer aliases are supplied by this contract, so the result has none. Every call rereads a bounded workload credential, uses non-local HTTPS and a three-second total budget, limits the response to 64 KiB, rejects redirects, compressed responses and nonzero Age headers, and exposes sanitized failures. No caching or same-token fallback exists. User Engine's current environment-based receiver credential rotation still needs an owner rollout/revocation receipt. ## Remaining dependencies — 2026-10-04 | Hub tasks | Owner and required artifact | What unblocks Hub | | --- | --- | --- | | 0012-T01 | net-kingdom, user-engine, tenant-engine, access-engine and platform surface owners: reviewed action/audience/tenant/enforcement matrix with disputed rows resolved | Signed-off source/profile mapping; executable per-owner acceptance cases | | 0012-T02 | user-engine USER-WP-0037-T03 + railiance-platform/rapp-user-engine: actual Hub workload identity, dedicated credential delivery/rotation reference, TLS origin and scoped account mapping | Wire this implemented client to an admitted private endpoint and prove allow/deny/withdrawal/outage without owner payloads or credentials in evidence | | 0012-T02 | tenant-engine + deployment owner: authenticated Hub caller binding for authoritative lifecycle read, canonical identifier/record version and observation time | Implement TenantReader against that admitted response; do not treat actor query text or roles/live as workload authentication | | 0012-T02 | net-kingdom/KeyCape + custody owner: actual immutable root identity, approved nonempty custody grant where intended, Hub audience/redirect registration and attended AAL2/recovery/revocation receipts | Real positive root journey; the accepted empty custody source proves denial only | | 0012-T03 | access-engine + platform owner: Hub protected-system policy, authenticated workload grant, pinned trusted public keys and credential delivery; audit-core + platform owner: Hub sender classes including hub.operation.committed, operational custody and rotation/failure receipts | Compose real PDP/audit dependencies; existing FLEX-WP-0024/0025 source completion does not admit Hub | | 0012-T04 | rapp-core-hub plus T02/T03 owners: pinned private image/migration/composition, network boundary, explicit owner-bound messaging/event producer aliases and rollback | Execute real browser/API/MCP, direct-service bypass, revocation and audit-outage acceptance | | 0012-T05 | ops-hub first, other inventoried extensions, activity-core/Repo Manager/inbox caller owners: per-audience identity/delegation/tenant contract and host enforcement | Root and workload allow plus anonymous/non-root/wrong-audience/tenant denial with separate attribution | | 0012-T06 | platform/Railiance owners after T04/T05: attended per-surface management and audit receipts | M1 requires every inventory row, not a navigation link or broad provisioning decision | | 0012-T07 | rapp-core-hub RAPPCOREHUB-WP-0002-T05 after M1: explicit public-enable authorization, TLS/bypass/rollback packet | Package and enable only the reviewed public release | | 0012-T08 | identity/tenant/policy owners after M1: roles, delegated principals and stored tenant provenance | Phase 2 implementation can start without inferring tenant authority from legacy data | These requirements update the existing workplans; they are not messages claiming external owners have accepted new work. No control was relaxed or live credential retrieved in this review. Workplans 0006/0011 independently retain A5/A4 cutover and inbox source-feed/retention/reader-admission requirements. Local verification: `make ci-check` covers normalization, transport refusal, rotation, withdrawal and post-audit expiry. To exercise the actual owner route and serializer with synthetic authority, run `HUB_CORE_USER_ENGINE_SOURCE=/home/worsch/user-engine .venv/bin/python -m pytest -q tests/test_user_engine_owner_contract.py`. The owner suite is explicit opt-in and does not contact a live endpoint.