**Note** from Bead: 31bd5380 · [canonical source](https://redfish.acequia.io/guerin/.agents/31bd5380-d743-420f-81a1-9258e7fbbf9a/2026-06-03/notes/user-representation-vocabulary.md) · session 2026-06-03 · discussion: Talk: 31bd5380
> **Read first: [URI as the Primitive, Identity as Derivative](https://redfish.acequia.io/guerin/.agents/31bd5380-d743-420f-81a1-9258e7fbbf9a/2026-06-03/notes/uri-as-primitive.md)** (added 2026-06-03, turn 32). > > That note re-anchors the entire frame: capabilities at URIs are primary; identities (person, org, AI agent) are *named bundles of URI capabilities*, not first-class entities. Anonymous participation becomes the default. This vocabulary note still uses identity-centric structure for readability (and to map cleanly to SaaS-conventional readers), but the **canonical anchor is URI-primary**. Where the two framings disagree, the URI-primary note wins. This document defines the **identity, user, and participant vocabulary** for the Acequia ecosystem. It is a sibling/refinement of Gemini's [user-representation-vocabulary.md](https://redfish.acequia.io/guerin/.agents/9e1d87f5-a226-4d1a-be05-64c8d5cacf38/2026-06-03/notes/user-representation-vocabulary.md). Tensions between the two readings are surveyed in [vocabulary-tension-claude-vs-gemini.md](https://redfish.acequia.io/guerin/.agents/31bd5380-d743-420f-81a1-9258e7fbbf9a/2026-06-03/notes/vocabulary-tension-claude-vs-gemini.md). **Note on the central distinction:** the vocabulary makes a strict separation between *persistent identities* (the URI-addressable entities — person, organization, AI agent) and *relationships* (the bindings between identities, including **user-of-org** and **participant-of-session**). Earlier drafts of this note collapsed "user" and "participant" into one concept; Stephen's Zoom anchor clarified the distinction: a user is someone with a seat under an org's subscription account; a participant is someone in a session, who may or may not be a user of any org. Both terms are now in the vocabulary with their narrow meanings. **Note on canonical-platform alignment** (added 2026-06-03 after reading [`acequia.io/documentation/platform/user-authentication.md`](acequia.io/documentation/platform/user-authentication.md), `architecture-overview.md`, and the sibling-bead [`chain-tokens-and-oauth.md`](https://redfish.acequia.io/guerin/.agents/9242fee3-0f2c-43a6-a506-8be19efe004a/2026-06-03/notes/chain-tokens-and-oauth.md)): the canonical platform has its own vocabulary in production. Where this note's terms align with the platform, that's noted inline. Where this note proposes a Document-A extension not currently in the platform, it's marked **[Proposed extension]**. Most notably: - The platform's role model is `owner / editor / viewer / pending` per-subdomain; this note's "host (role)" / "co-host" / "session host" model is a **[Proposed extension]** for the session vocabulary. - The platform's identity model is "users registered on a subdomain"; this note's split into "person identity + user-of-org relationship-binding" is a **[Proposed extension]** that clarifies the Zoom-anchor distinction. - The platform represents non-human identities (apps, mayordomos, automation) as **named API tokens issued by a user** — not as separate identity types. This note's "AI agent" persistent-identity entry is a **[Proposed extension]** that points at the same operational need. - "Application as a fourth persistent identity" was an earlier over-extrapolation in this note. **Removed.** Applications are resources (owned by an identity) with named API tokens, not a separate identity class. See "Application" entry in Other Terms.
## Persistent Identities **Frame note** (added 2026-06-03 after [uri-as-primitive.md](https://redfish.acequia.io/guerin/.agents/31bd5380-d743-420f-81a1-9258e7fbbf9a/2026-06-03/notes/uri-as-primitive.md)): these are **named bundles of URI capabilities**, *not* first-class entities. The URI is the address at which capabilities accumulate; the "person Jane" is the convergence of capabilities reachable from `/people/jane-smith/`. Names are for human convenience; the cryptographic reality is "which capabilities are currently held." That said, identity-URIs are conventional and useful — most participation accumulates against one. The entries below define the three conventional identity-bundles; see [uri-as-primitive.md](https://redfish.acequia.io/guerin/.agents/31bd5380-d743-420f-81a1-9258e7fbbf9a/2026-06-03/notes/uri-as-primitive.md) for the deeper frame including anonymous participation (capability exercised without an identity URI). These are the URI-addressable identity-bundles. All three hold bindings, have audit logs at `<identity-URI>/audit/`, can hold roles in scopes, and are subject to apoptotic lifecycle. - **Person** — individual human; cryptographic identity backed by **device keys** (PS256 keypair per registered device in the current Acequia substrate). URI convention: `/people/<handle>`. A person exists in the system as a person regardless of any org memberships. - **Organization** — collective with a **subscription account** (the billing relationship that funds the platform). Acts through its **users** (people with seats under it) and its **mayordomo** (the autonomous AI agent at the org URI). URI convention: `/orgs/<slug>`. - **AI agent** — autonomous AI entity at its own URI. **[Proposed extension]** — the canonical platform doesn't currently have a distinct AI-agent identity class; AI agents are operationally represented as **named API tokens** issued by a user (the owner). The proposed extension promotes them to first-class identities. For AI-agent identities under the proposed extension, the agent **is its own mayordomo** at its URI — no separation between identity and policy coordinator. URI convention: `/agents/<name>` or under a host org's `/agents/`. The bead system at `redfish.acequia.io/guerin/.agents/<GUID>/` operates this pattern at the agent-bead level — each bead is an agent identity-URI in practice, even though the underlying authentication today uses tokens issued by the bead's parciante (Stephen).
## Relationships (bindings between identities, and to sessions/groups/resources) Relationships are **bindings** — URI → URI references with metadata (scope, TTL, role, attenuation). The two most important relationships in the user-rep layer: - **User** — a person (or AI agent) holding a **seat under an organization's subscription account**. Not a kind of identity; a binding `<person-URI>` ↔ `<org-URI>` with seat metadata (the subscription seat itself, role-bundle on the seat, quotas, billing flags). "User of SFD" = the binding `(person:jane-smith ↔ org:sfd)` with seat properties. The Zoom anchor: a user of an org's Zoom account is someone with a seat under that org's Zoom billing — different from "someone in a Zoom meeting." A person can be a user of zero, one, or many orgs simultaneously. **Naming divergence from Zoom (intentional):** Zoom overloads "user" — a free Zoom account holder is also called a "user." This spec **reserves "user" for the org-seat binding** to disambiguate. A person with a free account who hasn't joined any org is just a **person** here, with the base capacity of the free tier (see Capacity below). Calling such a person a "user" in this spec would re-conflate identity with relationship — exactly the bug Stephen's Zoom-anchor correction caught. - **Participant** — a person (or AI agent) **in a session**. Not a kind of identity; a binding `<person-or-agent-URI>` ↔ `<session-URI>`. The Zoom anchor: participants are everyone in the meeting, regardless of whether they're a user of the hosting org's account. A participant **does not need to be a user** of any org. The session's host is a participant who additionally holds the host role. **Organizations are not participants** — orgs don't physically attend sessions; their users do on their behalf. Other relationship bindings: - **Member of group** — a person/agent/org holding a binding to a group. Lighter-weight than a user-binding (no necessary subscription seat). - **Federation** — an org-to-org binding for resource sharing or cross-org representation. - **Friend / contact** (if needed) — a person-to-person binding for direct sharing.
## Roles (properties of relationship bindings) Roles are **metadata on a binding** indicating what rights and responsibilities the binding carries. Not separate kinds of entities; not separate kinds of bindings. - **Host** — the role on the participant-of-session binding for the person/agent currently holding session-management authority. Exactly one per session at any moment. Authority: configure session-level settings, invite participants, promote to co-host, transfer host, end session. Zoom anchor: the meeting host. Inherits from effort 1.1. **Anyone can host.** Hosting does NOT require a user-of-org binding. Any person identity (with the free tier's base capacity) can claim a session and host it within free-tier limits. Becoming a user of an org just unlocks higher capacity (longer sessions, more participants, premium features — see Capacity below). AI-agent identities can also host. This matches Zoom: a free Zoom account can host up to N participants for up to M minutes; beyond that you need premium (personally or via an org seat). **Host can be acquired two ways:** - **Claim** — an eligible participant binds themselves as host (the typical flow for ephemeral sessions; first-person-through-the-door pattern). - **Election** — when no host is present (typical case for persistent session URIs whose previous host has left or never claimed), eligible participants are elected from a configured pool. Zoom anchor: alternative-host configuration, claim-host-when-no-host-present. AnyHazard examples: a recurring training-exercise room with a rotating-host roster; a public kiosk session with a "first eligible participant becomes host" default. Election mechanism is policy at the session URI (`<S>/policy/host-election`) — could be first-come (de facto election), pool-with-rotation, consensus among current participants, or external-trigger (the org admin pre-designates). The two modes coexist: a session URI can support both claim and election, with election as the fallback when no claim is in flight. - **Co-host** — a role on a participant-of-session binding **assigned by the host** (or by another co-host with sufficient rights). Zoom anchor: same idea. Multiple co-hosts per session allowed. Carries most session-management rights *except* (typically) removing the host or ending the session permanently. - **Host transfer** — the host moves the host role to another participant (typically a co-host) before exiting the session. Atomic operation; old host's role-binding gone, new host's role-binding established, audit-logged. - **Role-binding election** (general pattern) — orderly succession mechanism for any persistent role-binding when the current holder leaves or is absent. Eligible candidates are elected from a configured pool by a configured mechanism (first-come, rotation, consensus, external-trigger). Instances of this pattern: - **Host election** on persistent session URIs (just above) - **Mayordomo succession** for an org (effort-1 §F3.7 — N-of-M of designated successors) - **URI host fallback** when an origin host fails and a pinned-participant takes over canonical service - **Co-host promotion** when a host needs to step down without a direct transfer All four are the same structural pattern at different scopes. Implementation backing (consensus protocol, vote tally, threshold signature) is Document B; the user-vocab term is "election." - **Owner / Admin / Editor / Viewer** — roles on **user-of-org** bindings. Determine what subtrees of the org's namespace the user can access and at what scope. Note: these are roles on *user* bindings (the seat-relationship to the org), not on participant bindings (session-relationship). The pitch's effort-1 §3.3 puts these in the org-management area, which matches. - **Pending** — a transitional role on a user-binding indicating the seat is pre-approval (self-registered, awaiting admin approval). - **Mayordomo (governance role)** — a senior org-governance role held by one or more *users* (typically a small N with N-of-M succession per effort-1 §F3.7). The human counterpart of the mayordomo-as-agent concept. This is the parciante holding the ditch-boss role per NM acequia tradition. - **Mayordomo (agent)** — the AI agent at an org's URI that mediates policy autonomously. For AI-agent identities, the agent IS its own mayordomo at its URI. - **Owner (role / relationship)** — the identity (person/org/agent) with full control of a resource. See "Ownership and Permissions on Resources" below for full treatment. An identity can own many resources; a resource has exactly one owner at a time; ownership is transferable.
## Other Terms (not identities, not relationships, not roles) - **Observer** — present in the room/scope but **not authenticated**. Has no participant-binding for the session; doesn't appear in the session log; watches what's rendered. Inherits from effort 1.1. - **Anonymous participant** — exercises a capability at a URI without holding (or revealing) a persistent identity-URI. The participant exists in the moment of exercising the capability; the system has no persistent handle for them. **Not "guest mode"** — guest mode creates a temporary identity; anonymous participation requires *no identity at all*. The capability is in the URI's policy (e.g., `<event>/policy/submission-mode = "open"`); the exerciser holds nothing persistent. Worked example: a bystander submitting a phone-photo URI to an event's `submissions/` endpoint. See [uri-as-primitive.md](https://redfish.acequia.io/guerin/.agents/31bd5380-d743-420f-81a1-9258e7fbbf9a/2026-06-03/notes/uri-as-primitive.md) for the full pattern + operations table. - **Device** — hardware a person uses (laptop, phone, tablet, Simtable). Has its own keypair; bound as a sub-URI under a person identity (or under an org for org-owned hardware). Devices are NOT identities — they don't hold rights independently; they serve the identity URI they're bound under. - **Resource** — any addressable thing identities can read, write, share, or act on: **layer, scenario, progression, dataset, model, session, message, policy surface**, and also **live/dynamic resources** like simulations, cameras, sensors, running processes. Every resource has a URI. Two kinds: - **Static resource** — content is stored; GET returns the stored content. Most layers, scenarios, files. Cacheable, mirrorable, pinnable in conventional ways. - **Dynamic / live resource** — content is generated at request time or reflects live state. Simulations, cameras, sensors, processes, streams (see "Dynamic Resources / Live URIs" section below). Hosting and caching have different semantics. - **Session** — a bounded period of multi-participant interaction at a device (typically a Simtable). Sessions are URIs with sub-resources: `host`, `co-hosts/`, `participants/`, `imports/`, `audit/`. Apoptotic lifecycle — `DELETE`/`PROPPATCH state=ended` cascades through bindings. Two kinds: - **Ephemeral session URI** — one-shot; URI exists only for the session's duration. The typical Simtable session today. - **Persistent session URI** — exists at a known URL across time; host role is dynamic (can be claimed and re-claimed by different hosts over many sessions at the same URL). Zoom anchor: personal meeting rooms, recurring meetings, alternative-host configuration. AnyHazard examples: a standing weekly fire-department briefing room URL, a public-information kiosk URL, a recurring training-exercise room. - **Group (collaboration sense — this vocabulary)** — a lighter-weight collaboration container than an organization. URI: `/groups/<slug>` or `<org-URI>/groups/<slug>`. Identities hold member-of-group bindings. **Disambiguation:** the canonical Acequia platform uses "group" with a *different* meaning — a **runtime peer cohort** (a collection of browser tabs / nodes that have joined a WebSocket-mediated discovery group for peer-to-peer messaging). The two senses share the word but not the meaning. When writing for an audience that knows the platform, qualify as **collaboration group** vs **peer group** (or **runtime group**). The pitch's groups (effort-1 §3.4) are collaboration groups; `architecture-overview.md`'s groups are peer groups. - **Application** — a software service that runs in the namespace and acts in the system. Examples: AnyHazard, realtime.earth, alert.live, the simtable software. **Applications are resources** (owned by an identity — typically an org, sometimes a person) and authenticate via **named API tokens** issued by their owner. The platform doesn't currently model applications as a distinct identity type; an earlier draft of this note over-extrapolated to "Application as a fourth persistent identity," which is **removed**. The operational answer to "how does an app present identity?" is: the app holds an API token issued by its owner, with a name like `<scope>-<app-purpose>` indicating what it represents. See the "Naming convention for non-human-identity API tokens" section under Tokens. - **Account** (account-layer concept) — the billing entity that holds a subscription to higher-tier platform-infrastructure services. Owned by one or more **admins**. Has a member roster (users), service entitlements, billing contact, quotas, audit log. Two kinds: **personal account** (owned by one admin, who is also its user) and **organization account** (owned by one or more admins with a roster of users). The account is what funds backup, TURN-server, transactions-between-participants, subdomain/domain management, reverse proxying, and other for-pay services. **Account is a separate layer from participant** — participants don't need accounts; only when they need account-funded services do they become users of an account. Full treatment in [account-layer.md](https://redfish.acequia.io/guerin/.agents/31bd5380-d743-420f-81a1-9258e7fbbf9a/2026-06-03/notes/account-layer.md). - **Admin** (account-layer role) — manages an account: subscription tier, member management (adding/removing users), service allocation (which users get which services), billing contact, audit oversight. Plural admins per account are normal (N-of-M succession). **Admin is NOT a participant-layer role** — a person doesn't become an admin by accumulating session-host roles or owning resources at the participant layer. Admin is *only* about account management.
## URI Frame (the structural commitment) **Every addressable thing in the system has a URI.** Identities, devices, sessions, organizations, groups, resources, policy surfaces, and the **bindings between them** are all URIs. Operations are HTTP verbs on URIs. ### URI patterns **Persistent identities:** ``` https://anyhazard.acequia.io/people/jane-smith # person identity https://anyhazard.acequia.io/orgs/sfd # organization identity https://anyhazard.acequia.io/agents/wildfire-modeler-v2 # AI-agent identity https://anyhazard.acequia.io/orgs/sfd/agents/incident-triage # org-scoped AI-agent identity ``` **Devices** (sub-URIs of an identity): ``` https://anyhazard.acequia.io/people/jane-smith/devices/laptop-2024 https://anyhazard.acequia.io/orgs/sfd/devices/simtable-1 ``` **User bindings** (a person or agent holds a seat under an org): ``` # from the org's perspective: https://anyhazard.acequia.io/orgs/sfd/users/jane-smith # → references /people/jane-smith # binding metadata: seat, role bundle, quotas, billing # reciprocal from the person's perspective: https://anyhazard.acequia.io/people/jane-smith/memberships/sfd # → references /orgs/sfd ``` **Participant bindings** (a person/agent is in a session): ``` https://anyhazard.acequia.io/sessions/2026-06-03T10-sfd-table-1/host # → references the host's identity URI https://anyhazard.acequia.io/sessions/2026-06-03T10-sfd-table-1/co-hosts/ # listing of co-host bindings https://anyhazard.acequia.io/sessions/2026-06-03T10-sfd-table-1/participants/ # listing of non-host participants ``` A participant who is NOT a user of the hosting org still appears here — the participant binding doesn't require a user-binding. **Federation bindings** (org-to-org): ``` https://anyhazard.acequia.io/orgs/sfd/federations/peer-fd # → references /orgs/peer-fd # binding metadata: shared resources, scope, TTL ``` **Binding** — generally, a URI → URI reference with metadata. Bindings are the **fundamental unit of relationship** in the namespace, replacing "membership," "share," "federate," "session-attach," "device-link," "ownership" as parallel concepts. One mechanism with parameters; the parameter values determine the semantics. **Mount** — a binding that composes one URI subtree into another at a specific path. Enables Plan-9-style per-caller composition. **Per-caller composition** — the same URI returns different namespaces depending on who's asking. `GET <org-URI>/` returns the public face to a non-member, the editor-visible subtree to a user with editor role, the full namespace (queue, policy, audit) to a user with admin/mayordomo role. **Capability map** — `GET <person-URI>` (or `<org-URI>` or `<agent-URI>`) with bindings expanded. Not a separate feature; the natural rendering of the identity's URI.
## Identity & Authentication - **Device key** — cryptographic keypair stored on a specific device (PS256 in the current Acequia substrate). The primary anchor for a person's identity. Term retained from Gemini's vocab. - **Process key** — long-running service identity backing AI-agent identities. Not in Gemini's vocab. - **Corporate signing key** — used by organization identities; typically delegated to a user holding the mayordomo (governance) role. - **Subdomain identity** — a person's localized profile within one subdomain. Per-subdomain segmentation preserves privacy and data sovereignty. Term retained from Gemini's vocab. - **Acequia Passport** — opt-in cross-subdomain identity unifier (Gemini's contribution, credited and retained). A person can choose to link disparate subdomain identities under a verifiable credential. - **Authentication vectors** — QR codes, short codes, signed asserts (offline). Retained from Gemini's vocab. - **Handle** — display label, not credential. Per-subdomain reservable. - **Participant panel** — the app-agnostic UI surface where a person manages their identity URI, devices, user-bindings (org memberships), participant-bindings (active sessions), and capability map.
## Access, Capabilities, & State - **Role-binding** — a relationship binding (typically user-of-org or member-of-group) with a role attached. "Editor in org X" = the user-of-org binding from a person to X with the editor role attenuation. - **Role template** — a named binding-pattern applied as a unit (e.g., "default editor seat for SFD"). Generalizes Gemini's "Capability / Role Template" (credited). Multi-app aware by construction: the "editor" template applied at `https://anyhazard.acequia.io/orgs/sfd/` produces analogous bindings to applying it at `https://alert.live/orgs/sfd/`. - **Mode (Organization vs Guest)** — a policy property at the session/table level controlled by the owning org. Determines who can be the host of a session at that table. Inherits from effort 1.1. - **Capacity** — the resource provisioning available to a given identity. **Two-layer note** (added 2026-06-03 turn 35): the free tier is **participant-layer** capacity (anonymous-capable, identity-agnostic); the other two are **account-layer** capacity (require an account, fund higher-tier platform-infrastructure services). See [account-layer.md](https://redfish.acequia.io/guerin/.agents/31bd5380-d743-420f-81a1-9258e7fbbf9a/2026-06-03/notes/account-layer.md) for the full two-layer model. Provisioned through one of three channels (in increasing capability order): - **Free tier** — the baseline capacity available to any person (or AI agent) identity without an org-user binding. Includes hosting sessions within usage limits, holding personal resources within storage quota, sharing with other identities, joining others' sessions as participant. The specific thresholds (session duration cap, participant count, storage quota, etc.) are policy decisions for the platform, not vocabulary. - **Personal premium** — a paid upgrade to a person identity's individual capacity, without org affiliation. Higher session limits, more storage, advanced features. Independent of any org. - **Org seat allocation** — capacity provisioned via a user-of-org binding. The user's session/resource activity counts against the org's subscription. Per Kaz's GitHub-model notes (effort-1 §3.3): orgs pay for repos/resources; users are free; private content / premium features require org subscription. An identity's effective capacity at any moment is the **union** of its free tier baseline + any personal premium + capacity from any user-bindings to orgs. - **Chain token** — the cryptographic backing for a binding. Implementation detail (Document B), not user-facing vocabulary. - **Inbox** — sub-URI of an identity where incoming shares/grants land. `POST` to `<identity>/inbox/` creates an incoming binding. - **Queue** — sub-URI of an org/user-with-mayordomo-role where incoming approval requests land. `PUT <owner>/queue/<req>/approval` creates the corresponding binding. - **Audit log** — sub-URI of every identity/scope (`<URI>/audit/`). Append-only record of bindings created, modified, revoked. Substrate for the advanced-wave attribution ledger.
## Tokens **Realignment note** (2026-06-03): an earlier draft of this section had a "seven kinds of token" table I invented (application / stored / invite / device-link / federation / session-attach / pinning). The canonical platform has a **three-mode detection model** (chain / user / legacy-device) plus the **API tokens (stored tokens)** UX pattern. This section now leads with the platform's model. The "seven kinds" table was over-categorization — most of those kinds are implementation patterns built ON the underlying three-mode model, not distinct token types. Full historical chain-token design is in the sibling bead's [`chain-tokens-and-oauth.md`](https://redfish.acequia.io/guerin/.agents/9242fee3-0f2c-43a6-a506-8be19efe004a/2026-06-03/notes/chain-tokens-and-oauth.md). Companion implementation doc: [`tokens.md`](https://redfish.acequia.io/guerin/.agents/31bd5380-d743-420f-81a1-9258e7fbbf9a/2026-06-03/notes/tokens.md). ### What a token is A token is a cryptographic credential — a signed JWT carrying claims about who is making a request and what they're authorized to do. Backed by PS256 (RSA-PSS with SHA-256) per the platform. Verified by the substrate at every request. ### The three-mode detection (canonical platform) The platform classifies tokens by JWT-claim inspection in `src/auth/jwtAuth.mjs`: | Mode | Detected by | What it identifies | Status | |---|---|---|---| | **Chain Token** | `parent` claim present (SHA-256 of parent JWT) | A delegation chain; root traces to a registered user | **Primary direction.** Capability-style delegation. | | **User Token** | `kid` claim present, no `parent` | A user's direct authentication (key identified by JWK thumbprint); carries `deviceId` as attribution but identifies the *user* | **Recommended.** Structurally a depth-0 chain token. | | **Legacy Device Token** | No `kid`, no `parent` | A device by its `deviceId` | **Deprecated.** Backward compatibility only. (This is the source of the "device token misnaming" — devices aren't a first-class identity in the modern model; the keypair on a device signs *user* tokens.) | A user token's `kid` is the RFC 7638 JWK thumbprint of the user's public key (per-device — each device has its own key registered under the same user). This is what makes single-user-identity-across-multiple-devices work cleanly: one userId, multiple `kid`s in the user's `publicKeys` array. ### API tokens (the user-facing UX for long-lived non-interactive use) The platform exposes long-lived non-interactive tokens to users through the **API Tokens** dashboard surface (UI literally labeled "API Tokens"; implementation called "Stored Tokens" in `user-authentication.md`). How they work: 1. The user creates a long-lived JWT (`acequia.tokens.createUserToken({...}, '365d')`) 2. The user `POST`s it to `/auth/stored-tokens` with metadata (name, note, scope) 3. The server stores the JWT at `/auth/{subdomain}/stored-tokens/{tokenId}.json` 4. The server returns a short **CUID2 token ID** (e.g., `e7ph75g0mn3xoebuzsdw5ae1`) 5. The user uses the **token ID** (not the JWT) in `Authorization` header, `auth_token` cookie, or `?token=` query 6. The server resolves the token ID → loads the JWT → verifies normally This is the platform's pattern for what earlier drafts of this note called "application tokens" or "app tokens." **Apps don't get their own identity type — they get named API tokens issued by a user.** **The naming convention is load-bearing.** The token's `name` field tells you what it represents. Stephen's example: `wiki.acequia.org-mayordomo` — a custom-scoped API token named to indicate it represents the mayordomo for the wiki.acequia.org subdomain. The pattern reads: `<subdomain-or-scope>-<role-or-purpose>`. Other examples likely to appear: `firechief-jane-personal-automation`, `sfd-tile-pre-renderer`, `incident-triage-agent`, `daily-summary-bot`. API-token scope types per the platform docs: | Type | Description | |---|---| | **Full Access** | Same permissions as the issuing user account | | **Read Only** | Can read all paths, no write | | **Custom** | Specific `paths` (read) and `writePaths` (write) — the dashboard's "Custom" tag | API-token management endpoints: | Operation | Endpoint | |---|---| | Create | `POST /auth/stored-tokens` | | List | `GET /auth/stored-tokens` | | Get metadata | `GET /auth/stored-tokens/:tokenId` | | Update name/note | `PATCH /auth/stored-tokens/:tokenId` | | Regenerate JWT (rotate, change scope, extend expiry) | `PUT /auth/stored-tokens/:tokenId/jwt` | | Revoke | `DELETE /auth/stored-tokens/:tokenId` | | Purge (permanently delete, revoked only) | `DELETE /auth/stored-tokens/:tokenId/purge` | ### Chain tokens (the capability-delegation direction) The canonical primary direction is chain tokens — a UCAN-family capability mechanism. A chain is a linked list of JWTs walked from leaf to root via SHA-256 `parent` pointers; each link can only narrow scope (attenuation enforced structurally via `isScopeSubset`); chains stored content-addressable at `/auth/{subdomain}/chains/{sha256}.jwt`. A user token (no `parent` claim) is structurally a depth-0 chain token; the chain machinery is purely additive. Full design and OAuth comparison in [`chain-tokens-and-oauth.md`](https://redfish.acequia.io/guerin/.agents/9242fee3-0f2c-43a6-a506-8be19efe004a/2026-06-03/notes/chain-tokens-and-oauth.md). The headline: **chain tokens are wire-compatible with OAuth + JWT but belong to a different architectural family (capabilities, UCAN-style)** — borrowing OAuth's transport while replacing its centralized issuer with peer-mediated, bearer-verifiable delegation chains. ### Bootstrap mechanisms (token issuance flows for specific scenarios) The platform has several specific bootstrap flows — not distinct token types, but specific issuance mechanisms with their own UX:
- **Invite** ([`POST /auth/invites`](acequia.io/documentation/platform/user-authentication.md)) — owner mints a signed JWT representing a future user-binding. Recipient redeems via `POST /auth/invites/accept` with their freshly-generated keypair. Result: a user-binding created in the subdomain with pre-assigned role/paths. - **Device link** (`POST /auth/device-link/accept`) — existing-device-of-a-user signs a short-lived (5-minute) token that lets a new device add its keypair to the same user's `publicKeys` array. Result: same user identity across multiple devices. - **Public-key discovery** (`GET /auth/users/:userId/keys/:kid/public`) — anyone can fetch a user's public key by `kid` for offline JWT verification. These are **issuance/bootstrap mechanisms**, not separate token types. The resulting credential is always a chain/user/(legacy-device) token. ### Naming convention for non-human-identity API tokens (proposed Document-A extension) The platform's pattern of representing non-human identities (apps, mayordomos, automation, AI agents) as named API tokens deserves a vocabulary convention. **[Proposed extension]**: API tokens representing non-human actors follow `<scope-or-org>-<role-or-purpose>` naming. Examples: | Token name | Represents | |---|---| | `wiki.acequia.org-mayordomo` | The mayordomo agent serving the wiki.acequia.org subdomain | | `sfd-tile-pre-renderer` | An automated tile-rendering job for SFD's layers | | `anyhazard-incident-triage-agent` | An AI agent that triages incoming incidents | | `firechief-jane-daily-summary-bot` | Jane's personal daily-summary automation | The token is owned by the issuing user; the *holder* (the running process / agent / app) is whatever software currently has the token in its environment; the *audit trail* shows actions taken by the token's bearer with the token's name attached. This is the operational answer to "how do applications and AI agents present identity?" — they don't get their own identity type in the platform model; they get a named API token issued by a user, with the name indicating what they represent. ### Apoptotic lifecycle Tokens are apoptotic by design ([apoptosis-vs-necrosis](https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/apoptosis-vs-necrosis.md)): - **TTL enforced** by the substrate at every verification - **Explicit revocation** via `DELETE` on the issuer's token sub-URI; for chain tokens, the cascade walks the chain-token graph (revoking a parent revokes children); for legacy keys, key revocation removes from `publicKeys` array - **Revocation registry** at `/auth/{subdomain}/revocations.json` checked on every chain-link verification - **Cookie deletion** (`Set-Cookie: auth_token=; Max-Age=0`) is the browser-side complement Necrotic case: a leaked-but-not-revoked token. Mitigated by short TTLs, active rotation, revocation-list distribution.
## Ownership and Permissions on Resources A resource has an **owner** (an identity — person, organization, or AI agent) and may be shared with other identities at specific permission levels. - **Owner** — the identity (person/org/agent) with **full control** of a resource: read, write, share, transfer ownership, delete, change permissions, designate URI hosts. A resource has exactly one owner at any moment. **All three identity types can be owners** — a person can own personal scenarios; an org can own institutional layer collections; an AI agent can own its own outputs (e.g., a wildfire-modeling agent owns the model snapshots it publishes). - **Permissions** — bindings granted by the owner to other identities, with scope: - **read** — can view/access the resource's content - **write** — can modify the resource's content (typically implies read) - **share** — can re-grant access to other identities; attenuated by the [grant-not-more-than-you-have] rule (effort-1 §F5.7) so the share-recipient can't grant more than they themselves hold - Combinations are common: an "editor" binding typically grants read+write; a "co-owner" binding grants read+write+share+manage; an "approver" binding might grant share but not write. - **Ownership transfer** — atomic operation: `MOVE /resources/<R>/owner` to a new identity URI. Subject to acceptance by the new owner (the new owner's mayordomo can accept or decline). Preserves history (the binding-graph and audit log remain intact; just the owner-of-record changes). **Note on overloaded word "owner":** owner of a resource = the controlling identity of that resource. Distinct from **host**, which has its own three senses (session host, URI host, mayordomo governance role — see disambiguation below).
## Dynamic Resources / Live URIs Not every URI resolves to a stored file. The vocabulary explicitly accommodates **live / dynamic resources** — URIs whose content is generated at request time or reflects live state. This is the [agent-as-file-ducktyping](https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/agent-as-bead.md) frame at the user-vocab level: a path can resolve to a file, an agent, a camera, a room, a sensor, a process, a simulation. Verb semantics vary by resource kind. ### Kinds of dynamic resources - **Simulation URI** — GET returns the current state of an ongoing computation. Examples: a wildfire simulation in progress (current burn state); a weather model output (latest forecast); a fluid-dynamics simulation; an evacuation traffic model. Often paired with a `/inputs/` sub-URI for parameter control and a `/history/` sub-URI for replay. - **Camera URI** — GET returns the latest captured frame from a camera. Examples: a vantage-point camera at a fire watch tower; a body-worn camera; a satellite imagery feed; a drone live view. Geo.camera in the existing ecosystem is the worked example. - **Sensor URI** — GET returns the latest reading from a sensor. Examples: weather station; air-quality monitor; soil-moisture probe; seismic sensor. - **Process URI** — GET returns the current state of a running process. Examples: an incident-response workflow currently in progress; a model training job; a queue depth; a deployment status. - **Stream URI** — establishes a subscription for ongoing updates rather than a one-shot read. Examples: incident-alert stream; live participant-presence updates at a session URI; a chat-room transcript stream. Backed by SSE / WebSocket / WebRTC at the implementation level (Document B). ### GET semantics by resource kind | Resource kind | What GET returns | Caching | |---|---|---| | Static | Stored content (bytes) | Cacheable indefinitely until version changes; ETag / Last-Modified work normally | | Simulation | Current computed state at the moment of request | Cacheable with short TTL; staleness metadata important; client may want subscription instead | | Camera | Latest captured frame | Cacheable for a brief window (seconds); push subscription preferred for live use | | Sensor | Latest reading | Cacheable per sensor's update rate | | Process | Current process state | Cacheable for a brief window; subscription preferred for active monitoring | | Stream | Stream-establishment response (e.g., SSE handshake) | Not cacheable; the response is the connection | `PROPFIND` returns metadata indicating the resource kind so callers can choose appropriate behavior. Document B specifies the metadata schema. ### Worked example: Simtable cameras The AnyHazard/Simtable camera is the canonical worked example of dynamic-URI structure in this ecosystem. A camera is not a single URI — it's a **tree of related URIs** rooted at the camera, each with its own GET/PUT/POST semantics and its own permission model. This is the [agent-as-file-ducktyping](https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/agent-as-bead.md) frame and the existing geo.camera `supportedCapabilities.json` pattern made concrete. Example URI tree for a camera on a Simtable owned by SFD: ``` /orgs/sfd/devices/simtable-1/ # the Simtable device /orgs/sfd/devices/simtable-1/cameras/ # listing of cameras on this table /orgs/sfd/devices/simtable-1/cameras/overhead/ # this camera (PROPFIND for metadata + capabilities) # content URIs (the frame) /orgs/sfd/devices/simtable-1/cameras/overhead/latest # GET → latest captured frame /orgs/sfd/devices/simtable-1/cameras/overhead/stream # GET (SSE/WebSocket) → live frame subscription # parameter URIs (configuration; GET reads, PUT writes) /orgs/sfd/devices/simtable-1/cameras/overhead/params/focus-distance /orgs/sfd/devices/simtable-1/cameras/overhead/params/shutter-speed /orgs/sfd/devices/simtable-1/cameras/overhead/params/gain # ISO/gain /orgs/sfd/devices/simtable-1/cameras/overhead/params/resolution /orgs/sfd/devices/simtable-1/cameras/overhead/params/white-balance /orgs/sfd/devices/simtable-1/cameras/overhead/params/exposure # action URIs (triggers; POST to invoke) /orgs/sfd/devices/simtable-1/cameras/overhead/actions/capture # take a frame now /orgs/sfd/devices/simtable-1/cameras/overhead/actions/calibrate # run calibration /orgs/sfd/devices/simtable-1/cameras/overhead/actions/focus-here # autofocus on a coordinate /orgs/sfd/devices/simtable-1/cameras/overhead/actions/start-recording /orgs/sfd/devices/simtable-1/cameras/overhead/actions/stop-recording # discovery + audit /orgs/sfd/devices/simtable-1/cameras/overhead/capabilities # what this camera can do (supportedCapabilities) /orgs/sfd/devices/simtable-1/cameras/overhead/audit # who changed which params when ``` The same pattern applies to other device-resources on the Simtable: projectors (brightness, focus, keystone), microphones (gain, mute, direction), depth sensors, IMU, the table surface itself. ### Permissions on the camera tree Permissions are applied per-sub-URI (or per-subtree). A typical role mapping:
| Role | Permissions on the camera tree | |---|---| | **Observer** (unauthenticated bystander in the room) | None — observers don't bind to anything | | **Participant** (in a session at this table) | `read` on `/latest`, `/stream`, `/capabilities`; usually `read` on `/params/*` (can see current settings); no `write`, no `actions` | | **Camera operator** (session role granted by host, or a user-of-org role) | Above, plus `write` on `/params/*` (adjust settings) and `POST` on `/actions/*` (trigger captures, calibrate, refocus) | | **Session host** | Camera-operator permissions for cameras on this Simtable for the session's duration | | **Owner** (typically the org that owns the table) | Full control: above plus permission management, lifecycle (camera enable/disable), firmware updates | The camera-operator role is a useful pattern because it's typically a *session-scoped* role — a participant in a fire-debrief session might be granted camera-operator for the duration to point the overhead camera at a specific feature on the table without needing org-level permission. ### Capabilities-discovery (HATEOAS-style) The camera's `/capabilities` sub-URI returns its supported operations and parameter ranges (continuous values, enums, current limits). Callers discover what the camera can do at interaction time rather than relying on a pinned spec. Per the agent-as-file-ducktyping memory: "APIs are negotiated at interaction time (OPTIONS, PROPFIND, content-negotiation, HATEOAS, per-caller capability tailoring), not reified into pinned specs." Per-caller composition applies: a participant sees only the parameter URIs they're allowed to read; an operator sees those plus write-eligible parameters; an owner sees the full tree. ### Implications for ownership and permissions - An owner of a simulation URI controls **whether the simulation runs** (apoptotic signal: stop the simulation; reference-count GC: tear down if no participants are reading). - A camera URI's owner can revoke access at the source — `read` permission is meaningful even though the content isn't stored. - A sensor URI's owner manages calibration and availability — `write` permission on a sensor URI might mean "can change sampling rate" rather than "can change historical readings." - A process URI's owner controls start/stop/restart and can transfer control via host-transfer-like operations. ### Implications for capacity Dynamic resources consume **continuous compute or device resources** in addition to storage. Capacity (free tier / personal premium / org seat) governs: - How many concurrent simulations a person/agent can run - How many cameras an identity can stream from - How many subscriptions a stream URI will accept - Free-tier limits: typical (e.g., one small simulation at a time, low frame-rate cameras) - Premium: higher concurrency, higher resolution, longer duration
## URI Hosting and Distributed Availability Every URI exists at some host(s) — peers or servers that serve its content. **URI hosting is distinct from session hosting** even though both words use "host": - **URI host** — a peer or server that serves a URI's content. **Plural by design**: a URI can be hosted at multiple peers simultaneously, forming a distributed availability mesh. The pitch's resources (layers, scenarios, progressions, datasets, models) all need to be available somewhere; URI hosting is the substrate that makes that work. For **dynamic / live URIs**, URI hosting splits into three roles a peer can hold: - **Source hosting** — runs the computation, connects to the sensor, holds the live state. Typically singular per dynamic URI (one source of truth) though replicated-state systems can have multiple sources with consensus. - **Cache hosting** — serves the latest known value with staleness metadata. Plural; horizontally scalable for read-heavy dynamic URIs (e.g., a popular camera feed with thousands of readers). - **Stream hosting** — relays subscription/push updates from source to subscribers. Plural; tree-shaped distribution (source → relays → leaves). Different identities can hold different hosting roles for the same dynamic URI. The pitch's "bring-your-own resource to session" extends naturally to "bring-your-own camera feed" — the camera URI's source-host (the camera owner) attaches the URI; cache-hosts and stream-hosts serve it within the session. - **Origin host** — the URI host that the owner originally published from (typically the canonical write surface). Other URI hosts are mirrors/caches/replicas. - **Pinning** — an identity's commitment to keep a URI's content available locally and serve requests for it. **Pinning makes the identity a URI host** for that URI. Voluntary, opt-in. Example operation: `PUT /people/<P>/pinned/<URI-slug>` — declares Person P will host content from `<URI-slug>` locally. - **URI participant** — any identity that **interacts with a URI** (reads, writes, references it from other URIs, attends sessions at it, etc.). Generalizes session-participant: a session-participant is a URI-participant for the specific case where the URI is a session. - **CDN participation** — heavy URI participants may take on URI hosting responsibility — either by **opt-in** (the identity explicitly pins the URI) or by **policy threshold** ("identities that read this URI > N times per K-period automatically pin it for L-period"). Distributes content-delivery load; improves resilience; reduces dependence on the origin host. Acequia/saca anchor: parciantes who depend most on a section of ditch contribute most labor to maintaining it. - **Backup responsibility** — a URI participant who pins a URI commits to a retention SLA. Critical resources may have policy requiring K-of-N participants to pin at all times, ensuring no single point of failure. ### Acequia / saca anchor In NM acequia tradition, parciantes contribute labor to the shared acequia (the annual **saca** / ditch-cleaning). The acequia carries water for all parciantes; the parciantes carry the acequia. **Same pattern at the URI level**: URIs carry content for all participants; participants carry the URIs. This is the [distributed-origin-architecture](https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/) frame as a participant responsibility. ### Hubler anchor In the [self-assembling-wires frame](https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/self-assembling-wires/ecology.md), demand on a region of the substrate causes wires to form there. Heavy URI demand causes hosting to converge — peers that frequently access a URI are the natural candidates to host it. The CDN-participation policy is the operational implementation of this dynamic. ### Lifecycle interaction URI hosting interacts with apoptosis/necrosis: - A URI with **no active hosts** becomes unavailable. If the URI was supposed to persist, this is **necrotic** (loss of content despite still being referenced). - The **apoptotic mechanism**: the owner signals "deprecating this URI"; hosts can choose to keep serving (volunteer to take over canonical responsibility) or to release; orderly fade rather than sudden disappearance. - **Reference-count GC**: a URI with no hosts AND no incoming references can be reaped without disrupting anything. ### Three senses of "host" disambiguated The word "host" appears with **three distinct meanings** in this vocabulary. Disambiguate by context: | Sense | What it means | Who can be one | Scope | Responsibility | |---|---|---|---|---| | **Session host** | The participant who claimed a session | Person, AI agent | A session | Session management (configure, invite, transfer, end) | | **URI host** | A peer/server that serves a URI's content | Any peer or server; an identity (person/org/agent) that pins | A URI | Content availability, serving requests | | **Mayordomo (governance role)** | Senior org-governance role | A user of the org (person typically) | An organization | Policy, member management, succession | All three are "raised rights/responsibilities for a scope" — the structural pattern is the same. The scope differs (session vs URI vs org) and the responsibilities differ. The word "host" is overloaded in normal English ("host of a party," "host of a podcast," "web host") so context-based disambiguation is reasonable; the vocab makes the three senses explicit so spec readers don't conflate them.
## Lifecycle - **Apoptosis / apoptotic signal** — orderly, signaled termination of a binding (or a whole scope). Propagates through the chain-token graph. Lifecycle events (logout, revoke, expire, end-session, key rotation, host-transfer-on-leave, ownership transfer) all emit apoptotic signals. - **Necrosis** — the opposite of apoptosis. Dangling references, ungranted-but-still-held capabilities. The original pitch's "orphan recovery" (effort-2 §F7.3) patches the necrotic case. - **Succession** — the org's apoptotic mechanism for governance continuity across "eras of users": N-of-M threshold approval to transfer the mayordomo (governance) role without requiring the original holder's keys. Effort-1 §F3.7. - **Device promotion** — moving a device's URI atomically from `<person>/devices/X` to `<org>/devices/X`. Preserves historical context. **Gemini's contribution, credited.** - **Ephemeral access / signed assert** — short-lived binding issued locally at a Simtable for offline-edge cases. Reconciles when the network heals. **Gemini's contribution, credited.** In binding terms: a binding with `ttl: pending-reconciliation` and `provenance: locally-issued`.
## Operations (verbs on URIs) | Intent | URI verb + path | |---|---| | Add Jane as a user of SFD with editor role | `PUT /orgs/sfd/users/jane-smith` with body referencing `/people/jane-smith` + editor role template | | Remove Jane as a user of SFD | `DELETE /orgs/sfd/users/jane-smith` (apoptotic cascade revokes her org-scoped bindings) | | Jane (a user of SFD) claims a Simtable session as host | `PUT /sessions/<S>/host` referencing `/people/jane-smith` (subject to mode + allow-list policy; org capacity applies) | | Mike (a free person identity, not a user of any org) claims a session as host | `PUT /sessions/<S>/host` referencing `/people/mike-jones` (subject to free-tier capacity limits — session duration, participant count, etc.) | | Configure a persistent session URI with election fallback | `PROPPATCH /sessions/<persistent-S>` policy.host-election=first-come (or rotation, consensus, etc.) | | Trigger host election on a persistent session (no current host) | `POST /sessions/<persistent-S>/elect-host` — substrate runs the configured election protocol over current participants | | Add Mike (not a user of SFD) as a participant of the session | `PUT /sessions/<S>/participants/mike-jones` (no user-binding to SFD required) | | Jane promotes Mike to co-host | `PUT /sessions/<S>/co-hosts/mike-jones` | | Jane transfers host to Mike before leaving | `MOVE /sessions/<S>/host` (old binding gone, new binding present, audit-logged) | | End session | `PROPPATCH /sessions/<S>` state=ended; apoptotic cascade revokes all session bindings | | Share resource R to user P | `PUT /people/P/inbox/<binding>` referencing R | | Federate R to peer org X | `PUT /orgs/X/incoming/<binding>` referencing R | | Attach R to active session | `PUT /sessions/<S>/imports/<binding>` referencing R with `ttl: session-end` | | Browse my namespace | `GET /people/jane-smith/` (per-caller composition resolves the view) | | Promote DIY device to org | `MOVE /people/jane-smith/devices/X → /orgs/sfd/devices/X` | | Grant Mike read access to scenario R owned by Jane | `PUT /people/mike/inbox/<binding>` referencing R with `scope: read` | | Grant Mike read+write+share on scenario R | `PUT /people/mike/inbox/<binding>` referencing R with `scope: read+write+share` | | Transfer ownership of resource R to SFD | `MOVE /resources/<R>/owner` referencing `/orgs/sfd` (subject to SFD mayordomo's acceptance) | | Pin a URI (commit to hosting it locally) | `PUT /people/jane/pinned/<URI-slug>` | | Unpin (release URI-hosting commitment) | `DELETE /people/jane/pinned/<URI-slug>` | | List URI hosts for a given URI | `GET <R-URI>/hosts/` | | Owner deprecates a URI (apoptotic signal) | `PROPPATCH <R-URI>` state=deprecated; hosts can opt in to continued service or release | | Create an API token (UI: dashboard → API Tokens → + Create Token; API: `POST /auth/stored-tokens`) | User signs a JWT with their device key, POSTs with name/scope/TTL; gets back a CUID2 token ID | | Create an API token for a non-human-identity role (mayordomo, app, automation) | Same operation; name follows `<scope-or-org>-<role-or-purpose>` (e.g., `wiki.acequia.org-mayordomo`); scope is "Custom" with specific paths | | Use an API token | Put the token ID in `Authorization: Bearer <id>`, `auth_token=<id>` cookie, or `?token=<id>` query — substrate resolves ID → JWT → verifies | | Rotate an API token's JWT (zero-downtime) | `PUT /auth/stored-tokens/:id/jwt` with a new JWT — the token ID stays the same; permissions/expiry change | | Revoke an API token | `DELETE /auth/stored-tokens/:id` — sets `status: revoked`, kept for audit | | Purge a revoked API token | `DELETE /auth/stored-tokens/:id/purge` — permanently delete (revoked only) | | Issue a chain token (capability delegation) | Client-side: `acequia.chains.createChainToken({...})` with parent token + narrower scope + TTL; stored content-addressable at `/auth/{subdomain}/chains/{sha256}.jwt` | | Revoke a chain token | Hash added to `/auth/{subdomain}/revocations.json`; cascades to all children (revoking parent revokes children too) | | Add a new device key to an existing user | Device-link flow: existing device signs short-lived token; new device redeems via `POST /auth/device-link/accept` | | Revoke a device key | `DELETE /auth/users/:userId/keys/:kid` — sets status `revoked`; other devices keep working | | Read the latest frame from a camera URI | `GET https://anyhazard.acequia.io/orgs/sfd/cameras/watchtower-3` | | Subscribe to a camera's live stream | `GET <camera-URI>/stream` with `Accept: text/event-stream` (SSE) or upgrade to WebSocket | | Start a wildfire simulation | `POST /orgs/sfd/simulations/` with initial parameters; returns the simulation URI | | Read current state of a simulation | `GET <simulation-URI>` (current step, current burn state) | | Attach a live camera feed to a session | `PUT /sessions/<S>/imports/<name>` referencing the camera URI; substrate negotiates stream-hosting for participants | | Stop a simulation (apoptotic) | `DELETE <simulation-URI>` (or PROPPATCH state=stopped); reference-counted GC tears down compute | | Self-register as user of SFD (pending approval) | `POST /orgs/sfd/queue/` (creates a pending user-binding awaiting approval) | | SFD admin approves | `PUT /orgs/sfd/queue/<req>/approval` (promotes pending → active user-binding) |
## Vision-Frame Primitives (Document A vocabulary) Terms from the foundational Acequia design notes ([bead 874fce5b](https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/)) the user-rep layer should adopt: - **Acequia** — the word carries two foreground senses (per [acequia-the-word.md](https://redfish.acequia.io/guerin/.agents/31bd5380-d743-420f-81a1-9258e7fbbf9a/2026-06-03/notes/acequia-the-word.md)): - **The pattern** — coequal technical (formally specifiable: domains, WebDAV, capability-discipline auth, distributed-origin substrate) and governance (Ostrom-style observed features: self-determined per acequia, with cataloged features successful instances tend to exhibit — see [ostrom-and-acequia-governance.md](https://redfish.acequia.io/guerin/.agents/31bd5380-d743-420f-81a1-9258e7fbbf9a/2026-06-03/notes/ostrom-and-acequia-governance.md)) - **The platform** — `acequia.io`, Redfish Group's commercial service offering of the pattern (analogous to Gmail running SMTP — anyone can DIY a self-hosted equivalent; most won't) - Canonical analogy: **email server** (postfix/dovecot as the pattern; Gmail/Fastmail as commercial platforms; federation native to the protocol). Supplementary analogies: web server cluster vs AWS/Azure, DNS servers vs Cloudflare/Route53, Nextcloud self-hosted vs commercial Nextcloud hosting. - Historical NM acequias + Ostrom's commons-governance research are the grounding both the pattern and the platform draw from; not separate vocabulary entries. - **Parciante** — the water-rights holder; the unit of agency. In this vocabulary: the *person* (and, by extension, the org and AI agent as other identity-types that hold rights). - **Mayordomo** — see above (under Roles for the governance role; under Other Terms for the agent at a URI). - **Saca** — annual cleaning; collective labor obligation. Candidate vocabulary for "shared maintenance obligations." - **Bind / mount** — see above (URI Frame). - **Apoptosis / necrosis** — see above (Lifecycle). - **Polarized link / GET** — every cross-URI reference is directional and capability-attenuated. - **Advanced wave** — the attention/attribution/reputation flow complementing the value/capability flow. The audit log is the substrate.
## Out of Scope (Document B Material) - Specific cryptographic algorithms (PS256, Ed25519, ML-DSA, etc.) - Specific protocol wire formats (chain-token serialization, WebDAV verb mapping) - Specific UI patterns (panel layouts, button placement, color) - Billing implementations (Stripe vs LemonSqueezy vs other) - Storage backend (Acequia WebDAV vs S3 vs FS-A) - Algorithm choices for capability-map computation, conflict resolution
## What's New Here vs Gemini's Vocab - The **person / organization / AI agent** three-way distinction as persistent identities - The strict **identity vs relationship** distinction (user and participant as relationship bindings, not as kinds of identity) - **Participant** as session-scoped relationship binding (distinct from user) - **Host** and **co-host** as roles on participant bindings - **Host transfer** as an explicit Zoom-anchored operation - **Observer** as explicitly-not-in-any-binding - The URI frame applied throughout (bindings as URIs; operations as verbs on URIs) - Mayordomo with the governance-role / agent-at-URI distinction - Apoptosis / necrosis as lifecycle frame - Session as a first-class URI with `host`, `co-hosts/`, `participants/`, `imports/` - Vision-frame primitives (acequia, parciante, saca, advanced wave) - The agent-as-bead frame (the bead system as the participant protocol applied to agents) - **Capacity** with free tier / personal premium / org-seat allocation channels - **Ownership** as explicit identity-controls-resource relationship (with all three identity types as eligible owners) - **Permissions** as read / write / share with attenuated re-grant - **URI hosting** as a distinct sense of "host" — content availability as distributed responsibility - **Pinning, CDN participation, backup responsibility** at the URI level - Three-senses-of-host disambiguation table - **Persistent session URI** vs ephemeral session URI — the Zoom personal-meeting-room pattern - **Host election** as an acquisition mode for the host role (alongside claim); the general **role-binding election** pattern that also covers mayordomo succession, URI host fallback, co-host promotion - **Static vs dynamic resources** — URIs include cameras, sensors, simulations, processes, streams (the agent-as-file-ducktyping frame at the user-vocab level) - **Source / cache / stream hosting** as the three hosting roles for dynamic URIs (which can be held by different identities) - **AI agent as a persistent identity** — [Proposed extension]; canonical platform represents AI agents as named API tokens, not a distinct identity class - **Group sense disambiguation** — collaboration group (this vocab, pitch) vs runtime peer group (canonical platform) - **API tokens (named) as the operational mechanism for non-human identity** — apps/agents/mayordomos/automation use named API tokens issued by a user; naming convention `<scope-or-org>-<role-or-purpose>` (worked example: `wiki.acequia.org-mayordomo`)
## What Gemini's Vocab Has That This Keeps - **Subdomain identity** as privacy/sovereignty mechanism (retained) - **Acequia Passport** for cross-subdomain unification (credited, retained) - **Multi-app aware role templates** (credited, reframed as binding patterns) - **Device promotion** (credited, recast as URI MOVE) - **Ephemeral access / signed assert** (credited, recast as binding-with-TTL) - **Authentication vectors** (QR, short codes) (retained) - **User** as a concept (was kept implicitly but now made explicit and distinguished from participant)
## What's Resolved by Stephen's Correction In an earlier draft I had collapsed "user" and "participant" into a single concept, with "participant" as the rename of "user." Stephen's Zoom anchor clarified that they're distinct relationships with different meanings: - **User** = seat under an org's account (the commercial/membership relationship) - **Participant** = present in a session (the transient meeting relationship) A person can be a user of zero, one, or many orgs (the persistent membership pattern). A participant of any session may or may not be a user of any org (the meeting pattern). This matches Zoom directly and resolves what I had been calling the "user vs participant" tension with Gemini — Gemini's "user" is actually closer to this corrected user concept than to my over-broad earlier "participant" framing.
## Related - Gemini's vocab note: [https://redfish.acequia.io/guerin/.agents/9e1d87f5-a226-4d1a-be05-64c8d5cacf38/2026-06-03/notes/user-representation-vocabulary.md](https://redfish.acequia.io/guerin/.agents/9e1d87f5-a226-4d1a-be05-64c8d5cacf38/2026-06-03/notes/user-representation-vocabulary.md) - Tensions between this and Gemini's: [vocabulary-tension-claude-vs-gemini.md](https://redfish.acequia.io/guerin/.agents/31bd5380-d743-420f-81a1-9258e7fbbf9a/2026-06-03/notes/vocabulary-tension-claude-vs-gemini.md) - Worked URI-frame expression: [participants-and-resources-in-uri-sense.md](https://redfish.acequia.io/guerin/.agents/31bd5380-d743-420f-81a1-9258e7fbbf9a/2026-06-03/notes/participants-and-resources-in-uri-sense.md) - Fused critique (for Kaz): [artifacts/anyhazard-user-model-critique-fused.md](https://redfish.acequia.io/guerin/.agents/31bd5380-d743-420f-81a1-9258e7fbbf9a/2026-06-03/artifacts/anyhazard-user-model-critique-fused.md) - Foundational vision frame: [bead 874fce5b](https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/) - Acequia auth (worked example in another bead): [chain-tokens-and-oauth.md](https://redfish.acequia.io/guerin/.agents/9242fee3-0f2c-43a6-a506-8be19efe004a/2026-06-03/notes/chain-tokens-and-oauth.md)
## References (bead cross-links) - Bead: Acequia User Model & Architecture Bead · [canonical](https://redfish.acequia.io/guerin/.agents/9e1d87f5-a226-4d1a-be05-64c8d5cacf38/) - Bead: 9242fee3 · [canonical](https://redfish.acequia.io/guerin/.agents/9242fee3-0f2c-43a6-a506-8be19efe004a/) - Bead: 874fce5b · [canonical](https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/)