Version 0.2 · 2026-06-04 · Synthesis / decision document
This document consolidates a security model worked out with the Operator. The shape: keys form a hierarchy, an Operator's authority is bounded by their engagement, and each person's personal space sits under its own key the Operator never holds. That last point resolves a tension that surfaced earlier — that the Operator both should see their engagement and must not see a Contributor's personal space. A separate personal key resolves it structurally, not by policy.
The model has two layers that must be kept distinct: authorization (who is allowed to see — the OVA-anticipated layer) and encryption (who can physically see — the confidentiality tier). The recommendation is to build both, layered: OVA-style authorization everywhere via a seam ready for OVA when it lands; encryption-with-customer-held-keys only for the high-assurance engagements that need builder-proof confidentiality.
OVA is anticipated, not implemented. Everything here designs the seam for OVA's promised capabilities while a local stub fills it until OVA proper is ready.
Decision needed: ratify the layered model and the two boundary decisions (personal space genuinely closed to the Operator; authorization-vs-encryption handled as two distinct layers). The rater/intra-engagement disclosure grain is named here and scoped in a following document.
This document describes a target model. A CC verification pass against the live engine (2026-06-04) established what is and is not shipped. Recording it here so the rest of the document is read as intended design, not current state.
The Authorizer seam — not shipped. There is no Authorizer protocol, no LocalAuthorizer, no OvaAuthorizer in the engine. What exists is a single permissive stub, _alpha_authorizer_stub in credit/cross_engagement_memory.py (Phase 49/50), gating one read path. It takes the would-be-Authorizer arguments — so the long-horizon contract is exercised in production-shaped use — but returns True unconditionally, is not a protocol or class, is not present at every access boundary, and enforces none of the key hierarchy. The named seam the synthesis recommends (§5) is a Phase 45 recommendation, not shipped code.
The personal-space key — does not exist. Personal Memory is real, but as Phase 41's invisible Memory-only personal engagement — a separate engagement row, a persons.personal_engagement_id FK, an operator membership, personal/invisible visibility. The separation is structural and membership/designation-based, not cryptographic. Memory payloads are stored as plaintext JSONB; there is no encryption-at-rest and no per-person or per-space key of any kind. The synthesis's "the personal space has its own key, held only by the person" (§2) is a design abstraction, not a shipped key.
What this means for the model. The target model is unchanged and remains sound — but two load-bearing pieces are not yet built, and one is subtler than it first read: the key hierarchy (§2) is a design, to be implemented behind the Authorizer seam once that seam exists; and the personal-space boundary that exists today is membership/designation-based — precisely the policy-rule kind of boundary §2.2 contrasts against a structural key-held boundary. So today the boundary is the kind that can be misconfigured; the structural-key version is the target. §2.2's "cannot be misconfigured" describes the destination, not the current engine.
The rest of the document stands as the target. Read §2 and §5 as intended, with this section as the correction of record.
The Operator proposed, in working terms:
This is the right shape. The corrections below are not to the shape but to two things it leaves implicit, and one place an early version of the model nearly leaked.
Earlier in the working-through, the tension was stated as: the Operator should see everything in their engagement, and a Contributor's personal Memory must be readable only by that person. With a single Contributor key the Operator could see, the chain ran: Operator sees Contributor's key → key unlocks the Contributor's artifacts → Operator reaches the personal space. That collapses the personal-space promise. This was the live flaw.
The personal space has its own key, held only by the person. The key the Operator can see is the Contributor's engagement key — governing contributions into the engagement. The personal-space key appears nowhere in the Operator's chain.
v0.2 correction. This describes the target. Today (per §0) the personal-space boundary is membership/designation-based — the policy-rule kind, which can be misconfigured. The structural key-held boundary above is what the model commits to building, not what the engine enforces now. The destination is structural; the present is policy.
Operator key ──▶ Engagement key ──▶ Engagement Memory
(all Contributors' committed
engagement contributions)
Contributor engagement key ──▶ engagement contributions ──▶ under Engagement key ──▶ Operator reaches ✓
Contributor PERSONAL key ──▶ personal space ──▶ separate key, Operator never holds ✗
Two keys per person, two boundaries, no leak. The Operator's authority is bounded by the engagement; the personal space is bounded by a key only the person holds.
A key that "manages" content can mean two very different things, and the trust claim Loomworks can make depends entirely on which:
The difference is the difference between two threats:
The key hierarchy in §2, on its own, is doing authorization work. It bounds what each role may reach through the application. It does not by itself stop the builder, who goes around the application. To stop the builder requires encryption under keys the builder does not hold — and, because the Companion must read plaintext to reason, a place to decrypt the builder cannot inspect (secure enclaves). That is the confidentiality investigation's Mechanism 3.
So the same whiteboard drawing supports either claim. Which claim is true depends on whether the keys authorize or encrypt. This is the decision to ratify first, because every downstream claim inherits from it.
Every engagement, every key, every access is governed by an authorization layer. The key hierarchy in §2 is this layer's structure: Operator-key reaches engagement-key reaches committed contributions; personal-key is held only by the person. This covers the Operator-vs-Contributor and Operator-vs-personal-space boundaries cleanly, today, without encryption.
This layer is where OVA lands. OVA's promised capabilities map directly onto what it needs: capability-scoped credentials, least-privilege verification, role-grants-capabilities, attenuation across delegation chains, credential lifecycle as roles begin and end. Designation-as-credential (Operator / Contributor / personal-holder becomes the credential basis) is exactly OVA's model.
Encryption with customer-held keys plus enclave-sealed processing is not universal. It is reserved for engagements whose value is confidentiality from the builder — coaching, legal, clinical, regulated data. There, the engagement (or personal) key cryptographically seals content, the customer holds it, and the Companion reads plaintext only inside an attested enclave the builder cannot inspect.
Standard engagements run on §4.1 alone (authorization, governed and audited — the posture of every SaaS vendor). High-assurance engagements add §4.2. This is the tiered model from the confidentiality investigation, in the Operator's key vocabulary: authorization keys everywhere, encryption keys where it matters.
OVA is a future capability (provisional patent March 2026; full implementation gated on Kaspa vProg maturity, which Loomworks does not control). The discipline, already established in the FORAY/OVA integration strategy and the methodology, is seam-and-stub. The three steps below are the intended path; per §0, only a narrow permissive stub on one read path exists today, so all three are ahead, not behind:
Authorizer abstraction Loomworks calls at every access boundary, designed against OVA's long-horizon contract — multi-Contributor commit authority, personal-vs-engagement key separation, capability scoping, delegation chains — so it needs no breaking changes when OVA lands.LocalAuthorizer satisfying the contract for the present build (Operator/Contributor/personal-key enforcement). Throwaway in spirit; it teaches the contract.OvaAuthorizer replaces LocalAuthorizer behind the unchanged seam. Callers do not change.So the key model in §2 is to be implemented as the stub's enforcement logic, behind a seam shaped for OVA. The personal-key boundary, the engagement-key chain, the role-to-access mapping are all expressed as the contract the seam exposes. When OVA lands, it fulfills that contract with cryptographic credentials, concealment, and attenuation; nothing in Loomworks's access code paths is rewritten. (Today, per §0, neither the seam nor the key model is built — this is the path, not the present.)
The design rule: design the seam against OVA's promised capabilities; implement the stub for the present case. The synthesis here is the contract the seam must express.
One case the key hierarchy does not cover, named here rather than assumed solved:
A 360 rater is a Contributor whose input must reach the Operator (so the coach can synthesize) but must not be visible — attributed — to the client, who is also a Contributor on the same engagement. Both contribute into the same engagement, so both roll up under the one engagement key. The engagement key alone cannot distinguish "Operator sees, client does not." That requires a finer grain inside the engagement layer — per-contribution disclosure bands, the disclosure-layer investigation's subject, expressed in the OVA-anticipated model as per-contribution capabilities, not another top-level key.
This is the next document: the rater/intra-engagement disclosure grain, built on this synthesis once the layered model is ratified. It is deliberately not solved here, because solving it before the foundation is ratified risks building against the wrong foundation.
This synthesis names the model and the decisions; it does not pre-empt the scoping. The cost and trade-off of the high-assurance encryption tier (enclave infrastructure, customer-held-key recovery burden, the where-does-decryption-happen question relative to the model call) are carried in the confidentiality investigation and remain open. Ratifying the layered model does not commit to building the encryption tier yet — only to keeping the model coherent so the tier can be added when an engagement needs it.