repo-manager/docs/observation-command-contracts_v0.1.md

14 KiB

id type title status version created updated workplan_task depends_on related
RMGR-ARCH-CMD-0001 architecture Observation and command contracts v0.1 draft-reviewable 0.1 2026-08-09 2026-08-09 RMGR-WP-0001-T02
RMGR-ARCH-REP-0001
docs/repository-representation_v0.1.md
docs/observation-command-contracts_v0.1.yaml
INTENT.md
prj-state-hub-retirement/architecture/hub-extension-architecture_v0.1.md
prj-state-hub-retirement/architecture/information-model_v0.1.md

Observation and command contracts v0.1

Purpose

Define versioned, persistence-free contracts for:

  1. Observation — normalized repository facts and work-record index reads
  2. Commands — governed mutations with authz, idempotency, correlation, and Git-backed evidence
  3. Hub-core integration — how port.repo and port.work expose these without leaking SQLAlchemy models

Companion: observation-command-contracts_v0.1.yaml.

Implementation (OpenAPI generation, runtime) follows T04 foundation decision; this document freezes semantics for T03 extraction and T05 E2E proof.


Contract identity

Field Value
contract_id helixforge.repo-manager
contract_version 0.1.0 (draft-reviewable)
representation_ref RMGR-ARCH-REP-0001
Compatibility Additive in minor; breaking requires major + dual-run

Hard rule: Request/response DTOs are the public surface. Persistence schemas, table names, and ORM classes are private to Repo Manager.


Common envelope

Every API message (HTTP/JSON, event payload, or MCP tool result) SHOULD carry:

api_version: "0.1"
correlation_id: "<UUIDv7>"      # mint if client omits
request_id: "<UUIDv7>"          # per call
actor:
  type: human | agent | service
  id: "agt-…" | "user-…" | "svc-…"
authz:
  subject: "…"                  # identity principal
  scopes: ["repo:read", "repo:command:…"]
  decision: allow | deny        # on response if evaluated

Correlation

  • One human/agent action that spans observe → command → event uses one correlation_id.
  • Hub-core progress/interaction events that describe the same action reuse it (IA dual-write ban still applies: one semantic fact, correlated kinds).

Idempotency

Surface Key Behavior
Commands Idempotency-Key header or idempotency_key body (UUIDv7) Same key + same command type + same payload hash → return original result; conflict if payload differs
Observation none required Safe to retry; may return fresher observed_at
Writeback key includes repo_uuid + source_path + content hash Replay does not double-commit if evidence SHA already recorded

Retention of idempotency records: ≥ 24h (operational policy may extend).

Evidence object

Returned on every completed command (success or handled failure after partial work):

evidence:
  status: accepted | applied | rejected | failed
  git_sha: "…" | null          # primary proof when applied
  git_refs: ["refs/heads/…"]   # optional
  forge_pr_url: null | "…"
  files_touched: ["path", …]
  content_hashes: { "path": "sha256:…" }
  observed_at: "ISO-8601"
  notes: "non-secret"

Rule: status: applied without git_sha is invalid for file-mutating commands (except pure operator-config commands that only change host_paths).

Failure model

Code HTTP-ish Meaning Client action
unauthorized 401/403 Authn/authz failed Fix credentials/scopes
not_found 404 Unknown repo or record Re-resolve slug/uuid
conflict 409 Drift, lock, or idempotency payload mismatch Re-observe; resolve drift
precondition_failed 412 Stale expected_head_sha / base revision Refresh HEAD; retry
validation_error 422 Schema/vocab/command args invalid Fix request
policy_denied 403 Policy port deny Escalate / change policy
unavailable 503 Forge/git/policy/hub down Retry with backoff
internal 500 Unexpected Operator; attach correlation_id

Failures are structured JSON, never raw stack traces to external clients.

error:
  code: conflict
  message: "Index drift on workplans/RMGR-WP-0001-foundation.md"
  correlation_id: "…"
  details:
    finding_ids: ["…"]
  retryable: false

Authorization context

Commands and sensitive observation paths require:

Field Source
subject Identity authority / hub-core addressing
scopes Policy (examples below)
repo_uuid or repo_slug Resource
lane Optional autonomy lane for agent actors
reason Required for high-risk commands

Scope vocabulary (v0.1)

Scope Allows
repo:read Observation of representation + index
repo:register Create/update registration & host_paths
repo:reconcile Run consistency / rebuild projections
repo:command:work_status File-backed status writeback (task/WP)
repo:command:writeback_ids UUID / hub id frontmatter writeback
repo:command:lifecycle lifecycle transitions (archive, …)
repo:command:agent_assign coach/lead/director assignment
repo:admin Break-glass operator

Policy port: Repo Manager evaluates via hub-core port.policy (or local allowlist in dev). It does not become the authorization authority.

Green-lane agents may hold only repo:read + narrow command scopes per autonomy policy; non-green requires explicit human/policy allow.


Observation contract (port.repo / port.work reads)

Normalized fact types

Fact Description Source of truth
RepositorySnapshot ManagedRepository DTO (REP-0001) files + operator + git observation
WorkRecordIndexEntry spine fields for one work record file + index
ConsistencyFinding open C-rule style finding derived
RevisionObservation head_sha, dirty, observed_at git
AgentAssignment coach/lead/director file/registry projection
SignalSet named derived signals derived

Read operations

Op Port Request Response
GetRepository repo slug or uuid RepositorySnapshot
ListRepositories repo filters: domain, category, lifecycle, tag page of snapshots
ObserveRevision repo slug, optional host_id RevisionObservation
ListWorkRecords work repo, kind?, status? page of index entries
GetWorkRecord work uuid or (repo, canonical_id) entry + source_path
ListFindings repo repo, open_only? findings
GetSignals repo repo SignalSet

Pagination: cursor or limit/offset with stable sort (slug / updated_at). No ORM objects in responses.

Observation guarantees

  • Read-your-writes: After applied command with git_sha, a subsequent GetRepository/GetWorkRecord within the same process generation MUST reflect that revision or return observed_at older with explicit stale: true and head_sha for client retry.
  • Rebuild: Full reindex from files produces equivalent index content (modulo mint of new UUIDs only for records never writeback-assigned).

Command contract (governed mutations)

Command lifecycle

accepted → (running) → applied | rejected | failed
State Meaning
accepted Validated, authz allow, idempotency recorded; not yet on Git
running Optional intermediate for long ops
applied Evidence includes git_sha (or config-only evidence)
rejected Policy/validation; no mutation
failed Started but did not complete cleanly; may need repair

Clients MUST treat only applied as success for dependent steps.

Command envelope

command:
  type: "repo.work.update_task_status"   # cataloged
  api_version: "0.1"
  idempotency_key: "…"
  correlation_id: "…"
  repo: { slug: "repo-manager" }         # or uuid
  expected_head_sha: "…" | null          # optimistic concurrency
  actor: { type: agent, id: "…" }
  reason: "session checkpoint"
  params: { … }                          # type-specific

Command catalog (v0.1)

Registration & operator config

Type Params Mutates Git? Scope
repo.register slug, remote_url?, classification?, description? no* repo:register
repo.set_host_path host_id, path no repo:register
repo.set_lifecycle lifecycle, reason no** repo:command:lifecycle

* May write registration notes only if a repo file policy says so (default: no).
** Lifecycle is projection+operator state; forge archive is separate/explicit.

Observation-triggered

Type Params Mutates Git? Scope
repo.reconcile full? paths? no (index only) repo:reconcile
repo.rebuild_index kinds? no repo:reconcile

File-backed work (writeback)

Type Params Mutates Git? Scope
repo.work.update_task_status task_id, status, blocking_reason? yes repo:command:work_status
repo.work.update_workplan_status workplan_id, status yes repo:command:work_status
repo.work.create_workplan workplan_id, title, goal, status?, owner?, domain?, topic_slug? yes repo:command:workplan
repo.work.update_workplan workplan_id, title?, status?, owner?, domain?, topic_slug? yes repo:command:workplan
repo.work.archive_workplan workplan_id, confirm_archive yes repo:command:workplan
repo.work.writeback_ids record_ref, uuid fields yes repo:command:writeback_ids
repo.register.upsert_entry kind, entry_id, title?, status?, data? yes repo:command:register
repo.register.defer_entry kind, entry_id, status? yes repo:command:register
repo.register.add_note kind, entry_id, note, author? yes repo:command:register

repo.work.archive_workplan is the recoverable delete operation: it sets the canonical status to archived and moves the file under the dated workplans/archived/ convention. It does not erase repository history.

Agents

Type Params Mutates Git? Scope
repo.agents.assign coach?, lead?, director? prefer yes (file) repo:command:agent_assign

Command execution rules

  1. Authz first — deny before any file lock.
  2. Load observation — if expected_head_sha set and differs → precondition_failed.
  3. Drift gate — mutating commands on a path with open high-severity finding → conflict unless force: true + repo:admin.
  4. Apply — single atomic Git commit per command preferred; message includes correlation_id and command type.
  5. Reindex — update projections for touched paths.
  6. Emit — repository change event (IA: repository_change_event) with correlation_id; hub-core may project further.
  7. Never create workplans/tasks from telemetry or messages alone.

What is not a Repo Manager command

Action Owner
Send agent message / inbox hub-core port.messaging
Append progress event hub-core port.events.progress
Schedule cron / ops run activity-core port.schedule
Merge PR on forge without Git in checkout forge + human policy (optional later adapter)
Policy decision policy service

Events emitted

Event type When Payload (non-secret)
repo.registered register slug, uuid, domain
repo.observed optional periodic slug, head_sha
repo.reconciled reconcile done finding counts
repo.command.applied command success type, git_sha, files
repo.command.failed command fail type, code
repo.work.indexed new/updated index entry kind, id, path
repo.drift.detected new finding finding summary

Consumers: hub-core projections, activity-core triggers. Payloads MUST NOT include secrets, raw tokens, or full file contents by default (hashes + paths only).


Hub-core integration

  agents / domain hubs / MCP
            │
            ▼
        hub-core
     port.repo │ port.work
            │
            ▼
       repo-manager
      (this contract)
            │
            ▼
     Git checkouts + files
Hub-core need Repo Manager op
Address a repository GetRepository
Orient on repo work ListWorkRecords + signals
Apply agent task status repo.work.update_task_status
Consistency automation repo.reconcile (often via activity-core)
Domain summary (partial) snapshots + work counts

Hub-core must not:

  • open Repo Manager DB connections;
  • import repo_manager.models;
  • dual-write work status only to its own DB without command evidence.

During State Hub dual-run, a compatibility adapter may implement the same command types by calling State Hub APIs, then flip to native RM (T03/T05).


MCP / CLI mapping (illustrative)

User intent Contract
statehub fix-consistency (today) repo.reconcile (+ legacy adapter)
update_task_status MCP repo.work.update_task_status when cut over
register-from-classification repo.register + classification observe

Exact tool names land with runtime packaging (T04).


Conformance tests (minimum for T05)

# Test
C1 GetRepository returns DTO without ORM fields
C2 Reconcile is idempotent on clean tree
C3 update_task_status with same idempotency_key replays
C4 Stale expected_head_sha → precondition_failed
C5 Deny without scope → unauthorized/policy_denied
C6 applied response always has git_sha for file commands
C7 Rebuild index matches prior entries for UUID-written records
C8 Event payload has correlation_id and no secret keys

Acceptance (T02)

  • Normalized observation facts and read ops defined
  • Command catalog with lifecycle, scopes, evidence
  • Idempotency, correlation, failure model specified
  • Authz context and policy port boundary stated
  • Hub-core port mapping without persistence leakage
  • Machine-readable companion YAML
  • Runtime OpenAPI + automated suite (T04/T05)