Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/rich-actions-43.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@opencoven/cave-client': minor
---

Add the privileged authority tier (attachments, rich content, attention, task handoffs, explicitly confirmed GitHub actions) with Cave remaining the sole executor and canonical owner: a capability registry derived from the authoritative contract fixture that resolves every privileged action class against the live operation table per call; fail-closed bounded attachment transfer (file count, file size, request size, MIME allowlist with magic-byte signature agreement, filename, traversal, symlink, and the atomic uploader-credential-plus-conversation binding) with metadata-only records so attachment bytes never enter canonical conversation JSON; a passive rich-content AST over a closed non-executable node vocabulary that rejects raw markup nodes, unknown fields, unsafe link schemes (`https:`/`mailto:` only), oversized payloads, and over-deep nesting while preserving markup-looking text inertly; task-handoff transitions that keep proposed, pending, completed, rejected, and failed strictly distinct behind a declared transition map; closed attention-response kinds with bounded notes; and confirmed GitHub action machinery whose curated union ships deliberately empty.

The authoritative Cave fixture pinned at producer commit `4adc97b1` declares the privileged pairing scopes (`attachments:write`, `tasks:write`, `github:write`, `chat:write`, `conversations:write`) but no attachment, rich-content, attention, task, or GitHub operations, so the five optional `CaveTransport` bindings stay unbound, every privileged call resolves `undeclared`, and the client reports `unsupported_operation` after request validation (zero transport dispatch on validation failure) until the producer contract lands and `pnpm sync:contracts` imports it. No routes, scopes, capability families, or GitHub action kinds are invented.
1,392 changes: 1,238 additions & 154 deletions api-baselines/cave.d.ts

Large diffs are not rendered by default.

34 changes: 32 additions & 2 deletions api-baselines/cave.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,45 +17,75 @@
"entrypoints": {
".": {
"declarationFiles": [
"dist/client-ootQTXcj.d.ts",
"dist/client-M2RrMRyI.d.ts",
"dist/index.d.ts"
],
"runtimeExports": {
"dist/index.js": [
"CAVE_ANALYTICS_WINDOWS",
"CAVE_ATTACHMENT_CONTENT_TYPES",
"CAVE_ATTACHMENT_LIMITS",
"CAVE_ATTENTION_RESPONSE_KINDS",
"CAVE_CLIENT_VERSION",
"CAVE_CONVERSATION_EVENT_TYPES",
"CAVE_CONVERSATION_OPERATION_STATES",
"CAVE_CONVERSATION_ORIGINATING_SCOPES",
"CAVE_CONVERSATION_RECONCILE_REASONS",
"CAVE_CONVERSATION_TERMINAL_STATES",
"CAVE_DEFAULT_CAPABILITY_CONTRACT",
"CAVE_FAMILIAR_PROPERTIES",
"CAVE_GITHUB_ACTION_KINDS",
"CAVE_PAIRING_SCOPES",
"CAVE_PAIRING_STATUSES",
"CAVE_PRIVILEGED_ACTION_CLASSES",
"CAVE_PRIVILEGED_ACTION_REQUIREMENTS",
"CAVE_RICH_CONTENT_LIMITS",
"CAVE_RICH_CONTENT_URL_SCHEMES",
"CAVE_TASK_HANDOFF_STATES",
"CAVE_TASK_HANDOFF_TRANSITIONS",
"CaveAttachmentSchemaError",
"CaveClient",
"CaveClientError",
"CaveDiscoveryError",
"CavePairingSession",
"CaveRichContentError",
"bindCaveAttachments",
"caveConversationReconcileReason",
"collectCaveRichContentUrls",
"createCaveCapabilityRegistry",
"createCaveClient",
"createConversationEventTranslator",
"createDefaultCaveCapabilityRegistry",
"createDiscoveredCaveClient",
"createManagedCaveClient",
"digestCaveContractFixture",
"discoverCaveEndpoint",
"isCaveClientError",
"isCaveDiscoveryError",
"isCaveTaskHandoffTransition",
"normalizeCaveError",
"parseCaveAttachmentDownloadRequest",
"parseCaveAttachmentRecord",
"parseCaveAttachmentUploadRequest",
"parseCaveAttentionResponseRequest",
"parseCaveContractFixture",
"parseCaveGitHubActionRequest",
"parseCaveRichContent",
"parseCaveRichContentUrl",
"parseCaveTaskHandoffRequest",
"parsePrivilegedConfirmation",
"parseVerifiedCaveContractFixture",
"serializeCaveRichContent",
"sniffCaveAttachmentContentType",
"validateConversationEventCursor",
"validatePrivilegedOperationId",
"verifyCaveContractFixtureDigest"
]
}
},
"./managed": {
"declarationFiles": [
"dist/client-ootQTXcj.d.ts",
"dist/client-M2RrMRyI.d.ts",
"dist/managed.d.ts"
],
"runtimeExports": {
Expand Down
84 changes: 84 additions & 0 deletions packages/cave/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ record. Unix discovery still requires a positive inode.
- Conversational control adds the first bounded mutation authority while Cave
remains the sole executor and canonical owner; see
[Conversational control](#conversational-control) below.
- Privileged authority adds capability-gated attachment transfer, passive
rich content, attention responses, task handoffs, and the confirmed GitHub
action envelope while Cave remains the sole executor; see
[Privileged authority](#privileged-authority) below.
- Four bounded async iterators, `iterateFamiliars()`, `iterateProjects()`,
`iterateConversations()`, and `iterateConversationMessages()`, lazily compose
the list routes. There is intentionally no iterator for the single-item
Expand Down Expand Up @@ -543,6 +547,86 @@ streaming renderers (human/JSON/NDJSON ordering) are likewise staged for a
follow-up PR per the design's PR plan, as no CLI command can execute a
mutation against a real authority before that contract exists.

## Privileged authority

The privileged authority tier covers attachment transfer, rich content,
attention responses, task handoffs, and explicitly confirmed GitHub actions.
Cave stays authoritative for storage, grants, confirmation revalidation,
idempotency, audit, and domain mutation; the SDK exposes capability-gated
typed operations only.

### Capability gating

`createCaveCapabilityRegistry(contract)` resolves an action class
(`attachment-transfer`, `rich-content`, `attention-response`,
`task-handoff`, `github-action`) against the live operation table on every
call. An action class is actionable only when the consulted contract
declares at least one operation carrying its required scope; resolutions are
fresh frozen descriptors, never cached capability objects. The default
registry mirrors the pinned fixture (verified by tests), under which every
privileged class resolves `undeclared` and `CaveClient` reports
`unsupported_operation`. Every privileged request additionally requires an
exact `confirmed: true` and a caller-supplied 36-character operation UUID.

### Attachment transfer

Upload and download requests are validated fail closed before any
capability or transport work: file count, per-file size, total request size,
declared MIME type versus magic-byte signature agreement, filename rules
(no separators, dot segments, control characters, or hidden dotfiles),
symlink refusal, and the atomic binding of every attachment to its uploader
credential and conversation. Canonical attachment records are metadata-only:
attachment bytes never enter canonical conversation JSON, browser storage,
profile config, or diagnostic bundles.

### Rich content

`parseCaveRichContent(value)` turns an untrusted payload into a strict,
non-executable AST over a closed node vocabulary (text, code, line break,
link, paragraph, heading, code block, blockquote, list). There is no HTML
node type and no event-handler field anywhere in the model: markup-looking
text is preserved byte for byte as inert text, unknown node types and
unknown fields are rejected, link targets allow only `https:` and
`mailto:` (no scheme-less targets, no userinfo), and node-count, depth,
and character limits fail closed. Oversized hostile payloads are rejected,
never truncated.

### Attention and task handoffs

`parseCaveAttentionResponseRequest(value)` accepts the closed response
kinds `acknowledge` and `decline` with a bounded optional note.
`parseCaveTaskHandoffRequest(value)` moves a handoff through the declared
transition map, keeping proposed, pending, completed, rejected, and failed
strictly distinct; terminal states transition to nothing.

### GitHub actions

The curated GitHub action union (`CAVE_GITHUB_ACTION_KINDS`) is deliberately
**empty**: no reviewed producer contract has curated which GitHub actions
exist, so naming concrete kinds would fabricate a curation. The type-level
union is therefore uninhabitable and `parseCaveGitHubActionRequest` rejects
every request with the precise gap — fail closed by construction — while
the confirmation, operation-UUID, and bounded-input machinery ship ready
for the curated union.

### Upstream contract gap

The authoritative Cave fixture pinned at producer commit `4adc97b1` declares
the privileged pairing scopes but **no attachment, rich-content, attention,
task, or GitHub operations and no such capability families**. The five
optional `CaveTransport` methods `uploadAttachment`,
`downloadAttachment`, `respondToAttention`, `requestTaskHandoff`, and
`submitGitHubAction` stay unbound, and no CLI commands ship for unsupported
privileged actions. The Cave producer routes, scope-to-operation mapping,
capability families, attachment storage semantics, rich-content payload
contract, attention/task state ownership, the curated GitHub action union,
and their conformance vectors are owed by the upstream Cave producer
contract; once that lands, `pnpm sync:contracts` imports the exact fixture
commit and the registry, request parsers, and transport bindings are
reviewed against it. The privileged authority tier additionally requires a
dedicated security review of privileged authority before any of it becomes
actionable.

## Compatibility, deadlines, and retry guidance

Cave Client v1 health accepts additive Cave API updates on major version `1`
Expand Down
Loading