Complete architecture document set with multi-model review remediation: - Frozen interface contracts, runtime semantics, DB schemas - Event/tool/error/provider registries - Scheduler and main agent state machines - C4 module/code views, solution architecture, baseline V1 - Multi-model review reports and joint assessment - Phase-gate remediation complete (P0/P1/P2/UX resolved) - Implementation plan with T-000A through T-045 - Reference folders kept as placeholders only
436 lines
14 KiB
Markdown
436 lines
14 KiB
Markdown
# AirCoding Runtime Semantics V1
|
|
|
|
Date: 2026-05-27
|
|
Status: Canonical runtime semantics corrections for V1.0.0 Alpha
|
|
|
|
This document resolves implementation-critical semantics that cut across the event registry, DB schema, Scheduler, ArtifactStore, PermissionEngine, ContextAssembler, and ExperienceMiner.
|
|
|
|
## 1. Source of Truth
|
|
|
|
This document refines, not replaces:
|
|
|
|
- `interface-contracts-v1.md`
|
|
- `event-registry-v1.md`
|
|
- `db-schema-v1.md`
|
|
- `scheduler-state-machine-v1.md`
|
|
- `artifact-naming-v1.md`
|
|
- `security-model-v1.md`
|
|
|
|
If a runtime behavior conflicts with older wording, this document is authoritative for V1.0.0 Alpha runtime semantics.
|
|
|
|
## 2. Event Ingestion Boundary
|
|
|
|
All runtime events from workers, tools, agents, and internal services enter through `EventIngestor`.
|
|
|
|
```text
|
|
producer
|
|
→ EventIngestor.ingest(event)
|
|
→ schema/version validation
|
|
→ persistence policy lookup
|
|
→ durable: EventStore transaction + domain projection + post-commit EventBus publish
|
|
→ ephemeral: EventBus publish/coalescing only
|
|
```
|
|
|
|
Responsibilities:
|
|
|
|
| Component | Responsibility |
|
|
|---|---|
|
|
| EventIngestor | accepts events, validates routing, chooses durable vs ephemeral path |
|
|
| EventStore | validates durable event payload, inserts event, applies domain projection transactionally |
|
|
| EventBus | live publish/subscribe only |
|
|
| Domain services | emit follow-up events; do not hide policy inside EventStore |
|
|
|
|
EventStore must not create scheduler tasks, permission decisions, memory promotions, or doctor fixes by policy. Those are follow-up actions emitted by the owning services.
|
|
|
|
## 3. Durable Projection Rule
|
|
|
|
For same-session DB domain updates:
|
|
|
|
```text
|
|
BEGIN
|
|
insert events row
|
|
apply domain table projection
|
|
COMMIT
|
|
publish committed event to EventBus
|
|
```
|
|
|
|
For external DB/file side effects, use the cross-store semantics in section 6.
|
|
|
|
## 4. Heartbeat Semantics
|
|
|
|
`agent.heartbeat` remains an ephemeral event for live UI updates, but Scheduler must coalesce heartbeat timestamps into domain rows.
|
|
|
|
Rule:
|
|
|
|
```text
|
|
agent.heartbeat event
|
|
→ EventBus live publish
|
|
→ Scheduler/AgentMonitor updates agents.last_heartbeat_at and tasks.heartbeat_at at a throttled interval
|
|
```
|
|
|
|
Default coalescing interval:
|
|
|
|
```text
|
|
5 seconds or meaningful status change, whichever comes first
|
|
```
|
|
|
|
Recovery uses `agents.last_heartbeat_at`, `tasks.heartbeat_at`, process liveness, and task attempt state. It does not require replaying ephemeral heartbeat events.
|
|
|
|
## 5. Command Run Status Semantics
|
|
|
|
`command_runs` V1 schema has no explicit `status` column. Runtime derives status:
|
|
|
|
| Row state | Derived status |
|
|
|---|---|
|
|
| `completed_at` is null | `running` |
|
|
| `exit_code = 0` | `ok` |
|
|
| `exit_code` non-zero | `error` |
|
|
| cancellation metadata present | `cancelled` |
|
|
| inconsistent row | `unknown` |
|
|
|
|
ProjectionStore may expose derived command status. A later schema version may add a physical `status` column if needed.
|
|
|
|
## 6. Cross-DB and File Transaction Semantics
|
|
|
|
Some durable events refer to project-level DBs or files outside the session DB:
|
|
|
|
```text
|
|
debug-records.db
|
|
learned-memory.db
|
|
.air/shared/rules/*.md
|
|
skills
|
|
artifact files
|
|
workspace files
|
|
```
|
|
|
|
SQLite cannot provide one transaction across arbitrary files and DBs. V1.0.0 Alpha uses an outbox/compensation model.
|
|
|
|
### 6.1 Session DB First For Intent
|
|
|
|
For external side effects:
|
|
|
|
```text
|
|
1. Insert durable session event recording intent/request.
|
|
2. Insert or update session domain row with pending/external status where applicable.
|
|
3. Perform external DB/file operation through owning service.
|
|
4. Emit durable completed/failed event with evidence.
|
|
5. On restart, recovery scans pending external intents and reconciles.
|
|
```
|
|
|
|
### 6.2 Artifact Files
|
|
|
|
Artifact files use:
|
|
|
|
```text
|
|
write temp file
|
|
compute hash/size
|
|
atomic rename
|
|
insert artifact row + artifact.created event
|
|
```
|
|
|
|
If the DB insert fails after rename, startup recovery scans orphaned files and either registers or quarantines them.
|
|
|
|
### 6.3 Debug Records
|
|
|
|
`debug.record.created` means:
|
|
|
|
```text
|
|
session DB records debug-record intent/completion event
|
|
DebugKnowledgeStore writes debug-records.db
|
|
if debug-records.db write fails, emit debug.record.failed or task.failed with AirError
|
|
```
|
|
|
|
### 6.4 Memory and Rule Promotion
|
|
|
|
`memory.promoted` means:
|
|
|
|
```text
|
|
candidate was approved/promoted by owning service
|
|
rule/skill/learned-memory write is performed by ExperienceMiner/Curator service
|
|
session event records completed promotion and target ref
|
|
```
|
|
|
|
If the file/DB write fails, emit a failure event and leave the candidate unpromoted or pending repair.
|
|
|
|
## 7. Summary and Compaction Ownership
|
|
|
|
Only `summary.created` inserts a `summaries` row.
|
|
|
|
`context.compaction.completed` records compaction task completion and references the created summary:
|
|
|
|
```ts
|
|
interface ContextCompactionCompletedPayload {
|
|
task_id?: string
|
|
agent_id?: string
|
|
summary_id: string
|
|
range_start_message_id?: string
|
|
range_end_message_id?: string
|
|
token_estimate_before?: number
|
|
token_estimate_after?: number
|
|
}
|
|
```
|
|
|
|
Sequence:
|
|
|
|
```text
|
|
context.compaction.requested
|
|
context.compaction.started
|
|
summary.created
|
|
context.compaction.completed
|
|
```
|
|
|
|
This avoids duplicate summary rows.
|
|
|
|
## 8. Permission Layering
|
|
|
|
Permission evaluation order:
|
|
|
|
```text
|
|
1. tool capability declaration
|
|
2. permission profile
|
|
3. TaskSpec scope allowed/denied paths
|
|
4. path/command/network risk classification
|
|
5. credential/system-sensitive override
|
|
6. user prompt workflow if required
|
|
```
|
|
|
|
Project-level allow does not override task scope. Credential and system-sensitive boundaries override broad project/local allow.
|
|
|
|
Canonical decision:
|
|
|
|
```ts
|
|
action: allow | deny | ask_user | block | refuse | announce_then_run
|
|
grant_scope: none | once | session | project | global
|
|
```
|
|
|
|
## 9. Execution Primitive Semantics
|
|
|
|
Claude Code-quality execution is enforced through tool contracts, not only prompts.
|
|
|
|
### 9.1 Read-Before-Edit Token
|
|
|
|
`fs.read` returns or records a read observation:
|
|
|
|
```ts
|
|
interface FileReadObservation {
|
|
path: string
|
|
sha256?: string
|
|
observed_at: ISOTimeString
|
|
task_id?: TaskID
|
|
agent_id?: AgentID
|
|
}
|
|
```
|
|
|
|
`fs.edit` and `fs.patch` require either:
|
|
|
|
```text
|
|
active task read observation for the target file
|
|
or explicit expected_existing_sha256
|
|
```
|
|
|
|
### 9.2 Exact Edit Behavior
|
|
|
|
`fs.edit` rules:
|
|
|
|
1. `old_string` must match exactly.
|
|
2. If `replace_all` is false, `old_string` must occur exactly once.
|
|
3. If no match or ambiguous match, fail with `tool_error` and no file write.
|
|
4. The tool does not guess indentation or nearby replacements.
|
|
5. Successful edit emits a diff artifact.
|
|
|
|
### 9.3 Patch Behavior
|
|
|
|
`fs.patch` rules:
|
|
|
|
1. Patch paths must be within task scope and permission policy.
|
|
2. Rejected hunks become artifacts.
|
|
3. Partial patch application is allowed only if the patch tool can prove unchanged rejected paths were not written; otherwise fail atomically.
|
|
4. Successful patch emits a diff artifact.
|
|
|
|
### 9.4 Completion Gate
|
|
|
|
A code-changing WorkerResult cannot be `completed` unless:
|
|
|
|
```text
|
|
required verification passed, or
|
|
verification is explicitly skipped with reason/evidence/risk, and fallback_allowed is true
|
|
```
|
|
|
|
## 10. Project Scanner Semantics
|
|
|
|
Project initialization scanner collects full directory tree metadata with no directory exclusion and no depth limit.
|
|
|
|
Rationale: the user wants complete project shape visibility, and directory tree metadata alone is not comparable to reading file contents.
|
|
|
|
Safety boundaries:
|
|
|
|
1. Do not recurse through symlinks by default; record symlink target metadata instead.
|
|
2. Handle permission errors as entries with error metadata, not fatal scanner failure.
|
|
3. Avoid reading file contents during tree scan.
|
|
4. Record special file types without opening them.
|
|
5. Provide progress and cancellation hooks for UI responsiveness.
|
|
6. Detect obvious filesystem cycles or mount anomalies and record them as scanner warnings.
|
|
|
|
No directories such as `.git`, `node_modules`, build directories, or vendor directories are excluded from the directory tree.
|
|
|
|
## 11. Learning, Skills, and Experience Lifecycle
|
|
|
|
ExperienceMiner produces candidates; it does not silently rewrite durable project rules or skills unless assigned an explicit promotion task.
|
|
|
|
Lifecycle:
|
|
|
|
```text
|
|
candidate.created
|
|
→ evidence threshold check
|
|
→ user/project policy approval
|
|
→ promotion write through owning store
|
|
→ memory.promoted or promotion failed
|
|
→ rollback/archive if stale or harmful
|
|
```
|
|
|
|
Candidate types:
|
|
|
|
```text
|
|
project_rule
|
|
toolchain_rule
|
|
skill_update
|
|
debug_experience
|
|
```
|
|
|
|
Promotion requirements:
|
|
|
|
| Candidate | Promotion requirement |
|
|
|---|---|
|
|
| debug_experience | verified failure + fix evidence |
|
|
| project_rule | repeated pattern or explicit user confirmation |
|
|
| toolchain_rule | verified toolchain evidence or explicit user confirmation |
|
|
| skill_update | reviewed patch and trust policy approval |
|
|
|
|
Skills use Claude Skills-style directory structure where applicable:
|
|
|
|
```text
|
|
SKILL.md
|
|
scripts/
|
|
references/
|
|
assets/
|
|
```
|
|
|
|
Skill invocation must pass through capability/tool trust rules when it causes side effects.
|
|
|
|
## 12. C++ Diagnostic Ownership
|
|
|
|
`toolchain-cpp` owns deterministic extraction of compiler/test/static-analysis diagnostics and semantic signatures.
|
|
|
|
LLM-based interpretation belongs to runtime Debugger/Reviewer context, not hidden inside low-level toolchain code, unless a future injected diagnostic interpretation service is explicitly added.
|
|
|
|
This preserves package direction:
|
|
|
|
```text
|
|
toolchain-cpp → contracts
|
|
runtime/debugger → llm/provider facade
|
|
```
|
|
|
|
## 13. V1.0.0 Alpha Cut Line
|
|
|
|
V1.0.0 Alpha includes:
|
|
|
|
```text
|
|
complete C++ configure/build/test/static-analysis/debug/fix/review workflow
|
|
local and built-in capability manifests
|
|
GUI/network evidence tools
|
|
TUI/HUD projection
|
|
release gates for Linux tier 1
|
|
```
|
|
|
|
V1.0.0 Alpha may defer:
|
|
|
|
```text
|
|
third-party plugin registry/signing
|
|
container sandboxing
|
|
multi-machine scheduling
|
|
Windows-native deep support
|
|
advanced semantic merge
|
|
production bitmap image generation providers
|
|
```
|
|
|
|
## 14. FK-Off Application Invariants
|
|
|
|
With `foreign_keys = OFF`, the runtime must enforce referential consistency in application code.
|
|
|
|
Invariants:
|
|
|
|
1. `tasks.session_id` must reference an existing `sessions.id`.
|
|
2. `task_attempts.task_id` must reference an existing `tasks.id`.
|
|
3. `agents.task_id` must reference an existing `tasks.id` when not null.
|
|
4. `tool_runs.task_id`, `tool_runs.agent_id` must reference existing rows when not null.
|
|
5. `command_runs.task_id`, `command_runs.agent_id`, `command_runs.tool_run_id` must reference existing rows when not null.
|
|
6. `workspaces.task_id`, `workspaces.agent_id` must reference existing rows when not null.
|
|
7. `diagnostics.command_run_id`, `diagnostics.artifact_id` must reference existing rows when not null.
|
|
8. `evidence_refs` foreign columns must reference existing rows when not null.
|
|
|
|
Enforcement:
|
|
|
|
- Repository insert methods validate foreign key existence before insert.
|
|
- On session startup recovery, run orphan scan: rows referencing deleted parents are logged and either re-parented or archived.
|
|
- Release gate includes orphan scan validation.
|
|
|
|
## 15. Workspace GC Policy
|
|
|
|
`<project>/.air/local/workspaces/` and the `workspaces` table grow over time.
|
|
|
|
Retention rules:
|
|
|
|
1. Active workspaces (`status = active`) are preserved until merge or explicit cancel.
|
|
2. Merged workspaces (`status = merged`) are preserved for 7 days after `merged_at`, then cleaned.
|
|
3. Conflicted workspaces (`status = conflicted`) are preserved until user/system decision, then moved to `abandoned`.
|
|
4. Abandoned workspaces are preserved for 3 days, then cleaned.
|
|
5. `cleaned` status means filesystem artifacts removed; DB row retained with metadata.
|
|
|
|
Cleanup runs on session startup and periodically during idle.
|
|
|
|
## 16. Direct Mode Semantics
|
|
|
|
`/direct` enters a foreground execution lane where Main Agent acts with Executor-level permissions without dispatching to Scheduler.
|
|
|
|
Rules:
|
|
|
|
1. Direct mode is a Main Agent state, not a separate agent type.
|
|
2. Direct mode uses `permission_template: "main_direct"`.
|
|
3. Direct mode tasks write to the main workspace only; no worktree creation.
|
|
4. Direct mode does not block Scheduler-owned background tasks from running concurrently.
|
|
5. `/done` exits direct mode, triggers evidence collection, and returns to IDLE.
|
|
6. Direct mode changes are recorded in the event log with `source.kind = "main"` and metadata indicating direct mode.
|
|
|
|
## 17. ExperienceMiner Trigger Ownership
|
|
|
|
ExperienceMiner is triggered by:
|
|
|
|
1. `debug.record.created` event → Scheduler creates `mine_experience` task.
|
|
2. Session end → Scheduler creates final `mine_experience` task.
|
|
3. N-turn/tool-call interval (configurable, default 10) → Scheduler creates periodic `mine_experience` task.
|
|
4. Stale rule/skill discovered during execution → worker emits `memory.candidate.created` with `memory_type = skill_update`, Scheduler creates `mine_experience` task.
|
|
|
|
The Scheduler owns trigger creation; ExperienceMiner never self-triggers. Curator periodic dedup runs as a scheduled `mine_experience` task with `memory_type = "curator_dedup"`.
|
|
|
|
## 18. Doctor Self-Bootstrap
|
|
|
|
Doctor validates its own prerequisites before running capability checks:
|
|
|
|
1. Verify Bun runtime version.
|
|
2. Verify SQLite availability.
|
|
3. Verify basic shell access.
|
|
4. Verify `.air/` directory writability.
|
|
5. Then proceed to capability/dependency checks.
|
|
|
|
If self-bootstrap fails, Doctor reports a `blocking` issue and skips remaining checks.
|
|
|
|
## 19. air restore Semantics
|
|
|
|
`air restore` supports three granularities:
|
|
|
|
1. `air restore file <path>` — restore most recent backup of a single file.
|
|
2. `air restore time <timestamp>` — restore all files backed up since a given timestamp.
|
|
3. `air restore session <session-id>` — restore all files backed up during a specific session.
|
|
|
|
All restore operations use the git-backed backup repository at `<project>/.air/local/backups/`. Restore creates a new commit with the restored content, preserving full history.
|