Skip to content

Agent Versioning

Status: accepted + shipped (2026-07-13) · Full ADR archived at .indusk/planning/archive/agent-versioning/adr.md

Decision

A hosted agent is one stable identity per owner (hosted_agents.id, get-or-create, a unique owner_user_id index) that carries immutable snapshots in a new agent_versions table holding two spaces:

  • Versions — a single linear retained pathway (v1 → v2 → v3 …, append-only, every version archived-not-deleted). Revert re-deploys any prior version by moving a pointer; it does not rewrite history (a later commit still appends forward).
  • Drafts — a separate creator-named, forkable experiment space. Committing a draft appends it as the next version.

A version freezes decision-shaping fields onlystrategy / model / fallback_model / skill / agent_skills. Identity fields (name / avatar / subtitle) stay mutable and unversioned.

Load-bearing rules

  • Only the published version is seatable at real games. It's bound into AgentDeployment at the single /seat snapshot point; drafts are rejected at the real-table gate. Concurrent seats all run the same published version (no mid-game drift).
  • Off-every-table lock is pointer-scoped. An agent seated at any table cannot publish or revert until off every table (those move the pointer new seats bind). Drafts + identity stay editable while seated — they never affect live play. Enforced at the route and inside the publish/revert transaction under a per-agent advisory lock the seat-claim path also takes (closes the publish-vs-seat TOCTOU).
  • Every decision record is version-attributable. agent_version_id is stamped on agent_inference_charges, agent_call_records, decision_observations, and hosted_agent_seats.
  • One agent per owner retires the roster. Every "pick which agent" affordance (seat/tournament/copilot) collapses to auto-pick the single agent.
  • Fingerprint, dormant anchor. Publishing mints a version_hash (keccak of the canonical frozen bytes) + dormant anchored_at/anchor_tx columns. The real encrypt/anchor is deferred to agent-version-onchain-anchor.

Key tradeoffs accepted

  • Publish snapshots the draft in place (draft row → published) rather than minting a new agent row — keeps every agent_id FK / history stable (a publish-mints-new-agent design fragments them).
  • Storage migration is a reader-migration. Phase 6 dropped the legacy decision columns from hosted_agents; getHostedAgent / listHostedAgentsByUser now LEFT JOIN the published version and alias the fields back onto the same names, so the play-path readers were untouched.
  • Destructive pre-launch dev reset — multi-agent test data was wiped to one-per-owner (backfilled a v1 per agent); no graceful multi-agent conversion.

Blocks agent-decision-inspection (needs version tags + the draft/commit fix-loop) and agent-training-sandbox (drafts are its test substrate).