@startuml
!theme plain
title Turnstone — Workstream Template Architecture

skinparam participant {
    BackgroundColor<<admin>> #E8EAF6
    BackgroundColor<<server>> #FFE0B2
    BackgroundColor<<session>> #C8E6C9
    BackgroundColor<<storage>> #B3E5FC
    BackgroundColor<<integration>> #F3E5F5
}

participant "Admin / Console UI\n(governance.js)" as Admin <<admin>>
participant "Server\n(server.py)" as Server <<server>>
participant "ChatSession\n(session.py)" as Session <<session>>
participant "StorageBackend\n(SQLite)" as Storage <<storage>>
participant "Integration Points\n(scheduler, channel,\nbridge, MQ)" as Integrations <<integration>>

== Admin CRUD ==

Admin -> Server : POST /v1/api/admin/ws-templates
note right
  **Payload:**
  name, model, system_prompt,
  temperature, reasoning_effort,
  max_tokens, agent_max_turns,
  auto_approve, auto_approve_tools,
  token_budget, prompt_template,
  prompt_template_hash, notify_on_complete
end note

Server -> Storage : create_ws_template()
Storage --> Server : ws_template_id

Admin -> Server : PUT /v1/api/admin/ws-templates/{id}
Server -> Storage : get_ws_template(id)\n(snapshot pre-update state)
Storage --> Server : existing template
Server -> Storage : create_ws_template_version()\n(version snapshot)
Server -> Storage : update_ws_template(id, ...)
note right
  **Versioning:**
  Each update snapshots
  pre-update state into
  workstream_template_versions.
  version counter increments.
end note

Admin -> Server : GET /v1/api/admin/ws-templates
Server -> Storage : list_ws_templates()

Server <-- Server : GET /v1/api/ws-templates\n(read scope, summary only)
note right
  **Read-only listing:**
  name, description, model.
  Used by creation UI dropdowns.
  Available on both server + console.
end note

Admin -> Server : DELETE /v1/api/admin/ws-templates/{id}
Server -> Storage : delete_ws_template(id)

== Workstream Creation Flow ==

Integrations -> Server : CreateWorkstreamMessage\n(ws_template="production-agent")
note right
  **Sources:**
  - Console UI (Profile dropdown)
  - Scheduler (ws_template field)
  - Channel Router (ws_template)
  - Bridge (ws_template forwarding)
  - MQ Client (ws_template)
end note

Server -> Storage : get_ws_template_by_name("production-agent")
Storage --> Server : template dict

Server -> Server : resolve_ws_template()\napply model override
note right
  **Settings applied:**
  - model (overrides default)
  - system_prompt
  - temperature
  - reasoning_effort
  - max_tokens
  - agent_max_turns
  - auto_approve / auto_approve_tools
  - token_budget
  - tool_search config
end note

Server -> Session : mgr.create(model=template.model, ...)
Session -> Session : _init_system_messages()

alt template has prompt_template
    Session -> Storage : get_prompt_template_by_name()
    Session -> Session : _render_template()\n{{model}}, {{ws_id}}, {{node_id}}
end

Session -> Storage : _save_config()\n+ ws_template_id, ws_template_version

== Drift Detection ==

Server -> Server : compute prompt_template_hash\n(at creation time)
note right
  **Hash stored:**
  SHA-256 of prompt_template
  content at ws creation time.
  Compared at next creation
  to detect upstream changes.
end note

Server -> Storage : update_workstream()\n(store prompt_template_hash)

... later, new workstream created ...

Server -> Storage : get_ws_template()
Server -> Server : compare hash vs\ncurrent prompt_template content
alt hash mismatch
    Server -> Server : log.warning(\n"prompt template drift detected")
end

== Token Budget Enforcement ==

Session -> Session : send(message)
Session -> Session : _check_budget_gate()
note right
  **Budget gate:**
  if token_budget set:
    total = prompt_tokens + completion_tokens
    if total >= token_budget:
      block further sends
end note

alt budget exceeded
    Session -> Session : approve_tools(\n__budget_override__)
    note right
      Model can request
      budget override via
      special approval label.
      User must approve.
    end note
else within budget
    Session -> Session : continue normal flow
end

== Storage Schema ==

note over Storage
  **workstream_templates**
  id, name (unique), model, system_prompt,
  temperature, reasoning_effort, max_tokens,
  agent_max_turns, auto_approve, auto_approve_tools,
  token_budget, prompt_template, prompt_template_hash,
  tool_search, tool_search_threshold, tool_search_max_results,
  version, created_at, updated_at

  **workstream_template_versions**
  id, template_id (FK), version, snapshot (JSON),
  created_at

  **workstreams** (updated columns)
  + ws_template_id: str | None
  + ws_template_version: int | None

  **scheduled_tasks** (updated column)
  + ws_template: str | None
end note

@enduml
