Skip to content
Merged
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
36 changes: 32 additions & 4 deletions schema/00_common.cue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ package schema
// and therefore the generated Go — byte-identical to the pre-package one.

// Execution context for a plan step.
#Context: ("build" | "deploy" | "runtime") @go(-)
#Context: or(_contextWord) @go(-)

// #OpVerb — the verb DISCRIMINATOR vocabulary: the subset of #Op fields that are
// VERBS (exactly-one-set discriminators), as opposed to the shared modifiers
Expand All @@ -24,8 +24,7 @@ package schema
// field (the schemagen gate "OpVerbs ⊆ AuthoringVerbs" proves it) and MUST have a
// VerbCatalog entry (the registry bijection gate proves it). Keep in lockstep with
// the `--- verb discriminators ---` group in #Op.
#OpVerb: ("mkdir" | "copy" | "write" | "link" | "download" | "setcap" | "build" | "config" |
"plugin") @go(-)
#OpVerb: or(_opVerbWord) @go(-)

// ---------------------------------------------------------------------------
// Plan steps: the unified run/check/agent-run/agent-check/include vocabulary.
Expand Down Expand Up @@ -236,7 +235,7 @@ package schema
// the BuildKit sharing mode; owned renders a uid/gid-owned cache.
#CacheMount: {
dst: string & =~"^/"
sharing?: *"locked" | "shared" | "private"
sharing?: *"locked" | or(_sharingWord)
owned?: bool
}

Expand Down Expand Up @@ -401,3 +400,32 @@ package schema
// time, not about being unstuck.
force_stop?: bool @go(ForceStop)
}

// --- vocabulary tables (S3) --------------------------------------------------
// Every closed set of words is a table keyed by word, `<x>Word` is derived from it,
// and the enum an author meets is `or(<x>Word)` — so the table and the enum cannot
// disagree and a new word is ONE row here. `@vocab` names the owner (§3.1): these
// sets are compiled into THIS contract module, so the owner is `spec`.
//
// Each table is named after its word when that name is unique in the schema, and
// `<definition><Field>` when it is not; the comment above it names its site.

// #Context
_context: {build: {}, deploy: {}, runtime: {}} @vocab(spec)
_contextWord: [for w, _ in _context {w}]
// #OpVerb
_opVerb: {
mkdir: {}
copy: {}
write: {}
link: {}
download: {}
setcap: {}
build: {}
config: {}
plugin: {}
} @vocab(spec)
_opVerbWord: [for w, _ in _opVerb {w}]
// #CacheMount.sharing
_sharing: {locked: {}, shared: {}, private: {}} @vocab(spec)
_sharingWord: [for w, _ in _sharing {w}]
42 changes: 42 additions & 0 deletions schema/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,48 @@ embedding the closed `#Op`) is legal through v0.17 and rejected by v0.18's seman
with `field not allowed`. Raising the language version is the §10.1 pattern rewrite
(TODO 2.16), not a bump.

## Vocabulary tables (S3)

Every closed set of words in this schema is a **vocabulary table**, never a union
spelled out alternative by alternative (DESIGN.md §10.1 S3, D-PAT-3):

```cue
_context: {build: {}, deploy: {}, runtime: {}} @vocab(spec)
_contextWord: [for w, _ in _context {w}]

#Context: or(_contextWord) @go(-)
```

- **The table is the ONE home.** A new word is ONE row there; the derived
`_xWord` list and the enum an author meets are recomputations of it, so the
three cannot disagree.
- **`@vocab(<owner>)` names the owner** (§3.1). Every set in this module is
compiled into the `spec` contract module, so the owner is `spec`
(`scripts/design-consistency.sh` in the umbrella accepts `spec` as a
vocabulary owner beside `core` and the §3.1 plugin words).
- **A field whose default is a word keeps that default inline**:
`sharing?: *"locked" | or(_sharingWord)`. The default is part of the surface
(omitting the key materializes it), and it is also a row of the table, so the
accepted set is unchanged.
- **A two-value literal default stays as written** (`*false | bool`,
`mode?: *"internal" | "external"`): S3's one permitted inline enum is a
default with a single alternative.
- **Naming.** A table is named after its word (`_sharing`) when that name is
unique in the schema, and `<definition><Field>` (`_vmNetworkMode`,
`_cacheMountSharing`) when two defs have a field of the same name. Two defs
with the SAME words keep two tables: a field name is not a vocabulary, and
merging them would couple two shapes that only coincide today.
- **Tables live at the foot of the file that uses them**, one section per file,
each table preceded by a `// #Def.field` comment naming its site. The
concatenation is one compilation unit, so a table is visible to every file —
placing it beside its use keeps the pair findable.

`schema/vocab_s3_test.go` is the gate: every table must carry its `@vocab`, its
derived list must BE its rows, every table must be cited by a field and every
citation must resolve — and the test **injects a row into every table** and
asserts the derived list gains it, which is the only way to see that the list
derives rather than restates.

## Regenerating `spec` — `charly task cue-gen`

In THIS repository:
Expand Down
15 changes: 14 additions & 1 deletion schema/agent.cue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ package schema
#CredentialMount: {
src: string & !=""
dst: string & !=""
mode?: "copy" | "bind"
mode?: or(_credentialMountModeWord)
optional?: bool
}

Expand Down Expand Up @@ -70,3 +70,16 @@ package schema
progress_no_improvement_timeout?: #Duration @go(ProgressNoImprovementTimeout)
output_format?: string @go(OutputFormat)
}

// --- vocabulary tables (S3) --------------------------------------------------
// Every closed set of words is a table keyed by word, `<x>Word` is derived from it,
// and the enum an author meets is `or(<x>Word)` — so the table and the enum cannot
// disagree and a new word is ONE row here. `@vocab` names the owner (§3.1): these
// sets are compiled into THIS contract module, so the owner is `spec`.
//
// Each table is named after its word when that name is unique in the schema, and
// `<definition><Field>` when it is not; the comment above it names its site.

// #CredentialMount.mode
_credentialMountMode: {copy: {}, bind: {}} @vocab(spec)
_credentialMountModeWord: [for w, _ in _credentialMountMode {w}]
129 changes: 113 additions & 16 deletions schema/agent_control.cue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ package schema
#UUIDv7: string & =~"^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"

#TargetHop: {
transport: "inproc" | "exec" | "ssh" | "grpc" | "tmux"
transport: or(_targetHopTransportWord)
address?: string
user?: string
port?: int & >0 & <=65535
Expand Down Expand Up @@ -41,16 +41,16 @@ package schema
protocol_version: int & >=1 @go(ProtocolVersion,type=int)
entrypoint?: [...string]
profiles?: [...string]
interaction_modes?: [...("structured" | "terminal")] @go(InteractionModes)
persistence?: "none" | "session" | "required"
interaction_modes?: [...or(_interactionModesWord)] @go(InteractionModes)
persistence?: or(_agentRuntimeCapabilityPersistenceWord)
semantic_completion?: bool @go(SemanticCompletion)
}

#AgentSession: {
id: #UUIDv7 @go(ID)
runtime: string & !=""
target: #TargetSpec
state: "new" | "active" | "detached" | "closed" | "failed"
state: or(_agentSessionStateWord)
created_at: string @go(CreatedAt)
updated_at: string @go(UpdatedAt)
storage_ref?: string @go(StorageRef)
Expand Down Expand Up @@ -84,7 +84,7 @@ package schema
#AgentEvent: {
run_id: #UUIDv7 @go(RunID)
sequence: int & >=1
type: "started" | "message" | "tool" | "delegation" | "settled" | "status" | "completed" | "aborted" | "failed"
type: or(_agentEventTypeWord)
time: string
payload?: {...} @go(Payload,type=map[string]any)
}
Expand All @@ -109,7 +109,7 @@ package schema
edges?: [...#AgentDelegationEdge]
coordinator?: string
concurrency?: int & >=1
evidence_policy?: "target" | "coordinator" | "both" @go(EvidencePolicy)
evidence_policy?: or(_evidencePolicyWord) @go(EvidencePolicy)
}

// Durable control-plane projection of a declarative team. The authored graph
Expand All @@ -128,15 +128,15 @@ package schema
owner: string & !=""
session_id?: #UUIDv7 @go(SessionID)
run_id?: #UUIDv7 @go(RunID)
state: "delegated" | "active" | "settled" | "failed"
state: or(_agentFederationRecordStateWord)
updated_at: string @go(UpdatedAt)
metadata?: #StrMap
}

#Incident: {
id: #UUIDv7 @go(ID)
run_id?: #UUIDv7 @go(RunID)
state: "needs_rca" | "rca_active" | "awaiting_recovery" | "resolved"
state: or(_incidentStateWord)
summary: string & !=""
created_at: string @go(CreatedAt)
evidence_refs?: [...string] @go(EvidenceRefs)
Expand All @@ -145,7 +145,7 @@ package schema
#RCARecord: {
id: #UUIDv7 @go(ID)
incident_id: #UUIDv7 @go(IncidentID)
state: "active" | "complete"
state: or(_rcaRecordStateWord)
findings?: [...string]
root_cause?: string @go(RootCause)
completed_at?: string @go(CompletedAt)
Expand All @@ -167,10 +167,10 @@ package schema
id: #UUIDv7 @go(ID)
incident_id: #UUIDv7 @go(IncidentID)
rca_id?: #UUIDv7 @go(RCAID)
action: "reattach" | "resume" | "restart" | "rebuild-target" | "change-runtime" | "reassign" | "abort" | "operator"
action: or(_recoveryDecisionActionWord)
authorized_emergency_abort?: bool @go(AuthorizedEmergencyAbort)
params?: #RecoveryParams @go(Params,type=*RecoveryParams)
state: "planned" | "applied" | "failed"
state: or(_recoveryDecisionStateWord)
decided_at: string @go(DecidedAt)
applied_at?: string @go(AppliedAt)
error?: string
Expand All @@ -187,12 +187,12 @@ package schema
semantic_adapter?: string @go(SemanticAdapter)
keys?: [...string]
signals?: [...string]
persistence?: "none" | "detach" | "required"
transcript?: "none" | "raw" | "screen" | "both"
persistence?: or(_terminalProfilePersistenceWord)
transcript?: or(_transcriptWord)
}

#TerminalInput: {
kind: "text" | "paste" | "command" | "key" | "resize" | "signal" | "close"
kind: or(_terminalInputKindWord)
text?: string
key?: string
cols?: int & >0 & <=1000
Expand All @@ -212,8 +212,8 @@ package schema
#TerminalFrame: {
run_id: #UUIDv7 @go(RunID)
sequence: int & >=1
kind: "raw" | "screen" | "status" | "exit" | "error" | "resync"
stream?: "stdout" | "stderr" | "terminal"
kind: or(_terminalFrameKindWord)
stream?: or(_streamWord)
data?: bytes
snapshot?: string
status?: string
Expand All @@ -237,3 +237,100 @@ package schema
reason?: string
time: string
}

// --- vocabulary tables (S3) --------------------------------------------------
// Every closed set of words is a table keyed by word, `<x>Word` is derived from it,
// and the enum an author meets is `or(<x>Word)` — so the table and the enum cannot
// disagree and a new word is ONE row here. `@vocab` names the owner (§3.1): these
// sets are compiled into THIS contract module, so the owner is `spec`.
//
// Each table is named after its word when that name is unique in the schema, and
// `<definition><Field>` when it is not; the comment above it names its site.

// #TargetHop.transport
_targetHopTransport: {inproc: {}, exec: {}, ssh: {}, grpc: {}, tmux: {}} @vocab(spec)
_targetHopTransportWord: [for w, _ in _targetHopTransport {w}]
// #AgentRuntimeCapability.interaction_modes
_interactionModes: {structured: {}, terminal: {}} @vocab(spec)
_interactionModesWord: [for w, _ in _interactionModes {w}]
// #AgentRuntimeCapability.persistence
_agentRuntimeCapabilityPersistence: {none: {}, session: {}, required: {}} @vocab(spec)
_agentRuntimeCapabilityPersistenceWord: [for w, _ in _agentRuntimeCapabilityPersistence {w}]
// #AgentSession.state
_agentSessionState: {new: {}, active: {}, detached: {}, closed: {}, failed: {}} @vocab(spec)
_agentSessionStateWord: [for w, _ in _agentSessionState {w}]
// #AgentEvent.type
_agentEventType: {
started: {}
message: {}
tool: {}
delegation: {}
settled: {}
status: {}
completed: {}
aborted: {}
failed: {}
} @vocab(spec)
_agentEventTypeWord: [for w, _ in _agentEventType {w}]
// #AgentTeam.evidence_policy
_evidencePolicy: {target: {}, coordinator: {}, both: {}} @vocab(spec)
_evidencePolicyWord: [for w, _ in _evidencePolicy {w}]
// #AgentFederationRecord.state
_agentFederationRecordState: {delegated: {}, active: {}, settled: {}, failed: {}} @vocab(spec)
_agentFederationRecordStateWord: [for w, _ in _agentFederationRecordState {w}]
// #Incident.state
_incidentState: {
needs_rca: {}
rca_active: {}
awaiting_recovery: {}
resolved: {}
} @vocab(spec)
_incidentStateWord: [for w, _ in _incidentState {w}]
// #RCARecord.state
_rcaRecordState: {active: {}, complete: {}} @vocab(spec)
_rcaRecordStateWord: [for w, _ in _rcaRecordState {w}]
// #RecoveryDecision.action
_recoveryDecisionAction: {
reattach: {}
resume: {}
restart: {}
"rebuild-target": {}
"change-runtime": {}
reassign: {}
abort: {}
operator: {}
} @vocab(spec)
_recoveryDecisionActionWord: [for w, _ in _recoveryDecisionAction {w}]
// #RecoveryDecision.state
_recoveryDecisionState: {planned: {}, applied: {}, failed: {}} @vocab(spec)
_recoveryDecisionStateWord: [for w, _ in _recoveryDecisionState {w}]
// #TerminalProfile.persistence
_terminalProfilePersistence: {none: {}, detach: {}, required: {}} @vocab(spec)
_terminalProfilePersistenceWord: [for w, _ in _terminalProfilePersistence {w}]
// #TerminalProfile.transcript
_transcript: {none: {}, raw: {}, screen: {}, both: {}} @vocab(spec)
_transcriptWord: [for w, _ in _transcript {w}]
// #TerminalInput.kind
_terminalInputKind: {
text: {}
paste: {}
command: {}
key: {}
resize: {}
signal: {}
"close": {}
} @vocab(spec)
_terminalInputKindWord: [for w, _ in _terminalInputKind {w}]
// #TerminalFrame.kind
_terminalFrameKind: {
raw: {}
screen: {}
status: {}
exit: {}
error: {}
resync: {}
} @vocab(spec)
_terminalFrameKindWord: [for w, _ in _terminalFrameKind {w}]
// #TerminalFrame.stream
_stream: {stdout: {}, stderr: {}, terminal: {}} @vocab(spec)
_streamWord: [for w, _ in _stream {w}]
Loading
Loading