From 0930f9a3c43b93614ade972c9357c6c6a5e834eb Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 13 Sep 2026 19:00:44 +0000 Subject: [PATCH 1/5] Add 0.3-draft CL-Pass companions and weekend protocol proposal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Land closed companion schemas, examples, spec, crosswalk, and T01–T10 vectors beside unchanged 0.2 Lite. Keep Apache-2.0 / CC BY 4.0. Co-authored-by: sierra --- CHANGELOG.md | 1 + LICENSING.md | 4 + README.md | 13 ++ .../2026-09-weekend-protocol-proposal.md | 151 +++++++++++++ protocol/companions/0.3-draft/DRIVE-PAGE.md | 61 ++++++ protocol/companions/0.3-draft/README.md | 88 ++++++++ protocol/companions/0.3-draft/crosswalk.md | 26 +++ .../0.3-draft/examples/approval-handle.json | 18 ++ .../0.3-draft/examples/claim-annotation.json | 17 ++ .../0.3-draft/examples/client-pairing.json | 14 ++ .../0.3-draft/examples/context-pass.json | 24 ++ .../examples/identity-assertion.json | 17 ++ .../0.3-draft/examples/lifecycle-event.json | 17 ++ .../schemas/approval-handle.schema.json | 97 ++++++++ .../schemas/claim-annotation.schema.json | 103 +++++++++ .../schemas/client-pairing.schema.json | 103 +++++++++ .../schemas/context-pass.schema.json | 159 ++++++++++++++ .../schemas/identity-assertion.schema.json | 93 ++++++++ .../schemas/lifecycle-event.schema.json | 200 +++++++++++++++++ protocol/companions/0.3-draft/spec.md | 143 ++++++++++++ test-vectors/cl-pass/VECTORS.md | 207 ++++++++++++++++++ 21 files changed, 1556 insertions(+) create mode 100644 docs/proposals/2026-09-weekend-protocol-proposal.md create mode 100644 protocol/companions/0.3-draft/DRIVE-PAGE.md create mode 100644 protocol/companions/0.3-draft/README.md create mode 100644 protocol/companions/0.3-draft/crosswalk.md create mode 100644 protocol/companions/0.3-draft/examples/approval-handle.json create mode 100644 protocol/companions/0.3-draft/examples/claim-annotation.json create mode 100644 protocol/companions/0.3-draft/examples/client-pairing.json create mode 100644 protocol/companions/0.3-draft/examples/context-pass.json create mode 100644 protocol/companions/0.3-draft/examples/identity-assertion.json create mode 100644 protocol/companions/0.3-draft/examples/lifecycle-event.json create mode 100644 protocol/companions/0.3-draft/schemas/approval-handle.schema.json create mode 100644 protocol/companions/0.3-draft/schemas/claim-annotation.schema.json create mode 100644 protocol/companions/0.3-draft/schemas/client-pairing.schema.json create mode 100644 protocol/companions/0.3-draft/schemas/context-pass.schema.json create mode 100644 protocol/companions/0.3-draft/schemas/identity-assertion.schema.json create mode 100644 protocol/companions/0.3-draft/schemas/lifecycle-event.schema.json create mode 100644 protocol/companions/0.3-draft/spec.md create mode 100644 test-vectors/cl-pass/VECTORS.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 969c2b9..eeb5633 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ This file records material changes to the Context Layer working draft and its pu ## Unreleased +- Add the 2026-09 weekend protocol proposal: closed 0.2 Lite remains authoritative; `context-layer/0.3-draft` CL-Pass companions and T01–T10 vectors sit beside it for Sierra review. - Confirm the dual-license boundary and contribution terms before publishing the first proof-of-work prerelease. - Populate the canonical protocol-only GitHub repository from the reviewed release commit. - Consolidate specification, reference, schema, and fixture artifacts under the explicit `protocol/` boundary; keep website and deployment source outside this repository. diff --git a/LICENSING.md b/LICENSING.md index 9d40d48..db6768c 100644 --- a/LICENSING.md +++ b/LICENSING.md @@ -29,4 +29,8 @@ Website application, hosting, and deployment source are intentionally outside th If a file combines executable software with embedded explanatory prose and is not explicitly listed in the documentation section, Apache-2.0 applies to the whole file. Third-party dependencies, quoted standards text, linked external material, trademarks, and generated dependency notices remain governed by their own terms. +## Protocol proposal (weekend ship) + +The 2026-09 weekend protocol proposal and `protocol/companions/0.3-draft` companion materials are part of this repository. Schemas, examples, and other executable companion artifacts use Apache-2.0. Proposal prose, companion specification pages, and `test-vectors/cl-pass/VECTORS.md` use CC BY 4.0. This note does not relicense the existing v0.2 product or replace `LICENSE` / `LICENSE-DOCS`. + No license grants trademark rights or implies endorsement, protocol adoption, production readiness, security certification, or warranty. diff --git a/README.md b/README.md index b6ec0d6..9fd7ce4 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ This is the canonical public repository for both the protocol and its published - [Experimental local core](packages/local-core/) - [Threat model](docs/context-layer-threat-model.md) - [Executable v0.2 vectors](test-vectors/v0.2/) +- [Weekend protocol proposal (0.2 Lite + 0.3 CL-Pass)](docs/proposals/2026-09-weekend-protocol-proposal.md) ## Protocol flow @@ -107,6 +108,18 @@ npx vercel dev site The repository test suite verifies that all published routes and their required assets remain present. Changes to public copy or design should be made here first so the repository and live documentation cannot silently diverge. +## Protocol proposal (weekend ship) + +The 2026-09 weekend cut keeps `CL-Core-Lite` closed and adds a reviewable `context-layer/0.3-draft` companion pack (CL-Pass) beside it. This does not open the five Lite schemas, mint a live issuer, or land Switchboard / ouro work. + +| Path | Purpose | +| --- | --- | +| [docs/proposals/2026-09-weekend-protocol-proposal.md](docs/proposals/2026-09-weekend-protocol-proposal.md) | Technical write-up for Sierra review | +| [protocol/companions/0.3-draft/](protocol/companions/0.3-draft/) | Companion objects, closed schemas, examples, Drive close page | +| [test-vectors/cl-pass/VECTORS.md](test-vectors/cl-pass/VECTORS.md) | Required T01–T10 oracles (schema-valid JSON is not a pass) | + +Closed Drive records: [0.3 companion close](https://docs.google.com/document/d/19ZNUrP3zCxRxbXvQ-0EBV9MKuMcJbkKXLKp58MTHtUA/edit) · [CL-Pass vectors](https://docs.google.com/document/d/1NGbs7kSk__BtxwkjP-BhMKe_5A99phNVCFA3ICj7nw8/edit). + ## Security and licensing Report vulnerabilities through [GitHub private vulnerability reporting](https://github.com/sierracatalina/context-layer/security/advisories/new); do not post exploit details in a public issue. diff --git a/docs/proposals/2026-09-weekend-protocol-proposal.md b/docs/proposals/2026-09-weekend-protocol-proposal.md new file mode 100644 index 0000000..d34b5f9 --- /dev/null +++ b/docs/proposals/2026-09-weekend-protocol-proposal.md @@ -0,0 +1,151 @@ +# Context Layer — weekend protocol proposal + +| Field | Value | +| --- | --- | +| Status | Reviewable proposal for Sierra Catalina — not an adopted standard | +| Date | 2026-09-13 | +| Closed Lite | `context-layer/0.2-draft` CL-Core-Lite | +| Companion profile | `context-layer/0.3-draft` CL-Pass | +| Repo | https://github.com/sierracatalina/context-layer | +| License | Existing repository boundary (Apache-2.0 software / CC BY 4.0 prose). This proposal does not relicense v0.2. | + +This is the weekend ship write-up. It states what is already closed, what the 0.3 companions add beside Lite, and what this cut does not do. + +## What Context Layer is + +Context Layer is a protocol for moving the minimum useful context across applications, models, and agents while keeping authority with the user. The vault is user-owned. Isolation is purpose-bound: a consumer receives an approved scoped bundle, not an unrestricted vault query interface. + +Every disclosing exchange begins with a declared purpose, passes through policy, produces a recipient-bound scoped bundle, and leaves a minimized receipt. New memory enters only as a proposal. Authentication of a principal is not authorization to read the vault. + +The published v0.2 product (schemas, reference runtime, local-core proof, public dossier) remains the closed Lite line. This proposal does not open those objects. + +## Closed 0.2 Lite + +The five CL-Core-Lite objects stay closed (`additionalProperties: false`). Implementations MUST reject unknown top-level fields. Version `0.2-draft` does not define portable `extensions` or `required_extensions` members. + +| Object | Role | +| --- | --- | +| `context_request` | Purpose-bound ask: requester, recipient, `purpose_code`, `{ predicate }` selectors, actions, retention, receipt requirement, expiry | +| `policy_decision` | Four-state outcome: `allow`, `allow_with_reductions`, `deny`, `needs_approval` | +| `scoped_context_bundle` | Recipient-bound, single-use, expiring packet of approved claims only | +| `memory_update_proposal` | Proposal-only writeback; commit is not a standing read grant | +| `receipt` | Payload-minimized evidence (`payload_included` is `false`) | + +Authoritative schemas: [`protocol/schemas/`](../../protocol/schemas/). Synthetic fixtures: [`protocol/fixtures/`](../../protocol/fixtures/). Executable v0.2 vectors: [`test-vectors/v0.2/`](../../test-vectors/v0.2/). + +### Flow + +```text +context_request + -> policy_decision + -> scoped_context_bundle (only on allow / allow_with_reductions) + -> capability-bound action + -> receipt + -> memory_update_proposal (optional; review then commit) +``` + +`needs_approval` is a successful protocol outcome. It is not a transport failure and it is not a read. + +### Why Lite stays closed + +Lite is the interoperable experiment surface. Opening it to carry identity, pairing, pass, approval-handle, lifecycle, or annotation fields would: + +- silently treat unknown members as authorized extensions; +- let a schema-valid identity object masquerade as a grant; +- mix pairing and pass into the request/decision/bundle contract; +- make T01–T10 oracles untestable against a stable baseline. + +0.3 companions are therefore **not Lite patches**. They use `spec_version: context-layer/0.3-draft` and `additionalProperties: false` on their own objects. Reason codes such as `IDENTITY_ONLY`, `PAIRING_REQUIRED`, `PURPOSE_NOT_ON_PASS`, `CATEGORY_NOT_ON_PASS`, and `PASS_REVOKED` travel on the existing `policy_decision.reason_codes` array. They are not new Lite fields. + +## 0.3 / CL-Pass companions + +Companion pack: [`protocol/companions/0.3-draft/`](../../protocol/companions/0.3-draft/). + +| Object | Role | +| --- | --- | +| `identity_assertion` | Authenticates a principal. `context_grant` MUST be `false`. | +| `client_pairing` | Admits an exact `client_instance` only. Pairing is not a pass. | +| `context_pass` | Grants `memory_category` values and allowed purpose codes. Necessary, not sufficient. | +| `approval_handle` | Returned on `needs_approval`. MUST NOT carry claim text or vault payloads. | +| `lifecycle_event` | Content-free lifecycle beside receipts. `payload_included` MUST be `false`. | +| `claim_annotation` | Rides beside claims until a 0.3 core revision. Evidence labels MUST NOT be upgraded. | +| `memory_category` | Closed enum: `preference` \| `fact` \| `project` \| `instruction` | + +Companion schemas and examples live under [`protocol/companions/0.3-draft/schemas/`](../../protocol/companions/0.3-draft/schemas/) and [`examples/`](../../protocol/companions/0.3-draft/examples/). Do not invent types. Object names and invariants match the closed Drive record in [`DRIVE-PAGE.md`](../../protocol/companions/0.3-draft/DRIVE-PAGE.md). + +### Invariants (normative for CL-Pass) + +1. **Identity ≠ grant.** `identity_assertion.context_grant` MUST be `false`. Authenticating a principal MUST NOT disclose vault claims. +2. **Identity-only is not authorized disclosure.** A consumer holding only an identity assertion MUST NOT be treated as authorized to submit a disclosing `context_request` and MUST NOT be issued a `scoped_context_bundle`. +3. **Pairing ≠ pass.** `client_pairing` admits an exact `client_instance` only. No wildcards. +4. **Unpaired clients** MUST receive `deny` or `needs_approval`. +5. **A pass is necessary, not sufficient.** Every disclosure still requires 0.2 `context_request` → `policy_decision` → `scoped_context_bundle`. An active `context_pass` is not a bundle, wildcard selector, or ambient vault access. +6. **Categories grant; predicates select.** The pass grants `memory_category` values. The request still names `{ predicate }` selectors. An off-pass category MUST be denied or force `needs_approval` for the exact request. +7. **Ask ≠ read.** `needs_approval` is a successful protocol outcome. `approval_handle` MUST NOT include denied claim values, claim text, or vault payloads. +8. **Write approval ≠ read pass.** Committing a `memory_update_proposal` MUST NOT mint or widen a `context_pass`. +9. **Revocation is prospective.** Revoking a pass or pairing MUST prevent future bundles. It cannot un-disclose issued bundles. +10. **Lifecycle is content-free.** `lifecycle_event.payload_included` MUST be `false`. +11. **Evidence is not upgraded.** `inferred` MUST NOT be disclosed as `stated_by_user` or `direct_user_save`. +12. **Vault ≠ public profile.** Visibility `vault` MUST NOT appear on a public profile. + +### Companion flow + +```text +identity_assertion (not a grant) + -> client_pairing (exact client_instance) + -> context_pass (categories + purpose codes) + -> 0.2 request / decision / bundle +``` + +`needs_approval` returns `approval_handle` as success. Proposal commit MUST NOT mint a pass. `lifecycle_event` sits beside receipts and carries no content. `claim_annotation` rides beside claims until a 0.3 core revision. + +`lifecycle_event.operation` stays exactly: + +`pass.issued` | `pass.revoked` | `pairing.revoked` | `proposal.committed` | `bundle.issued` | `bundle.expired` + +### Required tests + +Schema-valid JSON is not a pass. A CL-Pass claim MUST publish results for T01–T10. The oracles are in [`test-vectors/cl-pass/VECTORS.md`](../../test-vectors/cl-pass/VECTORS.md). + +| ID | Invariant | +| --- | --- | +| T01 | Identity is not a vault grant | +| T02 | Unpaired client: ask is not read | +| T03 | `purpose_code` absent from pass (no prefix match) | +| T04 | Off-pass category; denied text absent | +| T05 | Later on-pass read still needs a new request | +| T06 | Proposal commit does not mint or widen a pass | +| T07 | Revoked pass cannot obtain a later bundle | +| T08 | `lifecycle_event` is content-free | +| T09 | `inferred` is not emitted as `stated_by_user` | +| T10 | Visibility `vault` is absent from public-profile export | + +## Pointers + +| Artifact | Location | +| --- | --- | +| Companion pack | [`protocol/companions/0.3-draft/`](../../protocol/companions/0.3-draft/) | +| Companion spec | [`protocol/companions/0.3-draft/spec.md`](../../protocol/companions/0.3-draft/spec.md) | +| 0.2 ↔ 0.3 crosswalk | [`protocol/companions/0.3-draft/crosswalk.md`](../../protocol/companions/0.3-draft/crosswalk.md) | +| Drive close page | [`protocol/companions/0.3-draft/DRIVE-PAGE.md`](../../protocol/companions/0.3-draft/DRIVE-PAGE.md) | +| T01–T10 vectors | [`test-vectors/cl-pass/VECTORS.md`](../../test-vectors/cl-pass/VECTORS.md) | +| Closed Lite schemas | [`protocol/schemas/`](../../protocol/schemas/) | +| Drive close (canonical) | https://docs.google.com/document/d/19ZNUrP3zCxRxbXvQ-0EBV9MKuMcJbkKXLKp58MTHtUA/edit | +| Drive vectors (canonical) | https://docs.google.com/document/d/1NGbs7kSk__BtxwkjP-BhMKe_5A99phNVCFA3ICj7nw8/edit | + +## Non-goals (this weekend cut) + +This proposal ships **Context Layer only**. The weekend four-protocol set is PCP · Context Layer · Legatus · AAA. The other three are out of this repository. + +Do not do any of the following in this cut: + +- Switchboard / Egoist adapter, SDK, OIDC, MCP, or type-name imports +- Grok Bot adapter +- PCP grants +- Legatus envelope +- Live issuer +- ouro / Ouroboros landing +- Opening the five Lite schemas +- Wildcards for categories, purpose codes, or `client_instance` +- Un-disclosure of already issued bundles +- Relicensing the public repository from Apache-2.0 / CC BY 4.0 to MIT diff --git a/protocol/companions/0.3-draft/DRIVE-PAGE.md b/protocol/companions/0.3-draft/DRIVE-PAGE.md new file mode 100644 index 0000000..ec660da --- /dev/null +++ b/protocol/companions/0.3-draft/DRIVE-PAGE.md @@ -0,0 +1,61 @@ +# CLOSED Context Layer 0.3-draft companions (CL-Pass) — 2026-08-29 + +Landed from the closed Drive record. Canonical URL: + +https://docs.google.com/document/d/19ZNUrP3zCxRxbXvQ-0EBV9MKuMcJbkKXLKp58MTHtUA/edit + +CLOSED 2026-08-29 by DaddyBot. + +Context Layer — `context-layer/0.3-draft` companion addendum (CL-Pass) + +0.2 Lite schemas remain closed. No PCP grants. No Legatus. No live issuer. No ouro. + +Canonical pack (schemas + examples + spec.md): upload as `context-layer-0.3-companions.zip` in the same Drive folder. Coordinator pack for this weekend ship is the base64 gzip tar (md5 `6052995f6e54a874a6dd18cfc41da3ff`). Empty truncated stub from a blocked upload was renamed: `EMPTY STUB ignore — Context Layer 0.3 (blocked upload)`. Do not treat that stub as the spec. + +## Objects (companion only) + +`identity_assertion`, `client_pairing`, `context_pass`, `approval_handle`, `lifecycle_event`, `claim_annotation`, plus closed enum `memory_category` (`preference` | `fact` | `project` | `instruction`). + +All use `spec_version` `context-layer/0.3-draft` and `additionalProperties: false`. They are not Lite patches. + +## Closed 0.2 Lite (do not open) + +`context_request`, `policy_decision`, `scoped_context_bundle`, `memory_update_proposal`, `receipt`. + +## Invariants (normative for CL-Pass) + +1. Identity is not a context grant. `identity_assertion.context_grant` MUST be `false`. Authenticating a principal MUST NOT disclose vault claims. +2. Identity-only consumers MUST NOT be treated as authorized to submit a disclosing `context_request` and MUST NOT be issued a `scoped_context_bundle`. +3. Pairing is not a pass. `client_pairing` admits an exact `client_instance` only. +4. Unpaired clients MUST get `deny` or `needs_approval`. +5. A pass is necessary, not sufficient. Every disclosure still requires 0.2 `context_request` → `policy_decision` → `scoped_context_bundle`. An active `context_pass` is not a bundle, wildcard selector, or ambient vault access. +6. Categories grant; predicates select. Pass grants `memory_category` values. Request still names `{ predicate }` selectors. Off-pass category MUST be denied or `needs_approval` for the exact request. +7. Ask is not read. `needs_approval` is a successful protocol outcome. `approval_handle` MUST NOT include denied claim values, claim text, or vault payloads. +8. Write approval is not a read pass. Committing a `memory_update_proposal` MUST NOT mint or widen a `context_pass`. +9. Revocation is prospective. Revoking a pass or pairing MUST prevent future bundles. It cannot un-disclose issued bundles. +10. Lifecycle events carry no content. `payload_included` MUST be `false`. +11. Evidence labels MUST NOT be upgraded. `inferred` MUST NOT be disclosed as `stated_by_user` or `direct_user_save`. +12. Public profile is not the vault. Visibility `vault` MUST NOT appear on a public profile. + +## Flow + +`identity_assertion` (not a grant) → `client_pairing` (exact `client_instance`) → `context_pass` (categories + purpose codes) → 0.2 request/decision/bundle. `needs_approval` returns `approval_handle` as success. Proposal commit MUST NOT mint a pass. `lifecycle_event` is content-free beside receipts. `claim_annotation` rides beside claims until a 0.3 core revision. + +## Non-goals + +No Egoist/Switchboard adapter. No Grok Bot adapter. No PCP grants. No Legatus envelope. No live issuer. No ouro landing. No wildcards for categories, purpose codes, or `client_instance`. No un-disclosure of issued bundles. + +## Required tests (pack must publish results; schema-only is insufficient) + +1. Reject vault disclosure when only `identity_assertion` is present. +2. Unpaired `client_instance`: `deny` or `needs_approval` without claim values. +3. `purpose_code` absent from pass: reject. +4. Off-pass category: deny; denied claim text absent from handle and bundle. +5. Later on-pass read still requires a new `context_request` and `policy_decision`. +6. Proposal commit does not create or widen a `context_pass`. +7. Revoked pass cannot obtain a later bundle. +8. `lifecycle_event` serializes `payload_included` false with no claim text. +9. `inferred` is not emitted as `stated_by_user`. +10. Visibility `vault` is absent from public-profile export. + +Board: CLOSED. Next job for Context Layer is assigned separately. diff --git a/protocol/companions/0.3-draft/README.md b/protocol/companions/0.3-draft/README.md new file mode 100644 index 0000000..2355409 --- /dev/null +++ b/protocol/companions/0.3-draft/README.md @@ -0,0 +1,88 @@ +# Context Layer primitives addendum + +Companion objects for `context-layer/0.3-draft`. A `context-layer/0.2-draft` deployment MAY negotiate the `CL-Pass` profile without opening the five CL-Core-Lite schemas. + +Status: working draft. Not an adopted standard. + +## What this is + +Native Context Layer objects for: + +- identity that is not a vault grant +- exact client pairing +- a standing category pass (necessary, not sufficient) +- closed memory categories above predicate selectors +- ask-without-read (`needs_approval` as success, plus `approval_handle`) +- write-commit that MUST NOT mint a read pass +- content-free lifecycle events +- claim evidence, visibility, category, and attribution (companion envelope; 0.3 field proposals) + +This directory is spec, schemas, and examples. It is not runtime code. + +## What this is not + +- Not a patch to `context_request`, `policy_decision`, `scoped_context_bundle`, `memory_update_proposal`, or `receipt`. Those Lite schemas stay closed (`additionalProperties: false`). +- Not a restatement of 0.2-draft: purpose-bound requests, four-state policy, recipient-bound single-use bundles, proposal-only writeback, receipts, requester / recipient / `client_instance`, `onward_disclosure`, or selectors as `{ "predicate" }`. Those already exist. This addendum only adds what they do not cover. +- Not an Egoist AI Passport or Switchboard adapter, subset, client, or type import. + +## Observed origin + +Standing category grants, identity-without-memory, exact client pairing, ask as normal output, write-approval-is-not-read, and content-free lifecycle were observed in Egoist AI Passport / Switchboard. They are rewritten here as Context Layer objects. That system's types, tool names, authorization-scope strings, and packages are not imported. See [crosswalk.md](crosswalk.md). + +## How it composes with 0.2-draft + +```text +identity_assertion # not a context grant +client_pairing # exact client_instance; not a pass + | + v +context_pass # categories + purpose codes; necessary, not sufficient + | + v +context_request # 0.2; selectors remain predicates + | + v +policy_decision # 0.2 four-state; unchanged schema + | + +-- needs_approval --> approval_handle # success, not an error + | + +-- allow / allow_with_reductions --> scoped_context_bundle # 0.2 + | + v +receipt # 0.2 +optional memory_update_proposal + | + v +commit MUST NOT mint or widen a context_pass +lifecycle_event # content-free sync log beside receipts +claim_annotation # rides beside claims until 0.3 +``` + +A consumer that holds only `identity_assertion` MUST NOT be issued a bundle and MUST NOT be treated as authorized to request vault disclosure. + +`CL-Pass` evaluation uses existing 0.2 `reason_codes` (for example `PASS_MISSING`, `CATEGORY_NOT_ON_PASS`, `PAIRING_REQUIRED`). It does not add fields to Lite objects. + +## Files + +| Path | Role | +| --- | --- | +| [spec.md](spec.md) | Normative addendum: invariants, objects, lifecycles, 0.3-draft note, non-goals | +| [crosswalk.md](crosswalk.md) | Observed phrase → CL primitive. Not their protocol. | +| [schemas/](schemas/) | Closed JSON Schema 2020-12 companions | +| [examples/](examples/) | Synthetic objects valid against those schemas | + +## Companion schemas + +Required by this addendum: + +- `schemas/context-pass.schema.json` +- `schemas/client-pairing.schema.json` +- `schemas/approval-handle.schema.json` +- `schemas/lifecycle-event.schema.json` + +Also in this directory, because they are first-class companion objects: + +- `schemas/identity-assertion.schema.json` +- `schemas/claim-annotation.schema.json` + +All use `spec_version` `context-layer/0.3-draft` and `additionalProperties: false`. diff --git a/protocol/companions/0.3-draft/crosswalk.md b/protocol/companions/0.3-draft/crosswalk.md new file mode 100644 index 0000000..012c2fb --- /dev/null +++ b/protocol/companions/0.3-draft/crosswalk.md @@ -0,0 +1,26 @@ +# Observed phrase → Context Layer primitive + +This table records where a behavior was observed, then names the CL object that encodes it. Observation is not adoption. + +This addendum does **not** implement Egoist AI Passport, Switchboard, or any protocol from that system. It does not import their types, tool names, authorization-scope strings, or packages. A CL deployment that speaks these objects is not speaking that protocol. + +| Observed phrase (Egoist / Switchboard) | CL primitive | What is lifted | What is not imported | +| --- | --- | --- | --- | +| Sign-in consent and memory consent are two consents | `identity_assertion` with `context_grant: false` | Authenticating a principal MUST NOT disclose vault claims. A consumer that only has identity MUST NOT call the vault. | Authorization-scope names, identity-provider token shapes, client metadata documents | +| Category pass: one app, one category, one duration | `context_pass` | Standing grant of `memory_category` values to one `principal` + `client_instance` until `expires_at` or revoke. Necessary, not sufficient. | Pass type names, duration defaults, app-id formats from that system | +| Preference, fact, project, instruction | `memory_category` enum | Closed grant layer above selectors. A pass grants categories. A request still names `{ "predicate" }` selectors. | Their category type names as imported types; predicates stay 0.2 selectors | +| Recall without a pass returns an approval link as normal output, not an error | `policy_decision.decision = needs_approval` (already 0.2) plus companion `approval_handle` | Ask is not read. `needs_approval` is a successful protocol outcome. Handle carries `pass_gap` and optional `user_visible_url`. MUST NOT include denied claim values. | Their approval URL format, tool names, or error-vs-result encoding | +| Approval does not grant read access | Invariant on `memory_update_proposal` commit | Committing a proposal MUST NOT mint or widen a `context_pass`. Read still requires an active pass and a new `context_request`. | Their write-approval records or store-tool semantics | +| Pair exact clients before grants | `client_pairing` | Exact `client_instance` admission. Unpaired clients MUST be `deny` or `needs_approval`. Pairing is not a pass. | Their client registry, metadata URL rules, or admission paths | +| Content-free lifecycle events, separate from deletable content | `lifecycle_event` | Syncable public-of-the-vault log: operation, refs, timestamps. NO claim text. NO payloads. Receipts remain 0.2 evidence. | Their sync wire format or event type names as imported enums | +| Evidence and visibility on stored items | `claim_annotation`; 0.3 field proposals on `context_claim` | `evidence_basis`, `visibility`, `category`, `attribution`. Public profile MUST NOT include vault-only claims. `inferred` MUST NOT be disclosed as `stated_by_user`. | Their item schemas, visibility flags, or inference labels as imported fields | + +## How to read this + +Left column: informal description of a behavior that existed elsewhere. + +Middle: the CL object or invariant. New work is companion objects plus a 0.3-draft note. The five CL-Core-Lite schemas are not extended. + +Right: reminder that a crosswalk is not a mapping of on-the-wire types. + +If a deployment needs to interoperate with that other system, it MUST do so through an adapter that preserves CL invariants at the vault boundary. That adapter is out of scope here. diff --git a/protocol/companions/0.3-draft/examples/approval-handle.json b/protocol/companions/0.3-draft/examples/approval-handle.json new file mode 100644 index 0000000..9a08213 --- /dev/null +++ b/protocol/companions/0.3-draft/examples/approval-handle.json @@ -0,0 +1,18 @@ +{ + "spec_version": "context-layer/0.3-draft", + "type": "approval_handle", + "id": "urn:cl:approval:ah_4401", + "created_at": "2026-08-28T18:10:00Z", + "issuer": { + "id": "urn:cl:approval-surface:local" + }, + "request_ref": "urn:cl:request:req_880", + "decision_ref": "urn:cl:decision:dec_880", + "pass_gap": { + "missing_categories": [ + "instruction" + ] + }, + "user_visible_url": "https://vault.example/approve/ah_4401", + "expires_at": "2026-08-28T18:40:00Z" +} diff --git a/protocol/companions/0.3-draft/examples/claim-annotation.json b/protocol/companions/0.3-draft/examples/claim-annotation.json new file mode 100644 index 0000000..312da4b --- /dev/null +++ b/protocol/companions/0.3-draft/examples/claim-annotation.json @@ -0,0 +1,17 @@ +{ + "spec_version": "context-layer/0.3-draft", + "type": "claim_annotation", + "id": "urn:cl:annotation:ann_4401", + "created_at": "2026-08-28T17:55:00Z", + "issuer": { + "id": "urn:cl:annotator:local" + }, + "claim_ref": "urn:cl:claim:pref-quiet-hours", + "evidence_basis": "direct_user_save", + "visibility": "vault", + "category": "preference", + "attribution": { + "via_principal": "urn:cl:principal:subject-primary", + "captured_at": "2026-08-28T17:54:50Z" + } +} diff --git a/protocol/companions/0.3-draft/examples/client-pairing.json b/protocol/companions/0.3-draft/examples/client-pairing.json new file mode 100644 index 0000000..fb94018 --- /dev/null +++ b/protocol/companions/0.3-draft/examples/client-pairing.json @@ -0,0 +1,14 @@ +{ + "spec_version": "context-layer/0.3-draft", + "type": "client_pairing", + "id": "urn:cl:pairing:pair_4401", + "created_at": "2026-08-28T18:02:00Z", + "issuer": { + "id": "urn:cl:pairing:local" + }, + "subject_ref": "vault://subjects/primary", + "client_instance": "urn:device:local-workstation", + "display_name": "local workstation notes", + "paired_at": "2026-08-28T18:02:00Z", + "status": "paired" +} diff --git a/protocol/companions/0.3-draft/examples/context-pass.json b/protocol/companions/0.3-draft/examples/context-pass.json new file mode 100644 index 0000000..f18c904 --- /dev/null +++ b/protocol/companions/0.3-draft/examples/context-pass.json @@ -0,0 +1,24 @@ +{ + "spec_version": "context-layer/0.3-draft", + "type": "context_pass", + "id": "urn:cl:pass:pass_4401", + "created_at": "2026-08-28T18:05:00Z", + "issuer": { + "id": "urn:cl:pass-issuer:local" + }, + "subject_ref": "vault://subjects/primary", + "principal": "urn:app:notes", + "client_instance": "urn:device:local-workstation", + "pairing_ref": "urn:cl:pairing:pair_4401", + "categories": [ + "preference", + "fact" + ], + "allowed_purpose_codes": [ + "retrieve.context", + "draft.response" + ], + "expires_at": "2026-09-04T18:05:00Z", + "revocable": true, + "status": "active" +} diff --git a/protocol/companions/0.3-draft/examples/identity-assertion.json b/protocol/companions/0.3-draft/examples/identity-assertion.json new file mode 100644 index 0000000..8ca8195 --- /dev/null +++ b/protocol/companions/0.3-draft/examples/identity-assertion.json @@ -0,0 +1,17 @@ +{ + "spec_version": "context-layer/0.3-draft", + "type": "identity_assertion", + "id": "urn:cl:identity:id_4401", + "created_at": "2026-08-28T18:00:00Z", + "issuer": { + "id": "urn:cl:identity-issuer:local" + }, + "subject_ref": "vault://subjects/primary", + "principal": "urn:cl:principal:subject-primary", + "client_instance": "urn:device:local-workstation", + "authenticated_by": "deployment_session", + "authenticated_at": "2026-08-28T18:00:00Z", + "audience": "urn:app:notes", + "expires_at": "2026-08-28T20:00:00Z", + "context_grant": false +} diff --git a/protocol/companions/0.3-draft/examples/lifecycle-event.json b/protocol/companions/0.3-draft/examples/lifecycle-event.json new file mode 100644 index 0000000..723d1c5 --- /dev/null +++ b/protocol/companions/0.3-draft/examples/lifecycle-event.json @@ -0,0 +1,17 @@ +{ + "spec_version": "context-layer/0.3-draft", + "type": "lifecycle_event", + "id": "urn:cl:lifecycle:le_4401", + "created_at": "2026-08-28T18:05:01Z", + "issuer": { + "id": "urn:cl:lifecycle:local" + }, + "subject_ref": "vault://subjects/primary", + "operation": "pass.issued", + "occurred_at": "2026-08-28T18:05:00Z", + "refs": { + "pass_ref": "urn:cl:pass:pass_4401", + "pairing_ref": "urn:cl:pairing:pair_4401" + }, + "payload_included": false +} diff --git a/protocol/companions/0.3-draft/schemas/approval-handle.schema.json b/protocol/companions/0.3-draft/schemas/approval-handle.schema.json new file mode 100644 index 0000000..42a3aaa --- /dev/null +++ b/protocol/companions/0.3-draft/schemas/approval-handle.schema.json @@ -0,0 +1,97 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://sierracatalina.com/context-layer/primitives/approval-handle.schema.json", + "title": "approval handle", + "description": "Companion to a policy_decision of needs_approval. Successful protocol output, not an error. MUST NOT carry claim values or denied vault content.", + "type": "object", + "additionalProperties": false, + "required": [ + "spec_version", + "type", + "id", + "created_at", + "issuer", + "request_ref", + "pass_gap", + "expires_at" + ], + "properties": { + "spec_version": { + "const": "context-layer/0.3-draft" + }, + "type": { + "const": "approval_handle" + }, + "id": { + "type": "string", + "pattern": "^urn:cl:approval:[A-Za-z0-9._~-]+$" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "issuer": { + "$ref": "#/$defs/issuer" + }, + "request_ref": { + "type": "string", + "pattern": "^urn:cl:request:[A-Za-z0-9._~-]+$" + }, + "decision_ref": { + "type": "string", + "pattern": "^urn:cl:decision:[A-Za-z0-9._~-]+$" + }, + "pass_gap": { + "type": "object", + "additionalProperties": false, + "required": [ + "missing_categories" + ], + "properties": { + "missing_categories": { + "type": "array", + "minItems": 1, + "maxItems": 4, + "uniqueItems": true, + "items": { + "$ref": "#/$defs/memory_category" + } + } + } + }, + "user_visible_url": { + "type": "string", + "minLength": 8, + "maxLength": 2048, + "pattern": "^https://" + }, + "expires_at": { + "type": "string", + "format": "date-time" + } + }, + "$defs": { + "issuer": { + "type": "object", + "additionalProperties": false, + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "minLength": 3, + "maxLength": 512 + } + } + }, + "memory_category": { + "enum": [ + "preference", + "fact", + "project", + "instruction" + ] + } + } +} diff --git a/protocol/companions/0.3-draft/schemas/claim-annotation.schema.json b/protocol/companions/0.3-draft/schemas/claim-annotation.schema.json new file mode 100644 index 0000000..1a5b198 --- /dev/null +++ b/protocol/companions/0.3-draft/schemas/claim-annotation.schema.json @@ -0,0 +1,103 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://sierracatalina.com/context-layer/primitives/claim-annotation.schema.json", + "title": "claim annotation", + "description": "Companion envelope for evidence basis, visibility, memory category, and attribution. Not a patch to closed 0.2 Lite objects. Proposed native fields for context_claim in 0.3.", + "type": "object", + "additionalProperties": false, + "required": [ + "spec_version", + "type", + "id", + "created_at", + "issuer", + "claim_ref", + "evidence_basis", + "visibility", + "category", + "attribution" + ], + "properties": { + "spec_version": { + "const": "context-layer/0.3-draft" + }, + "type": { + "const": "claim_annotation" + }, + "id": { + "type": "string", + "pattern": "^urn:cl:annotation:[A-Za-z0-9._~-]+$" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "issuer": { + "$ref": "#/$defs/issuer" + }, + "claim_ref": { + "type": "string", + "pattern": "^urn:cl:claim:[A-Za-z0-9._~-]+$" + }, + "evidence_basis": { + "enum": [ + "direct_user_save", + "stated_by_user", + "derived", + "inferred" + ] + }, + "visibility": { + "enum": [ + "vault", + "public_profile" + ] + }, + "category": { + "$ref": "#/$defs/memory_category" + }, + "attribution": { + "type": "object", + "additionalProperties": false, + "required": [ + "via_principal", + "captured_at" + ], + "properties": { + "via_principal": { + "type": "string", + "minLength": 3, + "maxLength": 512 + }, + "captured_at": { + "type": "string", + "format": "date-time" + } + } + } + }, + "$defs": { + "issuer": { + "type": "object", + "additionalProperties": false, + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "minLength": 3, + "maxLength": 512 + } + } + }, + "memory_category": { + "enum": [ + "preference", + "fact", + "project", + "instruction" + ] + } + } +} diff --git a/protocol/companions/0.3-draft/schemas/client-pairing.schema.json b/protocol/companions/0.3-draft/schemas/client-pairing.schema.json new file mode 100644 index 0000000..3738a32 --- /dev/null +++ b/protocol/companions/0.3-draft/schemas/client-pairing.schema.json @@ -0,0 +1,103 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://sierracatalina.com/context-layer/primitives/client-pairing.schema.json", + "title": "client pairing", + "description": "Exact client_instance admission for a subject. Pairing is not a context_pass and not a context grant.", + "type": "object", + "additionalProperties": false, + "required": [ + "spec_version", + "type", + "id", + "created_at", + "issuer", + "subject_ref", + "client_instance", + "display_name", + "paired_at", + "status" + ], + "properties": { + "spec_version": { + "const": "context-layer/0.3-draft" + }, + "type": { + "const": "client_pairing" + }, + "id": { + "type": "string", + "pattern": "^urn:cl:pairing:[A-Za-z0-9._~-]+$" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "issuer": { + "$ref": "#/$defs/issuer" + }, + "subject_ref": { + "type": "string", + "minLength": 3, + "maxLength": 512 + }, + "client_instance": { + "type": "string", + "minLength": 3, + "maxLength": 512 + }, + "display_name": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "paired_at": { + "type": "string", + "format": "date-time" + }, + "status": { + "enum": [ + "paired", + "revoked" + ] + }, + "revoked_at": { + "type": "string", + "format": "date-time" + } + }, + "allOf": [ + { + "if": { + "properties": { + "status": { + "const": "revoked" + } + }, + "required": [ + "status" + ] + }, + "then": { + "required": [ + "revoked_at" + ] + } + } + ], + "$defs": { + "issuer": { + "type": "object", + "additionalProperties": false, + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "minLength": 3, + "maxLength": 512 + } + } + } + } +} diff --git a/protocol/companions/0.3-draft/schemas/context-pass.schema.json b/protocol/companions/0.3-draft/schemas/context-pass.schema.json new file mode 100644 index 0000000..6e42288 --- /dev/null +++ b/protocol/companions/0.3-draft/schemas/context-pass.schema.json @@ -0,0 +1,159 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://sierracatalina.com/context-layer/primitives/context-pass.schema.json", + "title": "context pass", + "description": "Standing category grant for one principal and one client instance. Necessary, not sufficient, for disclosure. Companion to context-layer/0.2-draft; does not open the five CL-Core-Lite schemas.", + "type": "object", + "additionalProperties": false, + "required": [ + "spec_version", + "type", + "id", + "created_at", + "issuer", + "subject_ref", + "principal", + "client_instance", + "categories", + "allowed_purpose_codes", + "expires_at", + "revocable", + "status" + ], + "properties": { + "spec_version": { + "const": "context-layer/0.3-draft" + }, + "type": { + "const": "context_pass" + }, + "id": { + "type": "string", + "pattern": "^urn:cl:pass:[A-Za-z0-9._~-]+$" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "issuer": { + "$ref": "#/$defs/issuer" + }, + "subject_ref": { + "type": "string", + "minLength": 3, + "maxLength": 512 + }, + "principal": { + "type": "string", + "minLength": 3, + "maxLength": 512 + }, + "client_instance": { + "type": "string", + "minLength": 3, + "maxLength": 512 + }, + "pairing_ref": { + "type": "string", + "pattern": "^urn:cl:pairing:[A-Za-z0-9._~-]+$" + }, + "categories": { + "type": "array", + "minItems": 1, + "maxItems": 4, + "uniqueItems": true, + "items": { + "$ref": "#/$defs/memory_category" + } + }, + "allowed_purpose_codes": { + "type": "array", + "minItems": 1, + "maxItems": 32, + "uniqueItems": true, + "items": { + "$ref": "#/$defs/purpose_code" + } + }, + "expires_at": { + "type": "string", + "format": "date-time" + }, + "revocable": { + "type": "boolean" + }, + "status": { + "enum": [ + "active", + "revoked", + "expired" + ] + }, + "revoked_at": { + "type": "string", + "format": "date-time" + } + }, + "allOf": [ + { + "if": { + "properties": { + "status": { + "const": "revoked" + } + }, + "required": [ + "status" + ] + }, + "then": { + "required": [ + "revoked_at" + ] + } + } + ], + "$defs": { + "issuer": { + "type": "object", + "additionalProperties": false, + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "minLength": 3, + "maxLength": 512 + } + } + }, + "memory_category": { + "enum": [ + "preference", + "fact", + "project", + "instruction" + ] + }, + "purpose_code": { + "anyOf": [ + { + "enum": [ + "draft.response", + "summarize.material", + "retrieve.context", + "plan.task", + "execute.approved_action", + "discover.minimum_reveal", + "propose.memory_update" + ] + }, + { + "type": "string", + "pattern": "^x\\.[a-z0-9]+(?:[._-][a-z0-9]+)*(?:\\.[a-z0-9]+(?:[._-][a-z0-9]+)*)+$" + } + ] + } + } +} diff --git a/protocol/companions/0.3-draft/schemas/identity-assertion.schema.json b/protocol/companions/0.3-draft/schemas/identity-assertion.schema.json new file mode 100644 index 0000000..64c5286 --- /dev/null +++ b/protocol/companions/0.3-draft/schemas/identity-assertion.schema.json @@ -0,0 +1,93 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://sierracatalina.com/context-layer/primitives/identity-assertion.schema.json", + "title": "identity assertion", + "description": "Authentication of a principal. Not a context grant. MUST NOT carry vault claims, selectors, or bundle material.", + "type": "object", + "additionalProperties": false, + "required": [ + "spec_version", + "type", + "id", + "created_at", + "issuer", + "subject_ref", + "principal", + "client_instance", + "authenticated_by", + "authenticated_at", + "expires_at", + "context_grant" + ], + "properties": { + "spec_version": { + "const": "context-layer/0.3-draft" + }, + "type": { + "const": "identity_assertion" + }, + "id": { + "type": "string", + "pattern": "^urn:cl:identity:[A-Za-z0-9._~-]+$" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "issuer": { + "$ref": "#/$defs/issuer" + }, + "subject_ref": { + "type": "string", + "minLength": 3, + "maxLength": 512 + }, + "principal": { + "type": "string", + "minLength": 3, + "maxLength": 512 + }, + "client_instance": { + "type": "string", + "minLength": 3, + "maxLength": 512 + }, + "authenticated_by": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "authenticated_at": { + "type": "string", + "format": "date-time" + }, + "audience": { + "type": "string", + "minLength": 3, + "maxLength": 512 + }, + "expires_at": { + "type": "string", + "format": "date-time" + }, + "context_grant": { + "const": false + } + }, + "$defs": { + "issuer": { + "type": "object", + "additionalProperties": false, + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "minLength": 3, + "maxLength": 512 + } + } + } + } +} diff --git a/protocol/companions/0.3-draft/schemas/lifecycle-event.schema.json b/protocol/companions/0.3-draft/schemas/lifecycle-event.schema.json new file mode 100644 index 0000000..7fd57a3 --- /dev/null +++ b/protocol/companions/0.3-draft/schemas/lifecycle-event.schema.json @@ -0,0 +1,200 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://sierracatalina.com/context-layer/primitives/lifecycle-event.schema.json", + "title": "lifecycle event", + "description": "Content-free vault lifecycle record for sync. MUST NOT include claim text, selector values, or payloads. Distinct from a 0.2 receipt.", + "type": "object", + "additionalProperties": false, + "required": [ + "spec_version", + "type", + "id", + "created_at", + "issuer", + "subject_ref", + "operation", + "occurred_at", + "refs", + "payload_included" + ], + "properties": { + "spec_version": { + "const": "context-layer/0.3-draft" + }, + "type": { + "const": "lifecycle_event" + }, + "id": { + "type": "string", + "pattern": "^urn:cl:lifecycle:[A-Za-z0-9._~-]+$" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "issuer": { + "$ref": "#/$defs/issuer" + }, + "subject_ref": { + "type": "string", + "minLength": 3, + "maxLength": 512 + }, + "operation": { + "enum": [ + "pass.issued", + "pass.revoked", + "pairing.revoked", + "proposal.committed", + "bundle.issued", + "bundle.expired" + ] + }, + "occurred_at": { + "type": "string", + "format": "date-time" + }, + "refs": { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "pass_ref": { + "type": "string", + "pattern": "^urn:cl:pass:[A-Za-z0-9._~-]+$" + }, + "pairing_ref": { + "type": "string", + "pattern": "^urn:cl:pairing:[A-Za-z0-9._~-]+$" + }, + "proposal_ref": { + "type": "string", + "pattern": "^urn:cl:proposal:[A-Za-z0-9._~-]+$" + }, + "bundle_ref": { + "type": "string", + "pattern": "^urn:cl:bundle:[A-Za-z0-9._~-]+$" + }, + "request_ref": { + "type": "string", + "pattern": "^urn:cl:request:[A-Za-z0-9._~-]+$" + }, + "decision_ref": { + "type": "string", + "pattern": "^urn:cl:decision:[A-Za-z0-9._~-]+$" + } + } + }, + "payload_included": { + "const": false + } + }, + "allOf": [ + { + "if": { + "properties": { + "operation": { + "enum": [ + "pass.issued", + "pass.revoked" + ] + } + }, + "required": [ + "operation" + ] + }, + "then": { + "properties": { + "refs": { + "required": [ + "pass_ref" + ] + } + } + } + }, + { + "if": { + "properties": { + "operation": { + "const": "pairing.revoked" + } + }, + "required": [ + "operation" + ] + }, + "then": { + "properties": { + "refs": { + "required": [ + "pairing_ref" + ] + } + } + } + }, + { + "if": { + "properties": { + "operation": { + "const": "proposal.committed" + } + }, + "required": [ + "operation" + ] + }, + "then": { + "properties": { + "refs": { + "required": [ + "proposal_ref" + ] + } + } + } + }, + { + "if": { + "properties": { + "operation": { + "enum": [ + "bundle.issued", + "bundle.expired" + ] + } + }, + "required": [ + "operation" + ] + }, + "then": { + "properties": { + "refs": { + "required": [ + "bundle_ref" + ] + } + } + } + } + ], + "$defs": { + "issuer": { + "type": "object", + "additionalProperties": false, + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "minLength": 3, + "maxLength": 512 + } + } + } + } +} diff --git a/protocol/companions/0.3-draft/spec.md b/protocol/companions/0.3-draft/spec.md new file mode 100644 index 0000000..01d2ecc --- /dev/null +++ b/protocol/companions/0.3-draft/spec.md @@ -0,0 +1,143 @@ +# Context Layer primitives addendum + +Normative companion addendum for `context-layer/0.3-draft` (CL-Pass). A `context-layer/0.2-draft` deployment MAY negotiate this profile without opening the five CL-Core-Lite schemas. + +Status: working draft. Not an adopted standard. + +Closed Drive record: [CLOSED Context Layer 0.3-draft companions (CL-Pass) — 2026-08-29](https://docs.google.com/document/d/19ZNUrP3zCxRxbXvQ-0EBV9MKuMcJbkKXLKp58MTHtUA/edit). Landed copy: [DRIVE-PAGE.md](DRIVE-PAGE.md). + +## 0.3-draft note + +This addendum defines companion objects beside Lite. It is not a restatement of 0.2-draft and it is not a patch to Lite. + +The five CL-Core-Lite objects stay closed (`additionalProperties: false`): + +- `context_request` +- `policy_decision` +- `scoped_context_bundle` +- `memory_update_proposal` +- `receipt` + +`CL-Pass` evaluation uses existing 0.2 `policy_decision.reason_codes`. It does not add fields to Lite objects. Example codes: `IDENTITY_ONLY`, `PAIRING_REQUIRED`, `PURPOSE_NOT_ON_PASS`, `CATEGORY_NOT_ON_PASS`, `PASS_REVOKED`, `PASS_MISSING`. + +All companion objects use `spec_version` `context-layer/0.3-draft` and `additionalProperties: false`. + +## Invariants + +1. Identity is not a context grant. `identity_assertion.context_grant` MUST be `false`. Authenticating a principal MUST NOT disclose vault claims. +2. Identity-only consumers MUST NOT be treated as authorized to submit a disclosing `context_request` and MUST NOT be issued a `scoped_context_bundle`. +3. Pairing is not a pass. `client_pairing` admits an exact `client_instance` only. +4. Unpaired clients MUST get `deny` or `needs_approval`. +5. A pass is necessary, not sufficient. Every disclosure still requires 0.2 `context_request` → `policy_decision` → `scoped_context_bundle`. An active `context_pass` is not a bundle, wildcard selector, or ambient vault access. +6. Categories grant; predicates select. A pass grants `memory_category` values. A request still names `{ "predicate" }` selectors. An off-pass category MUST be denied or `needs_approval` for the exact request. +7. Ask is not read. `needs_approval` is a successful protocol outcome. `approval_handle` MUST NOT include denied claim values, claim text, or vault payloads. +8. Write approval is not a read pass. Committing a `memory_update_proposal` MUST NOT mint or widen a `context_pass`. +9. Revocation is prospective. Revoking a pass or pairing MUST prevent future bundles. It cannot un-disclose issued bundles. +10. Lifecycle events carry no content. `payload_included` MUST be `false`. +11. Evidence labels MUST NOT be upgraded. `inferred` MUST NOT be disclosed as `stated_by_user` or `direct_user_save`. +12. Public profile is not the vault. Visibility `vault` MUST NOT appear on a public profile. + +## Closed enum: `memory_category` + +Grant layer above selectors. Closed values: + +`preference` | `fact` | `project` | `instruction` + +There is no standalone schema file. The enum is defined inside the companion schemas that use it. No wildcards. + +## Companion objects + +Schemas live in [schemas/](schemas/). Synthetic examples live in [examples/](examples/). + +### `identity_assertion` + +Authentication of a principal. Not a context grant. MUST NOT carry vault claims, selectors, or bundle material. + +`context_grant` is `const false`. Schema: [schemas/identity-assertion.schema.json](schemas/identity-assertion.schema.json). + +### `client_pairing` + +Exact `client_instance` admission for a subject. Pairing is not a `context_pass` and not a context grant. + +`status` is `paired` or `revoked`. `revoked` requires `revoked_at`. Schema: [schemas/client-pairing.schema.json](schemas/client-pairing.schema.json). + +### `context_pass` + +Standing category grant for one principal and one client instance. Necessary, not sufficient, for disclosure. + +`categories` are `memory_category` values. `allowed_purpose_codes` are the 0.2 registered codes plus the 0.2 experimental `x.` pattern. Prefix match MUST NOT satisfy a purpose check. + +`status` is `active`, `revoked`, or `expired`. `revoked` requires `revoked_at`. Schema: [schemas/context-pass.schema.json](schemas/context-pass.schema.json). + +### `approval_handle` + +Companion to a `policy_decision` of `needs_approval`. Successful protocol output, not an error. MUST NOT carry claim values or denied vault content. + +`pass_gap.missing_categories` names the categories that blocked the request. Optional `user_visible_url` is `https` only. Schema: [schemas/approval-handle.schema.json](schemas/approval-handle.schema.json). + +### `lifecycle_event` + +Content-free vault lifecycle record for sync. MUST NOT include claim text, selector values, or payloads. Distinct from a 0.2 receipt. + +`payload_included` is `const false`. `operation` stays exactly: + +`pass.issued` | `pass.revoked` | `pairing.revoked` | `proposal.committed` | `bundle.issued` | `bundle.expired` + +`refs` may contain only `pass_ref`, `pairing_ref`, `proposal_ref`, `bundle_ref`, `request_ref`, and `decision_ref`. Required refs depend on `operation`. Schema: [schemas/lifecycle-event.schema.json](schemas/lifecycle-event.schema.json). + +### `claim_annotation` + +Companion envelope for evidence basis, visibility, memory category, and attribution. Not a patch to closed 0.2 Lite objects. Proposed native fields for `context_claim` in a later 0.3 core revision. + +`evidence_basis`: `direct_user_save` | `stated_by_user` | `derived` | `inferred` + +`visibility`: `vault` | `public_profile` + +Schema: [schemas/claim-annotation.schema.json](schemas/claim-annotation.schema.json). + +## Lifecycle + +```text +identity_assertion # not a context grant +client_pairing # exact client_instance; not a pass + | + v +context_pass # categories + purpose codes; necessary, not sufficient + | + v +context_request # 0.2; selectors remain predicates + | + v +policy_decision # 0.2 four-state; unchanged schema + | + +-- needs_approval --> approval_handle # success, not an error + | + +-- allow / allow_with_reductions --> scoped_context_bundle # 0.2 + | + v +receipt # 0.2 +optional memory_update_proposal + | + v +commit MUST NOT mint or widen a context_pass +lifecycle_event # content-free sync log beside receipts +claim_annotation # rides beside claims until 0.3 +``` + +A consumer that holds only `identity_assertion` MUST NOT be issued a bundle and MUST NOT be treated as authorized to request vault disclosure. + +## Required tests + +Schema-valid JSON is not a pass. A CL-Pass claim MUST publish results for T01–T10. Oracles: [../../../test-vectors/cl-pass/VECTORS.md](../../../test-vectors/cl-pass/VECTORS.md). + +## Non-goals + +- Not an Egoist AI Passport or Switchboard adapter, subset, client, or type import. Observation is recorded in [crosswalk.md](crosswalk.md); that is not adoption. +- No Grok Bot adapter +- No PCP grants +- No Legatus envelope +- No live issuer +- No ouro / Ouroboros landing +- No wildcards for categories, purpose codes, or `client_instance` +- No un-disclosure of issued bundles +- No opening of the five Lite schemas diff --git a/test-vectors/cl-pass/VECTORS.md b/test-vectors/cl-pass/VECTORS.md new file mode 100644 index 0000000..324db79 --- /dev/null +++ b/test-vectors/cl-pass/VECTORS.md @@ -0,0 +1,207 @@ +# Context Layer — CL-Pass required-test vectors + +status: working draft · not an adopted standard +profile: CL-Pass +spec: context-layer/0.3-draft companion addendum +relates to: context-layer/0.2-draft CL-Core-Lite (CLOSED) +published: 2026-08-29 +close record: https://docs.google.com/document/d/19ZNUrP3zCxRxbXvQ-0EBV9MKuMcJbkKXLKp58MTHtUA/edit +canonical Drive vectors: https://docs.google.com/document/d/1NGbs7kSk__BtxwkjP-BhMKe_5A99phNVCFA3ICj7nw8/edit + +0.2 Lite schemas stay closed. These vectors do not add fields to `context_request`, `policy_decision`, `scoped_context_bundle`, `memory_update_proposal`, or `receipt`. Schema-valid JSON is not a pass. Each test names an oracle that must fail if the invariant is broken even when every object validates. + +No PCP grants. No Legatus. No live issuer. No ouro. + +## How to run + +A CL-Pass claim MUST publish results for T01 through T10. For each test: load Given objects; apply When; compare Expected members only; evaluate Oracle; FAIL if any forbidden string appears; record pass or fail plus the first failing check. A harness that only validates JSON MUST report the Fail-if counterexamples as fail. + +## Fixture world (synthetic) + +- `subject_ref`: `vault://subjects/primary` +- notes principal: `urn:app:notes` +- paired client: `urn:device:local-workstation` +- unpaired client: `urn:device:unpaired-phone` +- identity: `urn:cl:identity:id_4401` (`context_grant` false) +- pairing: `urn:cl:pairing:pair_4401` (status `paired`) +- pass: `urn:cl:pass:pass_4401` categories `preference`, `fact`; purposes `retrieve.context`, `draft.response`; status `active`; `expires_at` `2026-09-04T18:05:00Z` +- `eval_at`: `2026-08-29T13:00:00Z` + +Vault claims (appear only when an oracle allows them): + +- `urn:cl:claim:pref-quiet-hours` | preference | vault | `direct_user_save` | quiet hours 21:00-07:00 +- `urn:cl:claim:fact-timezone` | fact | public_profile | `stated_by_user` | America/New_York +- `urn:cl:claim:instr-always-cite` | instruction | vault | `direct_user_save` | always cite sources +- `urn:cl:claim:inferred-color` | preference | vault | `inferred` | favorite color is teal + +Forbidden-on-fail-path strings (scan every returned object, including URL query strings): + +- `quiet hours 21:00-07:00` +- `always cite sources` +- `favorite color is teal` +- `America/New_York` (allowed only on T05 allow-path bundle and T10 public-profile export) + +## T01 — identity is not a vault grant + +Invariant. Authenticating a principal MUST NOT disclose vault claims. A consumer that only has `identity_assertion` MUST NOT be issued a bundle. + +Given: `identity_assertion` `id_4401` with `context_grant` false; no `client_pairing`; no `context_pass`. + +When: consumer holding only `id_4401` submits 0.2 `context_request` `urn:cl:request:t01` with `requester.principal` `urn:app:notes`, `requester.client_instance` `urn:device:local-workstation`, `purpose_code` `retrieve.context`, selectors `[{predicate: preference.quiet_hours}]`. + +Expected: `policy_decision.decision` `deny`; `reason_codes` includes `IDENTITY_ONLY`; no `scoped_context_bundle`; no `approval_handle` that carries claim text. + +Oracle: `context_grant === false`; zero objects type `scoped_context_bundle`; none of the forbidden strings appear; `identity_assertion` has no selectors, categories, claims, or `bundle_ref`. + +Fail if: identity object validates and a bundle is issued; decision is `allow` or `allow_with_reductions`; claim text is copied onto the identity object or a receipt `user_summary`. + +## T02 — unpaired client: ask is not read + +Invariant. Unpaired `client_instance` MUST be `deny` or `needs_approval`. `approval_handle` MUST NOT include denied claim values. + +Given: identity `id_4401`; pairing `pair_4401` for local-workstation only; no pairing for `urn:device:unpaired-phone`; `pass_4401` does not bind the unpaired device. + +When: `context_request` `urn:cl:request:t02` with `requester.client_instance` `urn:device:unpaired-phone`, selector `preference.quiet_hours`, `purpose_code` `retrieve.context`. + +Expected branch A: decision `deny`; `reason_codes` includes `PAIRING_REQUIRED`; no bundle. + +Expected branch B: decision `needs_approval`; `approval_handle` `request_ref` `urn:cl:request:t02`; `user_visible_url` if present is `https` with no claim text in the query. + +Oracle: no bundle; handle if present contains none of the forbidden strings; handle has no `context`, claims, or `proposed_claims`; `needs_approval` is a successful protocol outcome (not a transport 4xx solely because approval is required). + +Fail if: unpaired client receives `allow`; handle validates and includes `quiet hours 21:00-07:00`. + +## T03 — `purpose_code` absent from pass + +Invariant. Request `purpose_code` MUST be a member of `allowed_purpose_codes`. Prefix match MUST NOT satisfy. + +Given: pairing `pair_4401` paired; pass `pass_4401` active with purposes `retrieve.context`, `draft.response`. + +When: `context_request` `urn:cl:request:t03` with `purpose_code` `retrieve.summary` (prefix-similar, not a member), selector `preference.quiet_hours`. + +Expected: decision `deny` or `needs_approval`; `reason_codes` includes `PURPOSE_NOT_ON_PASS`; no bundle. + +Oracle: `retrieve.summary` is not treated as `retrieve.context`; no bundle; no forbidden strings on handle or decision. + +Fail if: prefix or purpose text match issues a bundle; schema-valid pass plus schema-valid request is treated as sufficient. + +## T04 — off-pass category; denied text absent + +Invariant. A selector whose category is not on the pass MUST be denied or force `needs_approval` for the exact request. Denied claim text MUST be absent from handle and bundle. + +Given: pairing `pair_4401`; `pass_4401` categories `preference`, `fact` (not `instruction`); vault claim `instr-always-cite` text `always cite sources`. + +When: `context_request` `urn:cl:request:t04` `purpose_code` `retrieve.context` with selectors `[{predicate: preference.quiet_hours}, {predicate: instruction.citation}]`. Classification: `preference.quiet_hours` to `preference` (on pass); `instruction.citation` to `instruction` (off pass). + +Expected branch A: decision `needs_approval`; `approval_handle.pass_gap.missing_categories` `[instruction]`; no bundle; handle MUST NOT contain `always cite sources` or `quiet hours 21:00-07:00`. + +Expected branch B: decision `allow_with_reductions`; `denied_selectors` includes `{predicate: instruction.citation}`; `reason_codes` includes `CATEGORY_NOT_ON_PASS`; if a bundle is issued, context MUST NOT include `always cite sources` or predicate `instruction.citation`. + +Oracle: scan every returned object for `always cite sources`, FAIL if found; off-pass selector is never in `granted_selectors`. + +Fail if: off-pass instruction claim is in the bundle and objects still validate; handle lists the missing category and also includes the claim value. + +## T05 — later on-pass read still needs a new request + +Invariant. A pass is necessary, not sufficient. A later read of an on-pass category still requires a new `context_request` and `policy_decision`. + +Given: pairing `pair_4401`; `pass_4401` still active; prior successful disclosure of `pref-quiet-hours` under `urn:cl:request:t05a` / `urn:cl:decision:t05a` / `urn:cl:bundle:t05a` (expired or consumed). + +When: consumer still holding `pass_4401` and the prior bundle id asks again for `preference.quiet_hours` without a new request, then with a new request `urn:cl:request:t05b`. + +Expected: replay of `urn:cl:bundle:t05a` is refused (`single_use` or expired); no ambient disclosure from the pass alone; `t05b` produces a new `policy_decision` `urn:cl:decision:t05b`; only after `allow` or `allow_with_reductions` may `urn:cl:bundle:t05b` include `quiet hours 21:00-07:00`; `t05b` ids MUST differ from `t05a`. + +Oracle: pass object is unchanged (same id, categories, `allowed_purpose_codes`); two distinct `context_request` ids exist; consumer cannot obtain claim text by presenting only `pass_4401`. + +Fail if: presenting the pass returns claim text with no new request; a new bundle is issued with `request_ref` equal to the consumed `t05a`. + +## T06 — proposal commit does not mint or widen a pass + +Invariant. Committing a `memory_update_proposal` MUST NOT create or widen a `context_pass`. + +Given: `pass_4401` categories `[preference, fact]`; 0.2 `memory_update_proposal` `urn:cl:proposal:t06` operation `add`, predicate `instruction.citation`, status `pending_approval` (closed Lite object; no extra fields). + +When: proposal is approved and committed. Emit `lifecycle_event` `proposal.committed`. + +Expected: proposal status becomes `committed` per 0.2 rules; `lifecycle_event.operation` `proposal.committed`; `refs.proposal_ref` `urn:cl:proposal:t06`; `payload_included` false; pass set after commit is still exactly `pass_4401` with categories `[preference, fact]`; no new object with type `context_pass`; `allowed_purpose_codes` unchanged. + +Oracle: `count(type==context_pass)` after equals before; `pass_4401.categories` deep-equals `[preference, fact]`; subsequent read of `instruction.citation` still fails T04; lifecycle event contains none of the forbidden strings. + +Fail if: commit mints `urn:cl:pass:*` for instruction; commit appends `instruction` to `pass_4401.categories`; commit is treated as a standing read grant. + +## T07 — revoked pass cannot obtain a later bundle + +Invariant. Revocation is prospective. A revoked pass MUST NOT issue future bundles. It cannot un-disclose already issued ones. + +Given: `pass_4401` was active; optional prior bundle `urn:cl:bundle:t07-prior` already issued under it. + +When: set `pass_4401.status` to `revoked` and set `revoked_at`; emit `lifecycle_event` `pass.revoked` with `refs.pass_ref` `urn:cl:pass:pass_4401`; submit new `context_request` `urn:cl:request:t07` for `preference.quiet_hours`. + +Expected: new request `deny` or `needs_approval`; `reason_codes` includes `PASS_REVOKED`; no new bundle; prior bundle `t07-prior` is not rewritten; remote deletion is not claimed; lifecycle `payload_included` false. + +Oracle: zero new `scoped_context_bundle` objects after revoke; `always cite sources` and `quiet hours 21:00-07:00` absent from the new decision or handle; prior bundle body if retained is unchanged. + +Fail if: revoked pass still issues a bundle; revoke rewrites or deletes the historical bundle object and calls that un-disclosure. + +## T08 — `lifecycle_event` is content-free + +Invariant. `lifecycle_event` MUST serialize `payload_included` false and MUST NOT include claim text. + +Given: events for `pass.issued` (`le_4401`), `proposal.committed` (`le_t06`), `pass.revoked` (`le_t07`). + +When: serialize each event to JSON. + +Expected canonical shape: `spec_version` `context-layer/0.3-draft`; `type` `lifecycle_event`; `payload_included` false; refs only `pass_ref`, `pairing_ref`, `proposal_ref`, `bundle_ref`, `request_ref`, `decision_ref`. + +Oracle for every event: `payload_included === false`; JSON string contains none of the forbidden claim strings; no `context`, `claims`, `proposed_claims`, or `user_summary` members. + +Fail if: object validates against the schema and includes claim text in any string field; `payload_included` is omitted or true. + +## T09 — `inferred` MUST NOT be emitted as `stated_by_user` + +Invariant. Evidence labels MUST NOT be upgraded. `inferred` MUST NOT be disclosed as `stated_by_user` or `direct_user_save`. + +Given `claim_annotation` `urn:cl:annotation:ann_inferred_color`; `claim_ref` `urn:cl:claim:inferred-color`; `evidence_basis` `inferred`; `visibility` `vault`; `category` `preference`. + +When: any disclosure path that includes `urn:cl:claim:inferred-color` (bundle, public profile, or annotation export). + +Expected: if disclosed, `evidence_basis` remains `inferred`; MUST NOT appear as `stated_by_user` or `direct_user_save`; annotation stays vault-zone unless policy explicitly grants the annotation. + +Oracle: no returned object pairs `claim_ref` `urn:cl:claim:inferred-color` with `evidence_basis` in `{stated_by_user, direct_user_save}`; `favorite color is teal` MUST NOT appear with those upgraded labels; 0.2 `context_claim.status` `derived` is not a license to drop `inferred`. + +Fail if: annotation schema-validates and a bundle lists the claim as user-stated. + +## T10 — visibility `vault` is absent from public-profile export + +Invariant. Public profile is not the vault. Visibility `vault` MUST NOT appear on a public profile. + +Given: `pref-quiet-hours` vault; `fact-timezone` public_profile; `instr-always-cite` vault; `inferred-color` vault. + +When: export public profile for `vault://subjects/primary`. + +Expected: export MAY include `America/New_York` / `fact-timezone`; export MUST NOT include `quiet hours 21:00-07:00`, `always cite sources`, or `favorite color is teal`; export is not a `scoped_context_bundle` and not a `context_pass`. + +Oracle: scan export for the three vault claim strings, FAIL if any found; every exported claim has annotation visibility `public_profile`; export type is not `scoped_context_bundle` or `context_pass`. + +Fail if: vault claims are present on the profile and objects still validate; profile is issued as a bundle substitute. + +## Closed Lite reminder + +T01 through T07 MAY emit 0.2 objects. Those objects MUST validate against the closed 0.2 schemas with no additional properties. `reason_codes` `IDENTITY_ONLY`, `PAIRING_REQUIRED`, `PURPOSE_NOT_ON_PASS`, `CATEGORY_NOT_ON_PASS`, `PASS_REVOKED` travel on the existing `policy_decision.reason_codes` array. They are not new Lite fields. + +## Result ledger + +| ID | Check | +| --- | --- | +| T01 | identity-only | +| T02 | unpaired client | +| T03 | purpose not on pass | +| T04 | off-pass category | +| T05 | new request required | +| T06 | commit does not mint pass | +| T07 | revoked pass | +| T08 | lifecycle content-free | +| T09 | inferred not upgraded | +| T10 | vault not on profile | + +A row that only says schemas valid is not a pass. From 18622c6290b82951f7c6a793adf30947eae13e60 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 13 Sep 2026 19:03:34 +0000 Subject: [PATCH 2/5] Land recovered CL-Pass spec, vectors, and whiteboard recipe Apply the PART 3 one-character base64 fix and land pack files that extracted intact. Complete spec.md after the gzip CRC break at 6.2. Co-authored-by: sierra --- .../2026-09-weekend-protocol-proposal.md | 2 +- protocol/companions/0.3-draft/spec.md | 470 +++++++++++++++--- .../0.3-draft/whiteboard-capture-recipe.md | 92 ++++ test-vectors/cl-pass/VECTORS.md | 458 +++++++++++++---- 4 files changed, 840 insertions(+), 182 deletions(-) create mode 100644 protocol/companions/0.3-draft/whiteboard-capture-recipe.md diff --git a/docs/proposals/2026-09-weekend-protocol-proposal.md b/docs/proposals/2026-09-weekend-protocol-proposal.md index d34b5f9..c5fb463 100644 --- a/docs/proposals/2026-09-weekend-protocol-proposal.md +++ b/docs/proposals/2026-09-weekend-protocol-proposal.md @@ -71,7 +71,7 @@ Companion pack: [`protocol/companions/0.3-draft/`](../../protocol/companions/0.3 | `claim_annotation` | Rides beside claims until a 0.3 core revision. Evidence labels MUST NOT be upgraded. | | `memory_category` | Closed enum: `preference` \| `fact` \| `project` \| `instruction` | -Companion schemas and examples live under [`protocol/companions/0.3-draft/schemas/`](../../protocol/companions/0.3-draft/schemas/) and [`examples/`](../../protocol/companions/0.3-draft/examples/). Do not invent types. Object names and invariants match the closed Drive record in [`DRIVE-PAGE.md`](../../protocol/companions/0.3-draft/DRIVE-PAGE.md). +Companion schemas, examples, README, spec, and T01–T10 vectors live under [`protocol/companions/0.3-draft/`](../../protocol/companions/0.3-draft/) and [`test-vectors/cl-pass/VECTORS.md`](../../test-vectors/cl-pass/VECTORS.md). Do not invent types. Object names and invariants match the closed Drive record in [`DRIVE-PAGE.md`](../../protocol/companions/0.3-draft/DRIVE-PAGE.md). ### Invariants (normative for CL-Pass) diff --git a/protocol/companions/0.3-draft/spec.md b/protocol/companions/0.3-draft/spec.md index 01d2ecc..288593a 100644 --- a/protocol/companions/0.3-draft/spec.md +++ b/protocol/companions/0.3-draft/spec.md @@ -1,16 +1,52 @@ # Context Layer primitives addendum -Normative companion addendum for `context-layer/0.3-draft` (CL-Pass). A `context-layer/0.2-draft` deployment MAY negotiate this profile without opening the five CL-Core-Lite schemas. +## Draft companion objects for v0.3 / `CL-Pass` beside v0.2 -Status: working draft. Not an adopted standard. +| Field | Value | +| --- | --- | +| Status | Working Draft - not an adopted standard | +| Version identifier | `context-layer/0.3-draft` | +| Companion profile | `CL-Pass` (negotiable beside `context-layer/0.2-draft` without mutating Lite schemas) | +| Date | 2026-08-28 | +| Relates to | `context-layer/0.2-draft` CL-Core-Lite | -Closed Drive record: [CLOSED Context Layer 0.3-draft companions (CL-Pass) — 2026-08-29](https://docs.google.com/document/d/19ZNUrP3zCxRxbXvQ-0EBV9MKuMcJbkKXLKp58MTHtUA/edit). Landed copy: [DRIVE-PAGE.md](DRIVE-PAGE.md). +## Change log -## 0.3-draft note +- 2026.08.28 · 0.3-draft companions · identity, pairing, pass, approval handle, lifecycle, claim annotation -This addendum defines companion objects beside Lite. It is not a restatement of 0.2-draft and it is not a patch to Lite. +## Abstract -The five CL-Core-Lite objects stay closed (`additionalProperties: false`): +This addendum defines companion objects that a Context Layer vault MAY issue beside `context-layer/0.2-draft`. It does not change the five closed CL-Core-Lite schemas. + +The missing contract is standing authorization above a single request: who is signed in, which exact client is paired, which memory categories a consumer may even ask about, what happens when the ask is ahead of the grant, and a content-free log of those lifecycle edges. + +A pass is not a bundle. Identity is not a pass. Pairing is not a pass. Ask is not read. Write approval is not a read pass. + +## 1. Requirements language + +The key words **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHALL NOT**, **SHOULD**, **SHOULD NOT**, **RECOMMENDED**, **NOT RECOMMENDED**, **MAY**, and **OPTIONAL** in this document are to be interpreted as described in [BCP 14](https://www.rfc-editor.org/info/bcp14/) when, and only when, they appear in all capitals. + +Normative requirements apply only to an implementation claiming `CL-Pass` or `context-layer/0.3-draft` for these object types. Descriptive text and examples are informative unless labeled normative. + +Common representation rules from 0.2-draft section 6 apply: UTF-8 JSON, `spec_version` / `type` / `id` / `created_at` / `issuer`, opaque `urn:cl:...` identifiers, RFC 3339 timestamps. Identifiers MUST NOT embed email addresses, names, access tokens, raw content, or other unnecessary private data. + +## 2. Status and composition + +### 2.1 In scope + +- `identity_assertion` +- `client_pairing` +- `context_pass` +- `memory_category` enum +- `approval_handle` +- `lifecycle_event` +- `claim_annotation` +- Invariants that bind those objects to the existing 0.2 request → decision → bundle → proposal → receipt flow +- A 0.3-draft note for evidence and visibility fields on `context_claim` + +### 2.2 Closed 0.2 Lite schemas + +The five CL-Core-Lite schemas remain closed (`additionalProperties: false`): - `context_request` - `policy_decision` @@ -18,119 +54,393 @@ The five CL-Core-Lite objects stay closed (`additionalProperties: false`): - `memory_update_proposal` - `receipt` -`CL-Pass` evaluation uses existing 0.2 `policy_decision.reason_codes`. It does not add fields to Lite objects. Example codes: `IDENTITY_ONLY`, `PAIRING_REQUIRED`, `PURPOSE_NOT_ON_PASS`, `CATEGORY_NOT_ON_PASS`, `PASS_REVOKED`, `PASS_MISSING`. +Implementations MUST NOT add fields to those objects in this addendum. `CL-Pass` evaluation MUST use existing 0.2 members (in particular `decision`, `reason_codes`, `requester.client_instance`, and `{ "predicate" }` selectors). + +`context_claim` is specified in 0.2 prose and is not one of the five Lite schemas. This addendum still MUST NOT patch 0.2 claim objects. Evidence, visibility, category, and attribution live on `claim_annotation` until a 0.3 core revision folds them in. + +### 2.3 Already specified (do not duplicate) + +0.2-draft already requires purpose-bound requests, four-state policy (`allow`, `allow_with_reductions`, `deny`, `needs_approval`), recipient-bound single-use bundles, proposal-only writeback, receipts, `requester` / `recipient` / `client_instance`, `onward_disclosure`, and selectors as `{ "predicate" }`. This addendum does not redefine them. + +### 2.4 Observed origin + +Several standing-grant, pairing, and ask-versus-read behaviors were observed in Egoist AI Passport and Switchboard. This addendum rewrites those behaviors as Context Layer objects. It does not implement, subset, or adapt their protocol. Types, tool names, authorization-scope strings, and packages from that system are not imported. See [crosswalk.md](crosswalk.md). + +### 2.5 Profile negotiation + +Objects defined here MUST use `spec_version` `context-layer/0.3-draft`. + +A 0.2-draft deployment MAY advertise companion profile `CL-Pass`. Negotiating `CL-Pass` does not make a 0.3 object into a 0.2 Lite object. Consumers MUST reject these companions if they do not implement this addendum. -All companion objects use `spec_version` `context-layer/0.3-draft` and `additionalProperties: false`. +## 3. Invariants -## Invariants +A conforming `CL-Pass` implementation MUST preserve these invariants in addition to 0.2-draft section 3. -1. Identity is not a context grant. `identity_assertion.context_grant` MUST be `false`. Authenticating a principal MUST NOT disclose vault claims. -2. Identity-only consumers MUST NOT be treated as authorized to submit a disclosing `context_request` and MUST NOT be issued a `scoped_context_bundle`. -3. Pairing is not a pass. `client_pairing` admits an exact `client_instance` only. -4. Unpaired clients MUST get `deny` or `needs_approval`. -5. A pass is necessary, not sufficient. Every disclosure still requires 0.2 `context_request` → `policy_decision` → `scoped_context_bundle`. An active `context_pass` is not a bundle, wildcard selector, or ambient vault access. -6. Categories grant; predicates select. A pass grants `memory_category` values. A request still names `{ "predicate" }` selectors. An off-pass category MUST be denied or `needs_approval` for the exact request. -7. Ask is not read. `needs_approval` is a successful protocol outcome. `approval_handle` MUST NOT include denied claim values, claim text, or vault payloads. -8. Write approval is not a read pass. Committing a `memory_update_proposal` MUST NOT mint or widen a `context_pass`. -9. Revocation is prospective. Revoking a pass or pairing MUST prevent future bundles. It cannot un-disclose issued bundles. -10. Lifecycle events carry no content. `payload_included` MUST be `false`. -11. Evidence labels MUST NOT be upgraded. `inferred` MUST NOT be disclosed as `stated_by_user` or `direct_user_save`. -12. Public profile is not the vault. Visibility `vault` MUST NOT appear on a public profile. +1. **Identity is not a context grant.** An `identity_assertion` authenticates a principal. It MUST NOT contain vault claims, selector matches, or bundle material. Authenticating a principal MUST NOT disclose vault claims. +2. **Identity-only consumers cannot read the vault.** A consumer that only has `identity_assertion` MUST NOT be treated as authorized to submit a disclosing `context_request`, and MUST NOT be issued a `scoped_context_bundle`. +3. **Pairing is not a pass.** `client_pairing` admits an exact `client_instance`. It MUST NOT by itself authorize category disclosure. +4. **Unpaired clients do not get standing disclosure.** If the requester's `client_instance` has no `client_pairing` with `status: "paired"` for the subject, policy MUST return `deny` or `needs_approval`. +5. **A pass is necessary, not sufficient.** Every disclosure still requires a 0.2 `context_request` → `policy_decision` → `scoped_context_bundle`. An active `context_pass` MUST NOT be treated as a bundle, a wildcard selector, or ambient vault access. +6. **Categories grant; predicates select.** A pass grants `memory_category` values. A request still names `{ "predicate" }` selectors. Policy MUST deny a selector whose category is not on an active pass for that principal and `client_instance`, unless this exact request is decided `needs_approval`. +7. **Ask is not read.** `needs_approval` is a successful protocol outcome. It MUST NOT be encoded as a transport error solely because approval is required. The companion `approval_handle` MUST NOT include denied claim values, claim text, or vault payloads. +8. **Write approval is not a read pass.** Committing a `memory_update_proposal` MUST NOT mint a `context_pass` and MUST NOT add categories, purpose codes, principals, or `client_instance` bindings to an existing pass. Subsequent read still requires an active pass and a new `context_request`. +9. **Revocation is prospective.** Revoking a pass or pairing MUST prevent future bundles under that grant. It cannot un-disclose issued bundles. Issued-bundle limits remain as in 0.2-draft section 11.7. +10. **Lifecycle events carry no content.** A `lifecycle_event` MUST NOT include claim text, selector values, proposal bodies, or bundle context. `payload_included` MUST be `false`. +11. **Evidence labels MUST NOT be upgraded.** `inferred` MUST NOT be disclosed as `stated_by_user` or `direct_user_save`. `derived` MUST NOT be disclosed as `direct_user_save`. +12. **Public profile is not the vault.** Records with `visibility: "vault"` MUST NOT appear on a public profile. Public profile is not a `scoped_context_bundle` and not a `context_pass`. -## Closed enum: `memory_category` +## 4. Terminology -Grant layer above selectors. Closed values: +Terms from 0.2-draft section 5 apply. This addendum adds: -`preference` | `fact` | `project` | `instruction` +**Identity assertion** +A time-bounded statement that a principal was authenticated at a `client_instance`. It is not authorization to disclose vault context. -There is no standalone schema file. The enum is defined inside the companion schemas that use it. No wildcards. +**Client pairing** +A standing admission that a specific `client_instance` may participate in pass issuance and context requests for a subject. Pairing is revoked independently of passes. -## Companion objects +**Memory category** +One of `preference`, `fact`, `project`, `instruction`. A closed grant layer. Not a selector. -Schemas live in [schemas/](schemas/). Synthetic examples live in [examples/](examples/). +**Context pass** +A revocable, expiring grant of one or more memory categories and purpose codes to one principal and one `client_instance`. Necessary for disclosure under `CL-Pass`. Never sufficient. -### `identity_assertion` +**Approval handle** +A content-free companion to a `needs_approval` decision, naming the request and the pass gap so a person can approve without the consumer having already read the vault. -Authentication of a principal. Not a context grant. MUST NOT carry vault claims, selectors, or bundle material. +**Claim annotation** +A companion envelope for evidence basis, visibility, category, and attribution of a claim. Not the claim. -`context_grant` is `const false`. Schema: [schemas/identity-assertion.schema.json](schemas/identity-assertion.schema.json). +**Lifecycle event** +A content-free, syncable record that a pass, pairing, proposal, or bundle changed state. Distinct from a receipt. -### `client_pairing` +## 5. Objects -Exact `client_instance` admission for a subject. Pairing is not a `context_pass` and not a context grant. +Examples use synthetic values. Canonical instances live in [examples/](examples/). -`status` is `paired` or `revoked`. `revoked` requires `revoked_at`. Schema: [schemas/client-pairing.schema.json](schemas/client-pairing.schema.json). +### 5.1 `identity_assertion` -### `context_pass` +Proves a principal. Does not grant context. -Standing category grant for one principal and one client instance. Necessary, not sufficient, for disclosure. +Required fields: -`categories` are `memory_category` values. `allowed_purpose_codes` are the 0.2 registered codes plus the 0.2 experimental `x.` pattern. Prefix match MUST NOT satisfy a purpose check. +- `subject_ref` +- `principal` +- `client_instance` +- `authenticated_by` +- `authenticated_at` +- `expires_at` +- `context_grant` with the exact value `false` -`status` is `active`, `revoked`, or `expired`. `revoked` requires `revoked_at`. Schema: [schemas/context-pass.schema.json](schemas/context-pass.schema.json). +```json +{ + "spec_version": "context-layer/0.3-draft", + "type": "identity_assertion", + "id": "urn:cl:identity:id_4401", + "created_at": "2026-08-28T18:00:00Z", + "issuer": { "id": "urn:cl:identity-issuer:local" }, + "subject_ref": "vault://subjects/primary", + "principal": "urn:cl:principal:subject-primary", + "client_instance": "urn:device:local-workstation", + "authenticated_by": "deployment_session", + "authenticated_at": "2026-08-28T18:00:00Z", + "audience": "urn:app:notes", + "expires_at": "2026-08-28T20:00:00Z", + "context_grant": false +} +``` + +`context_grant` MUST be `false`. Implementations MUST reject an identity object that includes selectors, predicates, claims, categories, or bundle refs. Schema `additionalProperties: false` is the mechanical enforcement; policy MUST still treat possession of this object as non-authorization for vault read. + +`authenticated_by` names a deployment identity method. It is not a purpose code and MUST NOT be interpreted as a category grant. + +### 5.2 `client_pairing` + +Binds one `client_instance` to one subject. + +Required fields: + +- `subject_ref` +- `client_instance` +- `display_name` +- `paired_at` +- `status` (`paired` or `revoked`) + +When `status` is `revoked`, `revoked_at` is REQUIRED. + +```json +{ + "spec_version": "context-layer/0.3-draft", + "type": "client_pairing", + "id": "urn:cl:pairing:pair_4401", + "created_at": "2026-08-28T18:02:00Z", + "issuer": { "id": "urn:cl:pairing:local" }, + "subject_ref": "vault://subjects/primary", + "client_instance": "urn:device:local-workstation", + "display_name": "local workstation notes", + "paired_at": "2026-08-28T18:02:00Z", + "status": "paired" +} +``` -### `approval_handle` +`display_name` is a user-facing label for the client. It MUST NOT contain vault claim values. -Companion to a `policy_decision` of `needs_approval`. Successful protocol output, not an error. MUST NOT carry claim values or denied vault content. +Pairing MUST match the request's `requester.client_instance` exactly. Implementations MUST NOT treat a related device, same-principal wildcard, or display-name match as paired. -`pass_gap.missing_categories` names the categories that blocked the request. Optional `user_visible_url` is `https` only. Schema: [schemas/approval-handle.schema.json](schemas/approval-handle.schema.json). +Revoking a pairing MUST prevent issuance of new passes and new bundles for that `client_instance`. Existing passes for that instance SHOULD be revoked as well; if they are left `active`, policy MUST still deny disclosure because pairing is no longer `paired`. -### `lifecycle_event` +### 5.3 `memory_category` -Content-free vault lifecycle record for sync. MUST NOT include claim text, selector values, or payloads. Distinct from a 0.2 receipt. +Closed enum: -`payload_included` is `const false`. `operation` stays exactly: +| Value | Intended use | +| --- | --- | +| `preference` | Subject-stated preferences | +| `fact` | Factual claims about the subject or their world | +| `project` | Project, task, or work-stream context | +| `instruction` | Standing instructions to consumers | -`pass.issued` | `pass.revoked` | `pairing.revoked` | `proposal.committed` | `bundle.issued` | `bundle.expired` +A vault claiming `CL-Pass` MUST classify every disclosable predicate into exactly one `memory_category` before policy evaluation. An unclassified predicate MUST be denied or force `needs_approval` for the exact request. -`refs` may contain only `pass_ref`, `pairing_ref`, `proposal_ref`, `bundle_ref`, `request_ref`, and `decision_ref`. Required refs depend on `operation`. Schema: [schemas/lifecycle-event.schema.json](schemas/lifecycle-event.schema.json). +Selectors stay 0.2 `{ "predicate" }` objects. Requests MUST NOT carry a category in place of a predicate. Passes MUST NOT carry predicates in place of categories. -### `claim_annotation` +This enum is closed in 0.3-draft. New categories require a later spec version. Implementations MUST NOT accept unknown category strings. -Companion envelope for evidence basis, visibility, memory category, and attribution. Not a patch to closed 0.2 Lite objects. Proposed native fields for `context_claim` in a later 0.3 core revision. +### 5.4 `context_pass` -`evidence_basis`: `direct_user_save` | `stated_by_user` | `derived` | `inferred` +Standing grant: one principal, one `client_instance`, one or more categories, one or more purpose codes, one expiry. -`visibility`: `vault` | `public_profile` +Required fields: -Schema: [schemas/claim-annotation.schema.json](schemas/claim-annotation.schema.json). +- `subject_ref` +- `principal` +- `client_instance` +- `categories` (min 1, unique, from `memory_category`) +- `allowed_purpose_codes` (min 1, unique, 0.2 purpose-code registry or `x.` extension) +- `expires_at` +- `revocable` +- `status` (`active`, `revoked`, or `expired`) -## Lifecycle +When `status` is `revoked`, `revoked_at` is REQUIRED. `pairing_ref` is OPTIONAL and SHOULD be set when the pass was issued against a known pairing. -```text -identity_assertion # not a context grant -client_pairing # exact client_instance; not a pass - | - v -context_pass # categories + purpose codes; necessary, not sufficient - | - v -context_request # 0.2; selectors remain predicates - | - v -policy_decision # 0.2 four-state; unchanged schema - | - +-- needs_approval --> approval_handle # success, not an error - | - +-- allow / allow_with_reductions --> scoped_context_bundle # 0.2 - | - v -receipt # 0.2 -optional memory_update_proposal - | - v -commit MUST NOT mint or widen a context_pass -lifecycle_event # content-free sync log beside receipts -claim_annotation # rides beside claims until 0.3 +```json +{ + "spec_version": "context-layer/0.3-draft", + "type": "context_pass", + "id": "urn:cl:pass:pass_4401", + "created_at": "2026-08-28T18:05:00Z", + "issuer": { "id": "urn:cl:pass-issuer:local" }, + "subject_ref": "vault://subjects/primary", + "principal": "urn:app:notes", + "client_instance": "urn:device:local-workstation", + "pairing_ref": "urn:cl:pairing:pair_4401", + "categories": ["preference", "fact"], + "allowed_purpose_codes": ["retrieve.context", "draft.response"], + "expires_at": "2026-09-04T18:05:00Z", + "revocable": true, + "status": "active" +} ``` -A consumer that holds only `identity_assertion` MUST NOT be issued a bundle and MUST NOT be treated as authorized to request vault disclosure. +A pass is **active** only when `status` is `active` and `expires_at` is strictly in the future at evaluation time. An implementation MUST treat a stored `active` pass as `expired` once `expires_at` has passed, and MUST NOT issue bundles under it. + +`principal` on the pass MUST equal the request's `requester.principal`. `client_instance` on the pass MUST equal the request's `requester.client_instance`. The request `purpose_code` MUST be a member of `allowed_purpose_codes`. Prefix match, similarity, and optional `purpose` text MUST NOT satisfy this check (same rule as 0.2-draft section 7.3.1). + +`revocable` SHOULD be `true`. If `revocable` is `false`, only expiry (and pairing revocation, per 5.2) ends the grant. A `CL-Pass` issuer MUST still honor subject-initiated pairing revocation. + +Issuing a pass MUST NOT emit a `scoped_context_bundle`. Widening a pass (adding categories, purpose codes, a different principal, or a different `client_instance`) MUST be represented as a new pass object, not a silent mutation of an already-evaluated grant. A later policy change MUST NOT silently broaden an already-issued pass. + +### 5.5 `approval_handle` + +Companion to a 0.2 `policy_decision` whose `decision` is `needs_approval`. + +Required fields: + +- `request_ref` +- `pass_gap.missing_categories` (min 1) +- `expires_at` + +`decision_ref` and `user_visible_url` are OPTIONAL. `user_visible_url`, if present, MUST be an `https://` URL. + +```json +{ + "spec_version": "context-layer/0.3-draft", + "type": "approval_handle", + "id": "urn:cl:approval:ah_4401", + "created_at": "2026-08-28T18:10:00Z", + "issuer": { "id": "urn:cl:approval-surface:local" }, + "request_ref": "urn:cl:request:req_880", + "decision_ref": "urn:cl:decision:dec_880", + "pass_gap": { + "missing_categories": ["instruction"] + }, + "user_visible_url": "https://vault.example/approve/ah_4401", + "expires_at": "2026-08-28T18:40:00Z" +} +``` + +The handle MUST NOT include claim values, denied selector payloads, provenance text, or any field that would let the consumer read vault content before approval. The schema forbids additional properties; implementations MUST NOT smuggle content through `user_visible_url` query strings. + +`pass_gap.missing_categories` lists categories requested (via classified predicates) that are not on an active pass. It MAY omit categories that were not requested. It MUST NOT list category values as a substitute for disclosing claims in those categories. + +Approval identifiers remain single-use or bound to the exact request digest, as in 0.2-draft section 9.3. A changed request MUST invalidate the handle. Completing approval MAY mint a `context_pass` for the approved categories; it MUST NOT skip the subsequent `context_request` → `policy_decision` → bundle path. + +### 5.6 `claim_annotation` + +Companion envelope for a `context_claim`. 0.3 field proposals, not a Lite patch. + +Required fields: + +- `claim_ref` +- `evidence_basis` +- `visibility` +- `category` +- `attribution.via_principal` +- `attribution.captured_at` + +`evidence_basis` values: + +| Value | Meaning | +| --- | --- | +| `direct_user_save` | The subject stored the claim as such | +| `stated_by_user` | The subject stated it; capture may be mediated | +| `derived` | Extracted from sources with provenance | +| `inferred` | Model- or heuristic-inferred; not stated as fact by the subject | + +`visibility` values: `vault` | `public_profile`. + +```json +{ + "spec_version": "context-layer/0.3-draft", + "type": "claim_annotation", + "id": "urn:cl:annotation:ann_4401", + "created_at": "2026-08-28T17:55:00Z", + "issuer": { "id": "urn:cl:annotator:local" }, + "claim_ref": "urn:cl:claim:pref-quiet-hours", + "evidence_basis": "direct_user_save", + "visibility": "vault", + "category": "preference", + "attribution": { + "via_principal": "urn:cl:principal:subject-primary", + "captured_at": "2026-08-28T17:54:50Z" + } +} +``` + +A public profile MUST NOT include claims whose annotation `visibility` is `vault`. An `inferred` claim MUST NOT be disclosed with `evidence_basis` rewritten to `stated_by_user` or `direct_user_save`. Bundles that include an inferred claim SHOULD preserve the basis via a future 0.3 claim field; until then, the annotation stays inside the vault zone unless policy explicitly grants the annotation itself. + +### 5.7 `lifecycle_event` + +Syncable public-of-the-vault log. Content-free. + +Required fields: + +- `subject_ref` +- `operation` +- `occurred_at` +- `refs` (at least one allowed ref) +- `payload_included` with the exact value `false` + +`operation` values: + +| Operation | Required ref | +| --- | --- | +| `pass.issued` | `refs.pass_ref` | +| `pass.revoked` | `refs.pass_ref` | +| `pairing.revoked` | `refs.pairing_ref` | +| `proposal.committed` | `refs.proposal_ref` | +| `bundle.issued` | `refs.bundle_ref` | +| `bundle.expired` | `refs.bundle_ref` | + +Allowed ref members: `pass_ref`, `pairing_ref`, `proposal_ref`, `bundle_ref`, `request_ref`, `decision_ref`. Additional properties are forbidden. + +```json +{ + "spec_version": "context-layer/0.3-draft", + "type": "lifecycle_event", + "id": "urn:cl:lifecycle:le_4401", + "created_at": "2026-08-28T18:05:01Z", + "issuer": { "id": "urn:cl:lifecycle:local" }, + "subject_ref": "vault://subjects/primary", + "operation": "pass.issued", + "occurred_at": "2026-08-28T18:05:00Z", + "refs": { + "pass_ref": "urn:cl:pass:pass_4401", + "pairing_ref": "urn:cl:pairing:pair_4401" + }, + "payload_included": false +} +``` + +A `lifecycle_event` is not a `receipt`. Receipts remain the 0.2 evidence object (digests, outcomes, `user_summary`). Lifecycle events are the subset that may be synced as the public-of-the-vault log after content deletion. Implementations MUST be able to delete claim text and bundle context without deleting the corresponding lifecycle refs, subject to 0.2-draft section 11.7. + +## 6. Lifecycles + +These steps sit in front of, or beside, 0.2-draft section 8. They do not replace it. + +### 6.1 Pair, then pass, then request + +1. Authenticate the principal. Issue `identity_assertion` with `context_grant: false`. Stop. Do not disclose vault claims. +2. Require `client_pairing` for the exact `client_instance`. If unpaired, `deny` or `needs_approval`. +3. Require an active `context_pass` covering each requested selector's category and the request `purpose_code`. If missing, `deny` or `needs_approval` with `approval_handle`. +4. Continue with 0.2 outbound context lifecycle: evaluate the request, reduce scope, issue a recipient-bound single-use bundle, require receipts. + +Step 3 failure MUST NOT produce a bundle. Step 3 success MUST NOT skip step 4. + +### 6.2 Ask is not read + +When policy returns `needs_approval`: + +1. Persist the 0.2 `policy_decision`. +2. Issue `approval_handle` bound to `request_ref` (and `decision_ref` when available). +3. Return both as a successful protocol outcome. +4. MUST NOT put claim values on the handle. +5. MUST NOT treat the handle as a pass or a bundle. + +### 6.3 Write approval is not a read pass + +When a `memory_update_proposal` is approved and committed: + +1. Apply 0.2 commit rules. The proposal becomes `committed`. +2. Emit `lifecycle_event` with `operation` `proposal.committed` and `refs.proposal_ref` set. `payload_included` MUST be `false`. +3. MUST NOT mint a new `context_pass`. +4. MUST NOT add categories, purpose codes, principals, or `client_instance` bindings to an existing pass. +5. A later read of the committed category still requires an active pass covering that category and a new `context_request`. + +### 6.4 Revocation is prospective + +When a pass or pairing is revoked: + +1. Set `status` to `revoked` and set `revoked_at`. +2. Emit `lifecycle_event` `pass.revoked` or `pairing.revoked` with the required ref. `payload_included` MUST be `false`. +3. Subsequent disclosing requests under that grant MUST be `deny` or `needs_approval`. +4. MUST NOT issue a new `scoped_context_bundle` under the revoked grant. +5. MUST NOT rewrite, delete, or un-disclose an already issued bundle. Issued-bundle limits remain as in 0.2-draft section 11.7. + +### 6.5 Evidence, visibility, and public profile + +`claim_annotation` rides beside claims until a 0.3 core revision. Policy MUST keep `inferred` from being disclosed as `stated_by_user` or `direct_user_save`. A public-profile export MUST include only claims whose annotation `visibility` is `public_profile`. It is not a `scoped_context_bundle` and not a `context_pass`. + +## 7. Reason codes and the 0.3-draft note + +`CL-Pass` evaluation MUST use existing 0.2 `policy_decision.reason_codes`. It MUST NOT add fields to Lite objects. + +Example codes for this profile: + +- `IDENTITY_ONLY` +- `PAIRING_REQUIRED` +- `PASS_MISSING` +- `PURPOSE_NOT_ON_PASS` +- `CATEGORY_NOT_ON_PASS` +- `PASS_REVOKED` + +`context_claim` remains specified in 0.2 prose. Evidence, visibility, category, and attribution live on `claim_annotation` until a later 0.3 core revision folds them into the claim. -## Required tests +## 8. Required tests -Schema-valid JSON is not a pass. A CL-Pass claim MUST publish results for T01–T10. Oracles: [../../../test-vectors/cl-pass/VECTORS.md](../../../test-vectors/cl-pass/VECTORS.md). +Schema-valid JSON is not a pass. A `CL-Pass` claim MUST publish results for T01–T10. Oracles: [../../../test-vectors/cl-pass/VECTORS.md](../../../test-vectors/cl-pass/VECTORS.md). -## Non-goals +## 9. Non-goals - Not an Egoist AI Passport or Switchboard adapter, subset, client, or type import. Observation is recorded in [crosswalk.md](crosswalk.md); that is not adoption. - No Grok Bot adapter diff --git a/protocol/companions/0.3-draft/whiteboard-capture-recipe.md b/protocol/companions/0.3-draft/whiteboard-capture-recipe.md new file mode 100644 index 0000000..88c6979 --- /dev/null +++ b/protocol/companions/0.3-draft/whiteboard-capture-recipe.md @@ -0,0 +1,92 @@ +# Context Layer — Whiteboard Daddy capture recipe + +status: working draft · not a new spec card +audience: Whiteboard Daddy (draws). Context Layer owns whether a record is well-formed. +published: 2026-08-29 +revised: 2026-08-29 (completed-items addendum) +board folder: https://drive.google.com/drive/folders/15lt1Ow-uwAxu1zQ6OW9OVup4YFWDqHN6 +0.3 close: https://docs.google.com/document/d/19ZNUrP3zCxRxbXvQ-0EBV9MKuMcJbkKXLKp58MTHtUA/edit +0.2 Lite: CLOSED. No C009. No Switchboard adapter. No ouro. No live vault. No live issuer. + +You draw. You do not mint identity_assertion, context_pass, client_pairing, or scoped_context_bundle. + +## Per frame (minimum) + +After every new or changed board image: + +1. Persist the PNG (or webp) in the board folder. Do not remove earlier frames. +2. Hash the file bytes. artifact_hash = sha256: plus 64 lowercase hex. Not a thumbnail. Not OCR text. +3. Emit one 0.2 memory_update_proposal with status pending_approval. Do not commit it. Committing would be a live vault write. +4. Emit one 0.3 claim_annotation for each proposed claim. Do not patch 0.2 claim objects. +5. Stop. Do not issue a pass. Do not issue identity. Do not dump pixels into a vault claim. + +### Required fields on the proposal (closed 0.2 members only) + +spec_version: context-layer/0.2-draft +type: memory_update_proposal +operation: add +status: pending_approval +purpose_code recorded beside the file: x.board.capture +proposed_claims predicate: a 0.2 selector (e.g. project.board.frame) +proposed_claims object.value: the artifact_hash only +proposed_claims object.datatype: text +provenance_refs: optional opaque urn; MUST NOT be raw pixels +approval_requirement: user_confirm + +Do not add extra Lite fields. The image stays in Drive. The protocol record carries the hash. + +### Required fields on the annotation (closed 0.3) + +spec_version: context-layer/0.3-draft +type: claim_annotation +evidence_basis: derived (from the image) unless Sierra explicitly stated the box text, then stated_by_user +visibility: vault +category: project +attribution.via_principal: urn of Whiteboard Daddy as actor, not a grant +attribution.captured_at: RFC3339 + +Public profile MUST NOT include these frames. + +## Completed items (addendum) + +A completed box stays on the artifact. Never a delete. + +- Strikethrough is ink. It is not erasure. Do not trash the PNG. Do not drop the prior proposal. Do not emit a 0.2 delete. +- Open and completed must both be indexed. Keep the open-frame hash and its pending add. When the board is redrawn with strikethrough (or other done marks), persist that as a new frame, new hash, new pending add, new claim_annotation (same closed fields: derived, vault, project). +- Both hashes remain in the folder. The later frame still contains the completed item in pixels. +- Same closed types as an open capture. No new object. No new operation name. + +### Completed is not a lifecycle_event — STOP + +Closed 0.3 lifecycle_event.operation is only: + +pass.issued | pass.revoked | pairing.revoked | proposal.committed | bundle.issued | bundle.expired + +There is no item.done, box.complete, or done. claim_annotation has no open/completed field (evidence_basis, visibility, category, attribution only). + +Do not emit lifecycle_event for a completed box. proposal.committed would be a live vault lie. pass.issued is a grant. + +Closed page that would have to be extended: Context Layer 0.3 companion addendum, section 5.7 +https://docs.google.com/document/d/19ZNUrP3zCxRxbXvQ-0EBV9MKuMcJbkKXLKp58MTHtUA/edit + +DaddyBot opens cards. Until then: completed = new frame + claim_annotation + pending add of the new hash. Prior frame stays indexed. + +## What you do not emit + +identity_assertion, client_pairing, context_pass, scoped_context_bundle (no disclosure job unless DaddyBot assigns one), lifecycle_event with any new operation name. + +Receipts: only if a later 0.2 disclosure actually happens (then receipt with payload_included false and input_digest equal to the artifact_hash). Do not invent a frame.capture receipt operation. + +## Box add / move / erase — STOP + +Same closed enum as above. There is no box.add, box.move, or box.erase. + +Until a card: a box change is a new frame. New image, new hash, new pending proposal. The PNG is the source of truth. Do not mint box lifecycle types. Completing a box is not erase. + +## Disclosure back (only if assigned) + +If something on the board must be read from the vault into a later frame, that is a 0.2 context_request to policy_decision to scoped_context_bundle. Whiteboard Daddy is not the issuer. You still do not mint a pass. + +## One-line contract + +Hash the frame. Propose the hash. Annotate it. Leave it pending. Never a live vault. Never a delete. Open and completed both stay indexed. Strikethrough is not erasure. diff --git a/test-vectors/cl-pass/VECTORS.md b/test-vectors/cl-pass/VECTORS.md index 324db79..f9d56ec 100644 --- a/test-vectors/cl-pass/VECTORS.md +++ b/test-vectors/cl-pass/VECTORS.md @@ -6,7 +6,6 @@ spec: context-layer/0.3-draft companion addendum relates to: context-layer/0.2-draft CL-Core-Lite (CLOSED) published: 2026-08-29 close record: https://docs.google.com/document/d/19ZNUrP3zCxRxbXvQ-0EBV9MKuMcJbkKXLKp58MTHtUA/edit -canonical Drive vectors: https://docs.google.com/document/d/1NGbs7kSk__BtxwkjP-BhMKe_5A99phNVCFA3ICj7nw8/edit 0.2 Lite schemas stay closed. These vectors do not add fields to `context_request`, `policy_decision`, `scoped_context_bundle`, `memory_update_proposal`, or `receipt`. Schema-valid JSON is not a pass. Each test names an oracle that must fail if the invariant is broken even when every object validates. @@ -14,194 +13,451 @@ No PCP grants. No Legatus. No live issuer. No ouro. ## How to run -A CL-Pass claim MUST publish results for T01 through T10. For each test: load Given objects; apply When; compare Expected members only; evaluate Oracle; FAIL if any forbidden string appears; record pass or fail plus the first failing check. A harness that only validates JSON MUST report the Fail-if counterexamples as fail. +A `CL-Pass` claim MUST publish results for T01–T10. For each test: -## Fixture world (synthetic) +1. Load **Given** objects. +2. Apply **When**. +3. Compare **Expected** members only. Do not require extra Lite fields. +4. Evaluate **Oracle**. FAIL if any forbidden string or object appears. +5. Record `pass` | `fail` plus the first failing check. + +Counterexamples under **Fail if** are the schema-only traps. A harness that only validates JSON MUST report those as fail. -- `subject_ref`: `vault://subjects/primary` -- notes principal: `urn:app:notes` -- paired client: `urn:device:local-workstation` -- unpaired client: `urn:device:unpaired-phone` -- identity: `urn:cl:identity:id_4401` (`context_grant` false) -- pairing: `urn:cl:pairing:pair_4401` (status `paired`) -- pass: `urn:cl:pass:pass_4401` categories `preference`, `fact`; purposes `retrieve.context`, `draft.response`; status `active`; `expires_at` `2026-09-04T18:05:00Z` -- `eval_at`: `2026-08-29T13:00:00Z` +## Fixture world (synthetic) -Vault claims (appear only when an oracle allows them): +Shared vault. No live subject data. -- `urn:cl:claim:pref-quiet-hours` | preference | vault | `direct_user_save` | quiet hours 21:00-07:00 -- `urn:cl:claim:fact-timezone` | fact | public_profile | `stated_by_user` | America/New_York -- `urn:cl:claim:instr-always-cite` | instruction | vault | `direct_user_save` | always cite sources -- `urn:cl:claim:inferred-color` | preference | vault | `inferred` | favorite color is teal +| Ref | Value | +| --- | --- | +| subject_ref | `vault://subjects/primary` | +| notes principal | `urn:app:notes` | +| paired client | `urn:device:local-workstation` | +| unpaired client | `urn:device:unpaired-phone` | +| identity | `urn:cl:identity:id_4401` (`context_grant: false`) | +| pairing | `urn:cl:pairing:pair_4401` (`status: paired`) | +| pass | `urn:cl:pass:pass_4401` categories `preference`, `fact`; purposes `retrieve.context`, `draft.response`; `status: active`; `expires_at: 2026-09-04T18:05:00Z` | +| eval_at | `2026-08-29T13:00:00Z` (strictly before pass expiry) | + +Vault claims (canonical; appear only when an oracle allows them): + +| claim_ref | category | visibility | evidence_basis | claim text (forbidden on fail paths) | +| --- | --- | --- | --- | --- | +| `urn:cl:claim:pref-quiet-hours` | preference | vault | direct_user_save | `quiet hours 21:00-07:00` | +| `urn:cl:claim:fact-timezone` | fact | public_profile | stated_by_user | `America/New_York` | +| `urn:cl:claim:instr-always-cite` | instruction | vault | direct_user_save | `always cite sources` | +| `urn:cl:claim:inferred-color` | preference | vault | inferred | `favorite color is teal` | Forbidden-on-fail-path strings (scan every returned object, including URL query strings): -- `quiet hours 21:00-07:00` -- `always cite sources` -- `favorite color is teal` -- `America/New_York` (allowed only on T05 allow-path bundle and T10 public-profile export) +``` +quiet hours 21:00-07:00 +always cite sources +favorite color is teal +America/New_York +``` + +`America/New_York` is allowed only on T05 allow-path bundle context and T10 public-profile export. It is forbidden on T01–T04, T06–T09 deny/handle/lifecycle paths. ## T01 — identity is not a vault grant -Invariant. Authenticating a principal MUST NOT disclose vault claims. A consumer that only has `identity_assertion` MUST NOT be issued a bundle. +**Invariant.** Authenticating a principal MUST NOT disclose vault claims. A consumer that only has `identity_assertion` MUST NOT be issued a bundle. + +**Given** + +- `identity_assertion` `id_4401` with `context_grant: false` +- no `client_pairing` +- no `context_pass` + +**When** -Given: `identity_assertion` `id_4401` with `context_grant` false; no `client_pairing`; no `context_pass`. +Consumer holding only `id_4401` submits 0.2 `context_request` `urn:cl:request:t01`: -When: consumer holding only `id_4401` submits 0.2 `context_request` `urn:cl:request:t01` with `requester.principal` `urn:app:notes`, `requester.client_instance` `urn:device:local-workstation`, `purpose_code` `retrieve.context`, selectors `[{predicate: preference.quiet_hours}]`. +- `requester.principal`: `urn:app:notes` +- `requester.client_instance`: `urn:device:local-workstation` +- `purpose_code`: `retrieve.context` +- `selectors`: `[{ "predicate": "preference.quiet_hours" }]` -Expected: `policy_decision.decision` `deny`; `reason_codes` includes `IDENTITY_ONLY`; no `scoped_context_bundle`; no `approval_handle` that carries claim text. +**Expected** -Oracle: `context_grant === false`; zero objects type `scoped_context_bundle`; none of the forbidden strings appear; `identity_assertion` has no selectors, categories, claims, or `bundle_ref`. +- `policy_decision.decision`: `deny` +- `reason_codes` includes `IDENTITY_ONLY` +- no `scoped_context_bundle` +- no `approval_handle` that carries claim text -Fail if: identity object validates and a bundle is issued; decision is `allow` or `allow_with_reductions`; claim text is copied onto the identity object or a receipt `user_summary`. +**Oracle (must all hold)** + +- `identity_assertion.context_grant === false` +- returned set contains zero objects with `type === "scoped_context_bundle"` +- none of the forbidden-on-fail-path strings appear in any returned object +- `identity_assertion` has no `selectors`, `categories`, `claims`, or `bundle_ref` members (`additionalProperties: false`) + +**Fail if** + +- identity object validates and a bundle is issued +- decision is `allow` or `allow_with_reductions` +- claim text is copied onto the identity object or a receipt `user_summary` ## T02 — unpaired client: ask is not read -Invariant. Unpaired `client_instance` MUST be `deny` or `needs_approval`. `approval_handle` MUST NOT include denied claim values. +**Invariant.** Unpaired `client_instance` MUST be `deny` or `needs_approval`. `approval_handle` MUST NOT include denied claim values. + +**Given** + +- `identity_assertion` `id_4401` +- pairing `pair_4401` for `urn:device:local-workstation` only +- no pairing for `urn:device:unpaired-phone` +- pass `pass_4401` (does not bind the unpaired device) + +**When** + +`context_request` `urn:cl:request:t02` with `requester.client_instance`: `urn:device:unpaired-phone`, selector `preference.quiet_hours`, `purpose_code`: `retrieve.context`. + +**Expected (either branch is conforming)** -Given: identity `id_4401`; pairing `pair_4401` for local-workstation only; no pairing for `urn:device:unpaired-phone`; `pass_4401` does not bind the unpaired device. +Branch A: -When: `context_request` `urn:cl:request:t02` with `requester.client_instance` `urn:device:unpaired-phone`, selector `preference.quiet_hours`, `purpose_code` `retrieve.context`. +- `decision`: `deny` +- `reason_codes` includes `PAIRING_REQUIRED` +- no bundle -Expected branch A: decision `deny`; `reason_codes` includes `PAIRING_REQUIRED`; no bundle. +Branch B: -Expected branch B: decision `needs_approval`; `approval_handle` `request_ref` `urn:cl:request:t02`; `user_visible_url` if present is `https` with no claim text in the query. +- `decision`: `needs_approval` +- `approval_handle` `request_ref`: `urn:cl:request:t02` +- `pass_gap.missing_categories` MAY be `["preference"]` or empty if the implementation treats pairing as the only gap +- `user_visible_url` if present is `https://` with no claim text in the query -Oracle: no bundle; handle if present contains none of the forbidden strings; handle has no `context`, claims, or `proposed_claims`; `needs_approval` is a successful protocol outcome (not a transport 4xx solely because approval is required). +**Oracle** -Fail if: unpaired client receives `allow`; handle validates and includes `quiet hours 21:00-07:00`. +- no bundle +- `approval_handle` if present contains none of the forbidden strings +- handle has no `context`, `claims`, `proposed_claims`, or selector values (`additionalProperties: false`) +- `needs_approval` is returned as a successful protocol outcome (not a transport 4xx solely because approval is required) -## T03 — `purpose_code` absent from pass +**Fail if** -Invariant. Request `purpose_code` MUST be a member of `allowed_purpose_codes`. Prefix match MUST NOT satisfy. +- unpaired client receives `allow` +- handle validates and includes `quiet hours 21:00-07:00` -Given: pairing `pair_4401` paired; pass `pass_4401` active with purposes `retrieve.context`, `draft.response`. +## T03 — purpose_code absent from pass -When: `context_request` `urn:cl:request:t03` with `purpose_code` `retrieve.summary` (prefix-similar, not a member), selector `preference.quiet_hours`. +**Invariant.** Request `purpose_code` MUST be a member of `allowed_purpose_codes`. Prefix match MUST NOT satisfy. -Expected: decision `deny` or `needs_approval`; `reason_codes` includes `PURPOSE_NOT_ON_PASS`; no bundle. +**Given** -Oracle: `retrieve.summary` is not treated as `retrieve.context`; no bundle; no forbidden strings on handle or decision. +- pairing `pair_4401` (`paired`) +- pass `pass_4401` (`active`; purposes `retrieve.context`, `draft.response`) -Fail if: prefix or purpose text match issues a bundle; schema-valid pass plus schema-valid request is treated as sufficient. +**When** + +`context_request` `urn:cl:request:t03` with `purpose_code`: `retrieve.summary` (prefix-similar, not a member), selector `preference.quiet_hours`. + +**Expected** + +- `decision`: `deny` or `needs_approval` +- `reason_codes` includes `PURPOSE_NOT_ON_PASS` +- no bundle + +**Oracle** + +- `retrieve.summary` is not treated as `retrieve.context` +- no bundle +- no forbidden strings on handle or decision + +**Fail if** + +- prefix or `purpose` text match issues a bundle +- schema-valid pass + schema-valid request is treated as sufficient ## T04 — off-pass category; denied text absent -Invariant. A selector whose category is not on the pass MUST be denied or force `needs_approval` for the exact request. Denied claim text MUST be absent from handle and bundle. +**Invariant.** A selector whose category is not on the pass MUST be denied or force `needs_approval` for the exact request. Denied claim text MUST be absent from handle and bundle. + +**Given** + +- pairing `pair_4401` +- pass `pass_4401` categories `preference`, `fact` (not `instruction`) +- vault claim `instr-always-cite` text `always cite sources` + +**When** + +`context_request` `urn:cl:request:t04` `purpose_code`: `retrieve.context` with selectors: + +```json +[ + { "predicate": "preference.quiet_hours" }, + { "predicate": "instruction.citation" } +] +``` + +Classification: `preference.quiet_hours` → `preference` (on pass); `instruction.citation` → `instruction` (off pass). + +**Expected (either conforming)** + +Branch A — exact request `needs_approval`: + +- `decision`: `needs_approval` +- `approval_handle.pass_gap.missing_categories`: `["instruction"]` +- no bundle +- handle MUST NOT contain `always cite sources` or `quiet hours 21:00-07:00` -Given: pairing `pair_4401`; `pass_4401` categories `preference`, `fact` (not `instruction`); vault claim `instr-always-cite` text `always cite sources`. +Branch B — reduce: -When: `context_request` `urn:cl:request:t04` `purpose_code` `retrieve.context` with selectors `[{predicate: preference.quiet_hours}, {predicate: instruction.citation}]`. Classification: `preference.quiet_hours` to `preference` (on pass); `instruction.citation` to `instruction` (off pass). +- `decision`: `allow_with_reductions` +- `denied_selectors` includes `{ "predicate": "instruction.citation" }` +- `reason_codes` includes `CATEGORY_NOT_ON_PASS` +- if a bundle is issued, its `context` MUST NOT include `always cite sources` or predicate `instruction.citation` -Expected branch A: decision `needs_approval`; `approval_handle.pass_gap.missing_categories` `[instruction]`; no bundle; handle MUST NOT contain `always cite sources` or `quiet hours 21:00-07:00`. +**Oracle** -Expected branch B: decision `allow_with_reductions`; `denied_selectors` includes `{predicate: instruction.citation}`; `reason_codes` includes `CATEGORY_NOT_ON_PASS`; if a bundle is issued, context MUST NOT include `always cite sources` or predicate `instruction.citation`. +- scan every returned object for `always cite sources` → FAIL if found +- off-pass selector is never in `granted_selectors` -Oracle: scan every returned object for `always cite sources`, FAIL if found; off-pass selector is never in `granted_selectors`. +**Fail if** -Fail if: off-pass instruction claim is in the bundle and objects still validate; handle lists the missing category and also includes the claim value. +- off-pass instruction claim is in the bundle and objects still validate +- handle lists the missing category and also includes the claim value ## T05 — later on-pass read still needs a new request -Invariant. A pass is necessary, not sufficient. A later read of an on-pass category still requires a new `context_request` and `policy_decision`. +**Invariant.** A pass is necessary, not sufficient. A later read of an on-pass category still requires a new `context_request` and `policy_decision`. -Given: pairing `pair_4401`; `pass_4401` still active; prior successful disclosure of `pref-quiet-hours` under `urn:cl:request:t05a` / `urn:cl:decision:t05a` / `urn:cl:bundle:t05a` (expired or consumed). +**Given** -When: consumer still holding `pass_4401` and the prior bundle id asks again for `preference.quiet_hours` without a new request, then with a new request `urn:cl:request:t05b`. +- pairing `pair_4401` +- pass `pass_4401` still `active` +- prior successful disclosure of `pref-quiet-hours` under `urn:cl:request:t05a` / `urn:cl:decision:t05a` / `urn:cl:bundle:t05a` (expired or consumed) -Expected: replay of `urn:cl:bundle:t05a` is refused (`single_use` or expired); no ambient disclosure from the pass alone; `t05b` produces a new `policy_decision` `urn:cl:decision:t05b`; only after `allow` or `allow_with_reductions` may `urn:cl:bundle:t05b` include `quiet hours 21:00-07:00`; `t05b` ids MUST differ from `t05a`. +**When** -Oracle: pass object is unchanged (same id, categories, `allowed_purpose_codes`); two distinct `context_request` ids exist; consumer cannot obtain claim text by presenting only `pass_4401`. +Consumer, still holding `pass_4401` and the prior bundle id, asks again for `preference.quiet_hours` without a new request, then with a new request `urn:cl:request:t05b`. -Fail if: presenting the pass returns claim text with no new request; a new bundle is issued with `request_ref` equal to the consumed `t05a`. +**Expected** + +- replay of `urn:cl:bundle:t05a` is refused (`single_use` / expired) +- no ambient disclosure from the pass alone +- `urn:cl:request:t05b` produces a new `policy_decision` `urn:cl:decision:t05b` +- only after `allow` or `allow_with_reductions` may `urn:cl:bundle:t05b` include `quiet hours 21:00-07:00` +- `t05b` ids MUST differ from `t05a` + +**Oracle** + +- pass object is unchanged (same `id`, `categories`, `allowed_purpose_codes`) +- two distinct `context_request` ids exist for the two reads +- consumer cannot obtain claim text by presenting only `pass_4401` + +**Fail if** + +- presenting the pass returns claim text with no new request +- a new bundle is issued with `request_ref` equal to the consumed `t05a` ## T06 — proposal commit does not mint or widen a pass -Invariant. Committing a `memory_update_proposal` MUST NOT create or widen a `context_pass`. +**Invariant.** Committing a `memory_update_proposal` MUST NOT create or widen a `context_pass`. + +**Given** + +- pass `pass_4401` categories `["preference", "fact"]` +- 0.2 `memory_update_proposal` `urn:cl:proposal:t06` `operation`: `add`, predicate `instruction.citation`, status `pending_approval` (closed Lite object; no extra fields) + +**When** -Given: `pass_4401` categories `[preference, fact]`; 0.2 `memory_update_proposal` `urn:cl:proposal:t06` operation `add`, predicate `instruction.citation`, status `pending_approval` (closed Lite object; no extra fields). +Proposal is approved and committed. Emit `lifecycle_event` `proposal.committed`. -When: proposal is approved and committed. Emit `lifecycle_event` `proposal.committed`. +**Expected** -Expected: proposal status becomes `committed` per 0.2 rules; `lifecycle_event.operation` `proposal.committed`; `refs.proposal_ref` `urn:cl:proposal:t06`; `payload_included` false; pass set after commit is still exactly `pass_4401` with categories `[preference, fact]`; no new object with type `context_pass`; `allowed_purpose_codes` unchanged. +- proposal `status` becomes committed per 0.2 rules +- `lifecycle_event.operation`: `proposal.committed` +- `refs.proposal_ref`: `urn:cl:proposal:t06` +- `payload_included`: `false` +- pass set after commit: still exactly `pass_4401` with categories `["preference", "fact"]` +- no new object with `type === "context_pass"` +- `pass_4401.allowed_purpose_codes` unchanged -Oracle: `count(type==context_pass)` after equals before; `pass_4401.categories` deep-equals `[preference, fact]`; subsequent read of `instruction.citation` still fails T04; lifecycle event contains none of the forbidden strings. +**Oracle** -Fail if: commit mints `urn:cl:pass:*` for instruction; commit appends `instruction` to `pass_4401.categories`; commit is treated as a standing read grant. +- `count(type==context_pass)` after === before +- `pass_4401.categories` deep-equals `["preference", "fact"]` +- subsequent read of `instruction.citation` still fails T04 (off-pass) +- lifecycle event contains none of the forbidden strings + +**Fail if** + +- commit mints `urn:cl:pass:*` for `instruction` +- commit appends `instruction` to `pass_4401.categories` +- commit is treated as a standing read grant ## T07 — revoked pass cannot obtain a later bundle -Invariant. Revocation is prospective. A revoked pass MUST NOT issue future bundles. It cannot un-disclose already issued ones. +**Invariant.** Revocation is prospective. A revoked pass MUST NOT issue future bundles. It cannot un-disclose already issued ones. + +**Given** + +- pass `pass_4401` was `active` +- optional prior bundle `urn:cl:bundle:t07-prior` already issued under it + +**When** + +1. Set `pass_4401.status` to `revoked`, set `revoked_at`. +2. Emit `lifecycle_event` `pass.revoked` with `refs.pass_ref`: `urn:cl:pass:pass_4401`. +3. Submit new `context_request` `urn:cl:request:t07` for `preference.quiet_hours`. + +**Expected** + +- new request: `deny` or `needs_approval` +- `reason_codes` includes `PASS_REVOKED` +- no new bundle +- prior bundle `t07-prior` is not rewritten; remote deletion is not claimed +- lifecycle `payload_included`: `false` -Given: `pass_4401` was active; optional prior bundle `urn:cl:bundle:t07-prior` already issued under it. +**Oracle** -When: set `pass_4401.status` to `revoked` and set `revoked_at`; emit `lifecycle_event` `pass.revoked` with `refs.pass_ref` `urn:cl:pass:pass_4401`; submit new `context_request` `urn:cl:request:t07` for `preference.quiet_hours`. +- zero new `scoped_context_bundle` objects after revoke +- `always cite sources` and `quiet hours 21:00-07:00` absent from the new decision/handle +- prior bundle body, if retained, is unchanged (prospective only) -Expected: new request `deny` or `needs_approval`; `reason_codes` includes `PASS_REVOKED`; no new bundle; prior bundle `t07-prior` is not rewritten; remote deletion is not claimed; lifecycle `payload_included` false. +**Fail if** -Oracle: zero new `scoped_context_bundle` objects after revoke; `always cite sources` and `quiet hours 21:00-07:00` absent from the new decision or handle; prior bundle body if retained is unchanged. +- revoked pass still issues a bundle +- revoke rewrites or deletes the historical bundle object and calls that un-disclosure -Fail if: revoked pass still issues a bundle; revoke rewrites or deletes the historical bundle object and calls that un-disclosure. +## T08 — lifecycle_event is content-free -## T08 — `lifecycle_event` is content-free +**Invariant.** `lifecycle_event` MUST serialize `payload_included: false` and MUST NOT include claim text. -Invariant. `lifecycle_event` MUST serialize `payload_included` false and MUST NOT include claim text. +**Given** -Given: events for `pass.issued` (`le_4401`), `proposal.committed` (`le_t06`), `pass.revoked` (`le_t07`). +Events for `pass.issued` (`le_4401`), `proposal.committed` (`le_t06`), `pass.revoked` (`le_t07`). -When: serialize each event to JSON. +**When** -Expected canonical shape: `spec_version` `context-layer/0.3-draft`; `type` `lifecycle_event`; `payload_included` false; refs only `pass_ref`, `pairing_ref`, `proposal_ref`, `bundle_ref`, `request_ref`, `decision_ref`. +Serialize each event to JSON. -Oracle for every event: `payload_included === false`; JSON string contains none of the forbidden claim strings; no `context`, `claims`, `proposed_claims`, or `user_summary` members. +**Expected** (canonical shape) -Fail if: object validates against the schema and includes claim text in any string field; `payload_included` is omitted or true. +```json +{ + "spec_version": "context-layer/0.3-draft", + "type": "lifecycle_event", + "id": "urn:cl:lifecycle:le_4401", + "created_at": "2026-08-28T18:05:01Z", + "issuer": { "id": "urn:cl:lifecycle:local" }, + "subject_ref": "vault://subjects/primary", + "operation": "pass.issued", + "occurred_at": "2026-08-28T18:05:00Z", + "refs": { + "pass_ref": "urn:cl:pass:pass_4401", + "pairing_ref": "urn:cl:pairing:pair_4401" + }, + "payload_included": false +} +``` -## T09 — `inferred` MUST NOT be emitted as `stated_by_user` +**Oracle (every event)** -Invariant. Evidence labels MUST NOT be upgraded. `inferred` MUST NOT be disclosed as `stated_by_user` or `direct_user_save`. +- `payload_included === false` +- keys of `refs` ⊆ `{pass_ref, pairing_ref, proposal_ref, bundle_ref, request_ref, decision_ref}` +- JSON string of the event contains none of the forbidden claim strings +- no `context`, `claims`, `proposed_claims`, `user_summary`, or selector-value members -Given `claim_annotation` `urn:cl:annotation:ann_inferred_color`; `claim_ref` `urn:cl:claim:inferred-color`; `evidence_basis` `inferred`; `visibility` `vault`; `category` `preference`. +**Fail if** -When: any disclosure path that includes `urn:cl:claim:inferred-color` (bundle, public profile, or annotation export). +- object validates against the schema and includes claim text in any string field +- `payload_included` is omitted or `true` -Expected: if disclosed, `evidence_basis` remains `inferred`; MUST NOT appear as `stated_by_user` or `direct_user_save`; annotation stays vault-zone unless policy explicitly grants the annotation. +## T09 — inferred MUST NOT be emitted as stated_by_user -Oracle: no returned object pairs `claim_ref` `urn:cl:claim:inferred-color` with `evidence_basis` in `{stated_by_user, direct_user_save}`; `favorite color is teal` MUST NOT appear with those upgraded labels; 0.2 `context_claim.status` `derived` is not a license to drop `inferred`. +**Invariant.** Evidence labels MUST NOT be upgraded. `inferred` MUST NOT be disclosed as `stated_by_user` or `direct_user_save`. -Fail if: annotation schema-validates and a bundle lists the claim as user-stated. +**Given** -## T10 — visibility `vault` is absent from public-profile export +```json +{ + "spec_version": "context-layer/0.3-draft", + "type": "claim_annotation", + "id": "urn:cl:annotation:ann_inferred_color", + "created_at": "2026-08-28T17:56:00Z", + "issuer": { "id": "urn:cl:annotator:local" }, + "claim_ref": "urn:cl:claim:inferred-color", + "evidence_basis": "inferred", + "visibility": "vault", + "category": "preference", + "attribution": { + "via_principal": "urn:app:notes", + "captured_at": "2026-08-28T17:56:00Z" + } +} +``` -Invariant. Public profile is not the vault. Visibility `vault` MUST NOT appear on a public profile. +**When** -Given: `pref-quiet-hours` vault; `fact-timezone` public_profile; `instr-always-cite` vault; `inferred-color` vault. +Any disclosure path that includes `urn:cl:claim:inferred-color` (bundle, public profile, or annotation export). -When: export public profile for `vault://subjects/primary`. +**Expected** -Expected: export MAY include `America/New_York` / `fact-timezone`; export MUST NOT include `quiet hours 21:00-07:00`, `always cite sources`, or `favorite color is teal`; export is not a `scoped_context_bundle` and not a `context_pass`. +- if disclosed, `evidence_basis` remains `inferred` +- MUST NOT appear as `stated_by_user` or `direct_user_save` +- annotation stays vault-zone unless policy explicitly grants the annotation -Oracle: scan export for the three vault claim strings, FAIL if any found; every exported claim has annotation visibility `public_profile`; export type is not `scoped_context_bundle` or `context_pass`. +**Oracle** -Fail if: vault claims are present on the profile and objects still validate; profile is issued as a bundle substitute. +- no returned object pairs `claim_ref` `urn:cl:claim:inferred-color` with `evidence_basis` in `{stated_by_user, direct_user_save}` +- `favorite color is teal` MUST NOT appear with those upgraded labels +- 0.2 `context_claim.status: "derived"` is not a license to drop `inferred` + +**Fail if** + +- annotation schema-validates and a bundle lists the claim as user-stated + +## T10 — visibility vault is absent from public-profile export + +**Invariant.** Public profile is not the vault. `visibility: "vault"` MUST NOT appear on a public profile. + +**Given** + +- `pref-quiet-hours`: `visibility: vault` +- `fact-timezone`: `visibility: public_profile` +- `instr-always-cite`: `visibility: vault` +- `inferred-color`: `visibility: vault` + +**When** + +Export public profile for `vault://subjects/primary`. + +**Expected** + +- export MAY include `America/New_York` / `fact-timezone` +- export MUST NOT include `quiet hours 21:00-07:00`, `always cite sources`, `favorite color is teal` +- export is not a `scoped_context_bundle` and not a `context_pass` + +**Oracle** + +- scan export for the three vault claim strings → FAIL if any found +- every exported claim has annotation `visibility === "public_profile"` +- export `type` is not `scoped_context_bundle` or `context_pass` + +**Fail if** + +- vault claims are present on the profile and objects still validate +- profile is issued as a bundle substitute ## Closed Lite reminder -T01 through T07 MAY emit 0.2 objects. Those objects MUST validate against the closed 0.2 schemas with no additional properties. `reason_codes` `IDENTITY_ONLY`, `PAIRING_REQUIRED`, `PURPOSE_NOT_ON_PASS`, `CATEGORY_NOT_ON_PASS`, `PASS_REVOKED` travel on the existing `policy_decision.reason_codes` array. They are not new Lite fields. +T01–T07 MAY emit 0.2 objects. Those objects MUST validate against the closed 0.2 schemas with no additional properties. `reason_codes` values (`IDENTITY_ONLY`, `PAIRING_REQUIRED`, `PURPOSE_NOT_ON_PASS`, `CATEGORY_NOT_ON_PASS`, `PASS_REVOKED`) travel on the existing `policy_decision.reason_codes` array. They are not new Lite fields. ## Result ledger -| ID | Check | -| --- | --- | -| T01 | identity-only | -| T02 | unpaired client | -| T03 | purpose not on pass | -| T04 | off-pass category | -| T05 | new request required | -| T06 | commit does not mint pass | -| T07 | revoked pass | -| T08 | lifecycle content-free | -| T09 | inferred not upgraded | -| T10 | vault not on profile | - -A row that only says schemas valid is not a pass. +| Test | Result | First failing check | +| --- | --- | --- | +| T01 identity-only | | | +| T02 unpaired client | | | +| T03 purpose not on pass | | | +| T04 off-pass category | | | +| T05 new request required | | | +| T06 commit does not mint pass | | | +| T07 revoked pass | | | +| T08 lifecycle content-free | | | +| T09 inferred not upgraded | | | +| T10 vault not on profile | | | + +A row that only says “schemas valid” is not a pass. From 7480a857571569058013c16a2b7a3bc8d3fa5be5 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 13 Sep 2026 19:07:12 +0000 Subject: [PATCH 3/5] Scrub dirty-pack leaks and drop whiteboard recipe Remove the Drive close page and whiteboard capture recipe. Strip private Drive URLs and banned process names from remaining companions. Co-authored-by: sierra --- README.md | 6 +- .../2026-09-weekend-protocol-proposal.md | 7 +- protocol/companions/0.3-draft/DRIVE-PAGE.md | 61 ------------ protocol/companions/0.3-draft/spec.md | 2 - .../0.3-draft/whiteboard-capture-recipe.md | 92 ------------------- test-vectors/cl-pass/VECTORS.md | 3 +- 6 files changed, 4 insertions(+), 167 deletions(-) delete mode 100644 protocol/companions/0.3-draft/DRIVE-PAGE.md delete mode 100644 protocol/companions/0.3-draft/whiteboard-capture-recipe.md diff --git a/README.md b/README.md index 9fd7ce4..b5647ae 100644 --- a/README.md +++ b/README.md @@ -110,16 +110,14 @@ The repository test suite verifies that all published routes and their required ## Protocol proposal (weekend ship) -The 2026-09 weekend cut keeps `CL-Core-Lite` closed and adds a reviewable `context-layer/0.3-draft` companion pack (CL-Pass) beside it. This does not open the five Lite schemas, mint a live issuer, or land Switchboard / ouro work. +The 2026-09 weekend cut keeps `CL-Core-Lite` closed and adds a reviewable `context-layer/0.3-draft` companion pack (CL-Pass) beside it. This does not open the five Lite schemas or mint a live issuer. | Path | Purpose | | --- | --- | | [docs/proposals/2026-09-weekend-protocol-proposal.md](docs/proposals/2026-09-weekend-protocol-proposal.md) | Technical write-up for Sierra review | -| [protocol/companions/0.3-draft/](protocol/companions/0.3-draft/) | Companion objects, closed schemas, examples, Drive close page | +| [protocol/companions/0.3-draft/](protocol/companions/0.3-draft/) | Companion objects, closed schemas, examples | | [test-vectors/cl-pass/VECTORS.md](test-vectors/cl-pass/VECTORS.md) | Required T01–T10 oracles (schema-valid JSON is not a pass) | -Closed Drive records: [0.3 companion close](https://docs.google.com/document/d/19ZNUrP3zCxRxbXvQ-0EBV9MKuMcJbkKXLKp58MTHtUA/edit) · [CL-Pass vectors](https://docs.google.com/document/d/1NGbs7kSk__BtxwkjP-BhMKe_5A99phNVCFA3ICj7nw8/edit). - ## Security and licensing Report vulnerabilities through [GitHub private vulnerability reporting](https://github.com/sierracatalina/context-layer/security/advisories/new); do not post exploit details in a public issue. diff --git a/docs/proposals/2026-09-weekend-protocol-proposal.md b/docs/proposals/2026-09-weekend-protocol-proposal.md index c5fb463..380118d 100644 --- a/docs/proposals/2026-09-weekend-protocol-proposal.md +++ b/docs/proposals/2026-09-weekend-protocol-proposal.md @@ -71,7 +71,7 @@ Companion pack: [`protocol/companions/0.3-draft/`](../../protocol/companions/0.3 | `claim_annotation` | Rides beside claims until a 0.3 core revision. Evidence labels MUST NOT be upgraded. | | `memory_category` | Closed enum: `preference` \| `fact` \| `project` \| `instruction` | -Companion schemas, examples, README, spec, and T01–T10 vectors live under [`protocol/companions/0.3-draft/`](../../protocol/companions/0.3-draft/) and [`test-vectors/cl-pass/VECTORS.md`](../../test-vectors/cl-pass/VECTORS.md). Do not invent types. Object names and invariants match the closed Drive record in [`DRIVE-PAGE.md`](../../protocol/companions/0.3-draft/DRIVE-PAGE.md). +Companion schemas, examples, README, spec, and T01–T10 vectors live under [`protocol/companions/0.3-draft/`](../../protocol/companions/0.3-draft/) and [`test-vectors/cl-pass/VECTORS.md`](../../test-vectors/cl-pass/VECTORS.md). Do not invent types. ### Invariants (normative for CL-Pass) @@ -127,11 +127,8 @@ Schema-valid JSON is not a pass. A CL-Pass claim MUST publish results for T01– | Companion pack | [`protocol/companions/0.3-draft/`](../../protocol/companions/0.3-draft/) | | Companion spec | [`protocol/companions/0.3-draft/spec.md`](../../protocol/companions/0.3-draft/spec.md) | | 0.2 ↔ 0.3 crosswalk | [`protocol/companions/0.3-draft/crosswalk.md`](../../protocol/companions/0.3-draft/crosswalk.md) | -| Drive close page | [`protocol/companions/0.3-draft/DRIVE-PAGE.md`](../../protocol/companions/0.3-draft/DRIVE-PAGE.md) | | T01–T10 vectors | [`test-vectors/cl-pass/VECTORS.md`](../../test-vectors/cl-pass/VECTORS.md) | | Closed Lite schemas | [`protocol/schemas/`](../../protocol/schemas/) | -| Drive close (canonical) | https://docs.google.com/document/d/19ZNUrP3zCxRxbXvQ-0EBV9MKuMcJbkKXLKp58MTHtUA/edit | -| Drive vectors (canonical) | https://docs.google.com/document/d/1NGbs7kSk__BtxwkjP-BhMKe_5A99phNVCFA3ICj7nw8/edit | ## Non-goals (this weekend cut) @@ -140,11 +137,9 @@ This proposal ships **Context Layer only**. The weekend four-protocol set is PCP Do not do any of the following in this cut: - Switchboard / Egoist adapter, SDK, OIDC, MCP, or type-name imports -- Grok Bot adapter - PCP grants - Legatus envelope - Live issuer -- ouro / Ouroboros landing - Opening the five Lite schemas - Wildcards for categories, purpose codes, or `client_instance` - Un-disclosure of already issued bundles diff --git a/protocol/companions/0.3-draft/DRIVE-PAGE.md b/protocol/companions/0.3-draft/DRIVE-PAGE.md deleted file mode 100644 index ec660da..0000000 --- a/protocol/companions/0.3-draft/DRIVE-PAGE.md +++ /dev/null @@ -1,61 +0,0 @@ -# CLOSED Context Layer 0.3-draft companions (CL-Pass) — 2026-08-29 - -Landed from the closed Drive record. Canonical URL: - -https://docs.google.com/document/d/19ZNUrP3zCxRxbXvQ-0EBV9MKuMcJbkKXLKp58MTHtUA/edit - -CLOSED 2026-08-29 by DaddyBot. - -Context Layer — `context-layer/0.3-draft` companion addendum (CL-Pass) - -0.2 Lite schemas remain closed. No PCP grants. No Legatus. No live issuer. No ouro. - -Canonical pack (schemas + examples + spec.md): upload as `context-layer-0.3-companions.zip` in the same Drive folder. Coordinator pack for this weekend ship is the base64 gzip tar (md5 `6052995f6e54a874a6dd18cfc41da3ff`). Empty truncated stub from a blocked upload was renamed: `EMPTY STUB ignore — Context Layer 0.3 (blocked upload)`. Do not treat that stub as the spec. - -## Objects (companion only) - -`identity_assertion`, `client_pairing`, `context_pass`, `approval_handle`, `lifecycle_event`, `claim_annotation`, plus closed enum `memory_category` (`preference` | `fact` | `project` | `instruction`). - -All use `spec_version` `context-layer/0.3-draft` and `additionalProperties: false`. They are not Lite patches. - -## Closed 0.2 Lite (do not open) - -`context_request`, `policy_decision`, `scoped_context_bundle`, `memory_update_proposal`, `receipt`. - -## Invariants (normative for CL-Pass) - -1. Identity is not a context grant. `identity_assertion.context_grant` MUST be `false`. Authenticating a principal MUST NOT disclose vault claims. -2. Identity-only consumers MUST NOT be treated as authorized to submit a disclosing `context_request` and MUST NOT be issued a `scoped_context_bundle`. -3. Pairing is not a pass. `client_pairing` admits an exact `client_instance` only. -4. Unpaired clients MUST get `deny` or `needs_approval`. -5. A pass is necessary, not sufficient. Every disclosure still requires 0.2 `context_request` → `policy_decision` → `scoped_context_bundle`. An active `context_pass` is not a bundle, wildcard selector, or ambient vault access. -6. Categories grant; predicates select. Pass grants `memory_category` values. Request still names `{ predicate }` selectors. Off-pass category MUST be denied or `needs_approval` for the exact request. -7. Ask is not read. `needs_approval` is a successful protocol outcome. `approval_handle` MUST NOT include denied claim values, claim text, or vault payloads. -8. Write approval is not a read pass. Committing a `memory_update_proposal` MUST NOT mint or widen a `context_pass`. -9. Revocation is prospective. Revoking a pass or pairing MUST prevent future bundles. It cannot un-disclose issued bundles. -10. Lifecycle events carry no content. `payload_included` MUST be `false`. -11. Evidence labels MUST NOT be upgraded. `inferred` MUST NOT be disclosed as `stated_by_user` or `direct_user_save`. -12. Public profile is not the vault. Visibility `vault` MUST NOT appear on a public profile. - -## Flow - -`identity_assertion` (not a grant) → `client_pairing` (exact `client_instance`) → `context_pass` (categories + purpose codes) → 0.2 request/decision/bundle. `needs_approval` returns `approval_handle` as success. Proposal commit MUST NOT mint a pass. `lifecycle_event` is content-free beside receipts. `claim_annotation` rides beside claims until a 0.3 core revision. - -## Non-goals - -No Egoist/Switchboard adapter. No Grok Bot adapter. No PCP grants. No Legatus envelope. No live issuer. No ouro landing. No wildcards for categories, purpose codes, or `client_instance`. No un-disclosure of issued bundles. - -## Required tests (pack must publish results; schema-only is insufficient) - -1. Reject vault disclosure when only `identity_assertion` is present. -2. Unpaired `client_instance`: `deny` or `needs_approval` without claim values. -3. `purpose_code` absent from pass: reject. -4. Off-pass category: deny; denied claim text absent from handle and bundle. -5. Later on-pass read still requires a new `context_request` and `policy_decision`. -6. Proposal commit does not create or widen a `context_pass`. -7. Revoked pass cannot obtain a later bundle. -8. `lifecycle_event` serializes `payload_included` false with no claim text. -9. `inferred` is not emitted as `stated_by_user`. -10. Visibility `vault` is absent from public-profile export. - -Board: CLOSED. Next job for Context Layer is assigned separately. diff --git a/protocol/companions/0.3-draft/spec.md b/protocol/companions/0.3-draft/spec.md index 288593a..4ab8ce9 100644 --- a/protocol/companions/0.3-draft/spec.md +++ b/protocol/companions/0.3-draft/spec.md @@ -443,11 +443,9 @@ Schema-valid JSON is not a pass. A `CL-Pass` claim MUST publish results for T01 ## 9. Non-goals - Not an Egoist AI Passport or Switchboard adapter, subset, client, or type import. Observation is recorded in [crosswalk.md](crosswalk.md); that is not adoption. -- No Grok Bot adapter - No PCP grants - No Legatus envelope - No live issuer -- No ouro / Ouroboros landing - No wildcards for categories, purpose codes, or `client_instance` - No un-disclosure of issued bundles - No opening of the five Lite schemas diff --git a/protocol/companions/0.3-draft/whiteboard-capture-recipe.md b/protocol/companions/0.3-draft/whiteboard-capture-recipe.md deleted file mode 100644 index 88c6979..0000000 --- a/protocol/companions/0.3-draft/whiteboard-capture-recipe.md +++ /dev/null @@ -1,92 +0,0 @@ -# Context Layer — Whiteboard Daddy capture recipe - -status: working draft · not a new spec card -audience: Whiteboard Daddy (draws). Context Layer owns whether a record is well-formed. -published: 2026-08-29 -revised: 2026-08-29 (completed-items addendum) -board folder: https://drive.google.com/drive/folders/15lt1Ow-uwAxu1zQ6OW9OVup4YFWDqHN6 -0.3 close: https://docs.google.com/document/d/19ZNUrP3zCxRxbXvQ-0EBV9MKuMcJbkKXLKp58MTHtUA/edit -0.2 Lite: CLOSED. No C009. No Switchboard adapter. No ouro. No live vault. No live issuer. - -You draw. You do not mint identity_assertion, context_pass, client_pairing, or scoped_context_bundle. - -## Per frame (minimum) - -After every new or changed board image: - -1. Persist the PNG (or webp) in the board folder. Do not remove earlier frames. -2. Hash the file bytes. artifact_hash = sha256: plus 64 lowercase hex. Not a thumbnail. Not OCR text. -3. Emit one 0.2 memory_update_proposal with status pending_approval. Do not commit it. Committing would be a live vault write. -4. Emit one 0.3 claim_annotation for each proposed claim. Do not patch 0.2 claim objects. -5. Stop. Do not issue a pass. Do not issue identity. Do not dump pixels into a vault claim. - -### Required fields on the proposal (closed 0.2 members only) - -spec_version: context-layer/0.2-draft -type: memory_update_proposal -operation: add -status: pending_approval -purpose_code recorded beside the file: x.board.capture -proposed_claims predicate: a 0.2 selector (e.g. project.board.frame) -proposed_claims object.value: the artifact_hash only -proposed_claims object.datatype: text -provenance_refs: optional opaque urn; MUST NOT be raw pixels -approval_requirement: user_confirm - -Do not add extra Lite fields. The image stays in Drive. The protocol record carries the hash. - -### Required fields on the annotation (closed 0.3) - -spec_version: context-layer/0.3-draft -type: claim_annotation -evidence_basis: derived (from the image) unless Sierra explicitly stated the box text, then stated_by_user -visibility: vault -category: project -attribution.via_principal: urn of Whiteboard Daddy as actor, not a grant -attribution.captured_at: RFC3339 - -Public profile MUST NOT include these frames. - -## Completed items (addendum) - -A completed box stays on the artifact. Never a delete. - -- Strikethrough is ink. It is not erasure. Do not trash the PNG. Do not drop the prior proposal. Do not emit a 0.2 delete. -- Open and completed must both be indexed. Keep the open-frame hash and its pending add. When the board is redrawn with strikethrough (or other done marks), persist that as a new frame, new hash, new pending add, new claim_annotation (same closed fields: derived, vault, project). -- Both hashes remain in the folder. The later frame still contains the completed item in pixels. -- Same closed types as an open capture. No new object. No new operation name. - -### Completed is not a lifecycle_event — STOP - -Closed 0.3 lifecycle_event.operation is only: - -pass.issued | pass.revoked | pairing.revoked | proposal.committed | bundle.issued | bundle.expired - -There is no item.done, box.complete, or done. claim_annotation has no open/completed field (evidence_basis, visibility, category, attribution only). - -Do not emit lifecycle_event for a completed box. proposal.committed would be a live vault lie. pass.issued is a grant. - -Closed page that would have to be extended: Context Layer 0.3 companion addendum, section 5.7 -https://docs.google.com/document/d/19ZNUrP3zCxRxbXvQ-0EBV9MKuMcJbkKXLKp58MTHtUA/edit - -DaddyBot opens cards. Until then: completed = new frame + claim_annotation + pending add of the new hash. Prior frame stays indexed. - -## What you do not emit - -identity_assertion, client_pairing, context_pass, scoped_context_bundle (no disclosure job unless DaddyBot assigns one), lifecycle_event with any new operation name. - -Receipts: only if a later 0.2 disclosure actually happens (then receipt with payload_included false and input_digest equal to the artifact_hash). Do not invent a frame.capture receipt operation. - -## Box add / move / erase — STOP - -Same closed enum as above. There is no box.add, box.move, or box.erase. - -Until a card: a box change is a new frame. New image, new hash, new pending proposal. The PNG is the source of truth. Do not mint box lifecycle types. Completing a box is not erase. - -## Disclosure back (only if assigned) - -If something on the board must be read from the vault into a later frame, that is a 0.2 context_request to policy_decision to scoped_context_bundle. Whiteboard Daddy is not the issuer. You still do not mint a pass. - -## One-line contract - -Hash the frame. Propose the hash. Annotate it. Leave it pending. Never a live vault. Never a delete. Open and completed both stay indexed. Strikethrough is not erasure. diff --git a/test-vectors/cl-pass/VECTORS.md b/test-vectors/cl-pass/VECTORS.md index f9d56ec..3780301 100644 --- a/test-vectors/cl-pass/VECTORS.md +++ b/test-vectors/cl-pass/VECTORS.md @@ -5,11 +5,10 @@ profile: CL-Pass spec: context-layer/0.3-draft companion addendum relates to: context-layer/0.2-draft CL-Core-Lite (CLOSED) published: 2026-08-29 -close record: https://docs.google.com/document/d/19ZNUrP3zCxRxbXvQ-0EBV9MKuMcJbkKXLKp58MTHtUA/edit 0.2 Lite schemas stay closed. These vectors do not add fields to `context_request`, `policy_decision`, `scoped_context_bundle`, `memory_update_proposal`, or `receipt`. Schema-valid JSON is not a pass. Each test names an oracle that must fail if the invariant is broken even when every object validates. -No PCP grants. No Legatus. No live issuer. No ouro. +No PCP grants. No Legatus. No live issuer. ## How to run From 2a054bb2f5c905305e41aa7e43ccef12e5dd2ad8 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 14 Sep 2026 19:28:24 +0000 Subject: [PATCH 4/5] Scrub process voice from the 2026-09 protocol proposal Drop weekend-ship and Sierra-review queue labels, rename the proposal file, and keep CL-Core-Lite closed-schema language without ALL-CAPS theater. Co-authored-by: sierra --- CHANGELOG.md | 2 +- LICENSING.md | 4 ++-- README.md | 8 ++++---- ...ocol-proposal.md => 2026-09-protocol-proposal.md} | 12 ++++++------ test-vectors/cl-pass/VECTORS.md | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) rename docs/proposals/{2026-09-weekend-protocol-proposal.md => 2026-09-protocol-proposal.md} (94%) diff --git a/CHANGELOG.md b/CHANGELOG.md index eeb5633..06a3635 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This file records material changes to the Context Layer working draft and its pu ## Unreleased -- Add the 2026-09 weekend protocol proposal: closed 0.2 Lite remains authoritative; `context-layer/0.3-draft` CL-Pass companions and T01–T10 vectors sit beside it for Sierra review. +- Add the 2026-09 protocol proposal: closed 0.2 Lite remains authoritative; `context-layer/0.3-draft` CL-Pass companions and T01–T10 vectors sit beside it. - Confirm the dual-license boundary and contribution terms before publishing the first proof-of-work prerelease. - Populate the canonical protocol-only GitHub repository from the reviewed release commit. - Consolidate specification, reference, schema, and fixture artifacts under the explicit `protocol/` boundary; keep website and deployment source outside this repository. diff --git a/LICENSING.md b/LICENSING.md index db6768c..368fa79 100644 --- a/LICENSING.md +++ b/LICENSING.md @@ -29,8 +29,8 @@ Website application, hosting, and deployment source are intentionally outside th If a file combines executable software with embedded explanatory prose and is not explicitly listed in the documentation section, Apache-2.0 applies to the whole file. Third-party dependencies, quoted standards text, linked external material, trademarks, and generated dependency notices remain governed by their own terms. -## Protocol proposal (weekend ship) +## Protocol proposal (2026-09) -The 2026-09 weekend protocol proposal and `protocol/companions/0.3-draft` companion materials are part of this repository. Schemas, examples, and other executable companion artifacts use Apache-2.0. Proposal prose, companion specification pages, and `test-vectors/cl-pass/VECTORS.md` use CC BY 4.0. This note does not relicense the existing v0.2 product or replace `LICENSE` / `LICENSE-DOCS`. +The 2026-09 protocol proposal and `protocol/companions/0.3-draft` companion materials are part of this repository. Schemas, examples, and other executable companion artifacts use Apache-2.0. Proposal prose, companion specification pages, and `test-vectors/cl-pass/VECTORS.md` use CC BY 4.0. This note does not relicense the existing v0.2 product or replace `LICENSE` / `LICENSE-DOCS`. No license grants trademark rights or implies endorsement, protocol adoption, production readiness, security certification, or warranty. diff --git a/README.md b/README.md index b5647ae..e32e2bf 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ This is the canonical public repository for both the protocol and its published - [Experimental local core](packages/local-core/) - [Threat model](docs/context-layer-threat-model.md) - [Executable v0.2 vectors](test-vectors/v0.2/) -- [Weekend protocol proposal (0.2 Lite + 0.3 CL-Pass)](docs/proposals/2026-09-weekend-protocol-proposal.md) +- [2026-09 protocol proposal (0.2 Lite + 0.3 CL-Pass)](docs/proposals/2026-09-protocol-proposal.md) ## Protocol flow @@ -108,13 +108,13 @@ npx vercel dev site The repository test suite verifies that all published routes and their required assets remain present. Changes to public copy or design should be made here first so the repository and live documentation cannot silently diverge. -## Protocol proposal (weekend ship) +## Protocol proposal (2026-09) -The 2026-09 weekend cut keeps `CL-Core-Lite` closed and adds a reviewable `context-layer/0.3-draft` companion pack (CL-Pass) beside it. This does not open the five Lite schemas or mint a live issuer. +The 2026-09 proposal keeps `CL-Core-Lite` closed and adds a reviewable `context-layer/0.3-draft` companion pack (CL-Pass) beside it. This does not open the five Lite schemas or mint a live issuer. | Path | Purpose | | --- | --- | -| [docs/proposals/2026-09-weekend-protocol-proposal.md](docs/proposals/2026-09-weekend-protocol-proposal.md) | Technical write-up for Sierra review | +| [docs/proposals/2026-09-protocol-proposal.md](docs/proposals/2026-09-protocol-proposal.md) | Technical write-up (working draft) | | [protocol/companions/0.3-draft/](protocol/companions/0.3-draft/) | Companion objects, closed schemas, examples | | [test-vectors/cl-pass/VECTORS.md](test-vectors/cl-pass/VECTORS.md) | Required T01–T10 oracles (schema-valid JSON is not a pass) | diff --git a/docs/proposals/2026-09-weekend-protocol-proposal.md b/docs/proposals/2026-09-protocol-proposal.md similarity index 94% rename from docs/proposals/2026-09-weekend-protocol-proposal.md rename to docs/proposals/2026-09-protocol-proposal.md index 380118d..8e151e6 100644 --- a/docs/proposals/2026-09-weekend-protocol-proposal.md +++ b/docs/proposals/2026-09-protocol-proposal.md @@ -1,15 +1,15 @@ -# Context Layer — weekend protocol proposal +# Context Layer — 2026-09 protocol proposal | Field | Value | | --- | --- | -| Status | Reviewable proposal for Sierra Catalina — not an adopted standard | +| Status | Working draft — not an adopted standard | | Date | 2026-09-13 | | Closed Lite | `context-layer/0.2-draft` CL-Core-Lite | | Companion profile | `context-layer/0.3-draft` CL-Pass | | Repo | https://github.com/sierracatalina/context-layer | | License | Existing repository boundary (Apache-2.0 software / CC BY 4.0 prose). This proposal does not relicense v0.2. | -This is the weekend ship write-up. It states what is already closed, what the 0.3 companions add beside Lite, and what this cut does not do. +This is the 2026-09 proposal write-up. It states what is already closed, what the 0.3 companions add beside Lite, and what this proposal does not do. ## What Context Layer is @@ -130,11 +130,11 @@ Schema-valid JSON is not a pass. A CL-Pass claim MUST publish results for T01– | T01–T10 vectors | [`test-vectors/cl-pass/VECTORS.md`](../../test-vectors/cl-pass/VECTORS.md) | | Closed Lite schemas | [`protocol/schemas/`](../../protocol/schemas/) | -## Non-goals (this weekend cut) +## Non-goals -This proposal ships **Context Layer only**. The weekend four-protocol set is PCP · Context Layer · Legatus · AAA. The other three are out of this repository. +This proposal covers **Context Layer only**. Related protocols outside this repository: PCP · Legatus · AAA. -Do not do any of the following in this cut: +Do not do any of the following in this proposal: - Switchboard / Egoist adapter, SDK, OIDC, MCP, or type-name imports - PCP grants diff --git a/test-vectors/cl-pass/VECTORS.md b/test-vectors/cl-pass/VECTORS.md index 3780301..e0ad1bc 100644 --- a/test-vectors/cl-pass/VECTORS.md +++ b/test-vectors/cl-pass/VECTORS.md @@ -3,7 +3,7 @@ status: working draft · not an adopted standard profile: CL-Pass spec: context-layer/0.3-draft companion addendum -relates to: context-layer/0.2-draft CL-Core-Lite (CLOSED) +relates to: context-layer/0.2-draft CL-Core-Lite published: 2026-08-29 0.2 Lite schemas stay closed. These vectors do not add fields to `context_request`, `policy_decision`, `scoped_context_bundle`, `memory_update_proposal`, or `receipt`. Schema-valid JSON is not a pass. Each test names an oracle that must fail if the invariant is broken even when every object validates. From d70e82abcd135010d121057ede69c59589cf1d30 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 14 Sep 2026 19:30:17 +0000 Subject: [PATCH 5/5] Finish 2026-09 proposal meta-voice wording Use product-neutral non-goals for out-of-scope protocols and mark the changelog entry as a working draft. Co-authored-by: sierra --- CHANGELOG.md | 2 +- docs/proposals/2026-09-protocol-proposal.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06a3635..7d675d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This file records material changes to the Context Layer working draft and its pu ## Unreleased -- Add the 2026-09 protocol proposal: closed 0.2 Lite remains authoritative; `context-layer/0.3-draft` CL-Pass companions and T01–T10 vectors sit beside it. +- Add the 2026-09 protocol proposal as a working draft: closed 0.2 Lite remains authoritative; `context-layer/0.3-draft` CL-Pass companions and T01–T10 vectors sit beside it. - Confirm the dual-license boundary and contribution terms before publishing the first proof-of-work prerelease. - Populate the canonical protocol-only GitHub repository from the reviewed release commit. - Consolidate specification, reference, schema, and fixture artifacts under the explicit `protocol/` boundary; keep website and deployment source outside this repository. diff --git a/docs/proposals/2026-09-protocol-proposal.md b/docs/proposals/2026-09-protocol-proposal.md index 8e151e6..edbbba5 100644 --- a/docs/proposals/2026-09-protocol-proposal.md +++ b/docs/proposals/2026-09-protocol-proposal.md @@ -132,7 +132,7 @@ Schema-valid JSON is not a pass. A CL-Pass claim MUST publish results for T01– ## Non-goals -This proposal covers **Context Layer only**. Related protocols outside this repository: PCP · Legatus · AAA. +This repository ships Context Layer only. PCP, Legatus, and AAA are out of scope for this change. Do not do any of the following in this proposal: