183 lines
6.5 KiB
Markdown
183 lines
6.5 KiB
Markdown
|
|
---
|
|||
|
|
id: RMGR-ADR-001
|
|||
|
|
type: architecture-decision-record
|
|||
|
|
title: "Implementation foundation for Repo Manager"
|
|||
|
|
status: accepted
|
|||
|
|
decided: "2026-08-09"
|
|||
|
|
workplan_task: RMGR-WP-0001-T04
|
|||
|
|
deciders: ["codex", "project-convention"]
|
|||
|
|
related:
|
|||
|
|
- docs/repository-representation_v0.1.md
|
|||
|
|
- docs/observation-command-contracts_v0.1.md
|
|||
|
|
- docs/state-hub-extraction-inventory_v0.1.md
|
|||
|
|
- INTENT.md
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# ADR-001: Implementation foundation for Repo Manager
|
|||
|
|
|
|||
|
|
## Status
|
|||
|
|
|
|||
|
|
**Accepted** (2026-08-09).
|
|||
|
|
|
|||
|
|
## Context
|
|||
|
|
|
|||
|
|
RMGR-WP-0001 requires a runtime, persistence, packaging, migration, test, and
|
|||
|
|
deployment shape **before** substantial extraction from State Hub (T03 phases
|
|||
|
|
P0–P5, T05 E2E). Choices must match ordinary HelixForge services so dual-run,
|
|||
|
|
operators, and agents do not face a one-off stack.
|
|||
|
|
|
|||
|
|
Reference platforms:
|
|||
|
|
|
|||
|
|
| Repo | Role | Stack |
|
|||
|
|
| --- | --- | --- |
|
|||
|
|
| `state-hub` | Current repo index + consistency (extract source) | Python 3.12, FastAPI, SQLAlchemy async, asyncpg, Alembic, uv, FastMCP |
|
|||
|
|
| `hub-core` | Shared library | Python 3.12, FastAPI/SQLAlchemy primitives, hatchling |
|
|||
|
|
| `core-hub` | Production hub runtime | Same + Docker/k8s |
|
|||
|
|
| `activity-core` | Schedulers/executors | Python, FastAPI, SQLAlchemy async, Alembic, Temporal (domain-specific) |
|
|||
|
|
|
|||
|
|
Repo Manager is a **functional component** (not a domain hub): service + CLI,
|
|||
|
|
own data plane for projections, Git as file authority.
|
|||
|
|
|
|||
|
|
## Decision
|
|||
|
|
|
|||
|
|
### 1. Language and packaging
|
|||
|
|
|
|||
|
|
| Choice | Decision |
|
|||
|
|
| --- | --- |
|
|||
|
|
| Language | **Python 3.12+** |
|
|||
|
|
| Layout | **`src/repo_manager/`** (src-layout, hatchling) |
|
|||
|
|
| Distribution | Installable package `repo-manager` / import `repo_manager` |
|
|||
|
|
| Tooling | **uv** + **Makefile** (fleet norm) |
|
|||
|
|
| Lint (phase 2) | ruff (align with core-hub when CI lands) |
|
|||
|
|
|
|||
|
|
### 2. Runtime surface
|
|||
|
|
|
|||
|
|
| Choice | Decision |
|
|||
|
|
| --- | --- |
|
|||
|
|
| HTTP API | **FastAPI** (async) implementing `helixforge.repo-manager` 0.1 |
|
|||
|
|
| ASGI server | **uvicorn** |
|
|||
|
|
| Settings | **pydantic-settings** |
|
|||
|
|
| DTOs | **Pydantic v2** only at API boundary (no ORM leakage) |
|
|||
|
|
| CLI | Entry point **`rmgr`** (`repo_manager.cli`) — `reconcile`, `register`, later `command` |
|
|||
|
|
| MCP | **Not day-1** — agents keep State Hub / hub-core MCP until dual-run; optional FastMCP adapter in a later WP |
|
|||
|
|
| Schedulers | **None in-process** — activity-core calls reconcile HTTP/CLI |
|
|||
|
|
|
|||
|
|
### 3. Persistence
|
|||
|
|
|
|||
|
|
| Choice | Decision |
|
|||
|
|
| --- | --- |
|
|||
|
|
| Database | **PostgreSQL 16** (CNPG/fleet); dedicated DB/schema **`repo_manager`** |
|
|||
|
|
| ORM | **SQLAlchemy 2.x asyncio** + **asyncpg** |
|
|||
|
|
| Migrations | **Alembic** under `src/repo_manager/migrations/` or repo-root `migrations/` |
|
|||
|
|
| Metadata | **Own `Base`** — never mix with hub-core or state-hub metadata (isolation) |
|
|||
|
|
| SQLite | **Dev/test only** optional via aiosqlite; production is Postgres |
|
|||
|
|
|
|||
|
|
**Rationale:** Separate DB from State Hub so cutover does not share write
|
|||
|
|
contention or schema ownership. Files remain authority for work records;
|
|||
|
|
Postgres holds registry, index, findings, command/idempotency logs.
|
|||
|
|
|
|||
|
|
### 4. Git and files
|
|||
|
|
|
|||
|
|
| Choice | Decision |
|
|||
|
|
| --- | --- |
|
|||
|
|
| Git operations | **subprocess git** (parity with `consistency_check` extract) |
|
|||
|
|
| Parsing | Port/adapt SH parsers → `repo_manager.parse` |
|
|||
|
|
| Writeback | Same commit evidence rules as contracts (git_sha required) |
|
|||
|
|
|
|||
|
|
Avoid new Git bindings (GitPython) until a concrete need; subprocess matches
|
|||
|
|
extract source and SSH/forge setups already in production images.
|
|||
|
|
|
|||
|
|
### 5. Events and integration
|
|||
|
|
|
|||
|
|
| Choice | Decision |
|
|||
|
|
| --- | --- |
|
|||
|
|
| hub-core dependency | **Optional path/editable** for utils only (slug/pagination) if useful; **no** shared tables |
|
|||
|
|
| NATS | **Optional later** — emit HTTP hooks or in-process event bus first; nats-py when hub-core event bus is standard |
|
|||
|
|
| Authz | Call hub-core **policy port** when available; **dev allowlist** scopes for local |
|
|||
|
|
|
|||
|
|
### 6. Testing
|
|||
|
|
|
|||
|
|
| Choice | Decision |
|
|||
|
|
| --- | --- |
|
|||
|
|
| Runner | **pytest** + **pytest-asyncio** (`asyncio_mode = auto`) |
|
|||
|
|
| Unit | parsers, transition matrix, DTOs |
|
|||
|
|
| Integration | Postgres test DB or ephemeral container; git fixtures in `tests/fixtures/repos/` |
|
|||
|
|
| Compat | Suites T-PARSE…T-DUAL-RUN from extraction inventory |
|
|||
|
|
|
|||
|
|
### 7. Deployment
|
|||
|
|
|
|||
|
|
| Choice | Decision |
|
|||
|
|
| --- | --- |
|
|||
|
|
| Container | **Dockerfile** (python:3.12-slim + git + openssh-client + uv) modeled on state-hub |
|
|||
|
|
| Local | `make db migrate api` / `make test` |
|
|||
|
|
| Cluster | Later Helm under railiance (not blocking T05); single replica first |
|
|||
|
|
| Secrets | DATABASE_URL / policy tokens via env or platform custody — never in repo |
|
|||
|
|
|
|||
|
|
### 8. Initial package modules (target)
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
src/repo_manager/
|
|||
|
|
__init__.py
|
|||
|
|
config.py
|
|||
|
|
db.py # engine, session, Base
|
|||
|
|
models/ # private ORM
|
|||
|
|
schemas/ # public Pydantic DTOs
|
|||
|
|
api/ # FastAPI routers
|
|||
|
|
parse/ # workplan/work-record parsers
|
|||
|
|
consistency/ # C-rules engine (extract)
|
|||
|
|
commands/ # command handlers
|
|||
|
|
gitops/ # subprocess git helpers
|
|||
|
|
cli.py
|
|||
|
|
migrations/
|
|||
|
|
tests/
|
|||
|
|
pyproject.toml
|
|||
|
|
Makefile
|
|||
|
|
Dockerfile # with first deployable slice
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 9. Explicit non-choices
|
|||
|
|
|
|||
|
|
| Rejected | Why |
|
|||
|
|
| --- | --- |
|
|||
|
|
| Haskell / IHP | Retired path; fleet is Python for this class of service |
|
|||
|
|
| Sharing State Hub database long-term | Confuses authority and cutover |
|
|||
|
|
| Embedding Temporal | activity-core owns schedules |
|
|||
|
|
| Day-1 full MCP surface | Dual-run via existing SH tools first |
|
|||
|
|
| Calling Repo Manager a hub | Taxonomy: functional component |
|
|||
|
|
|
|||
|
|
## Consequences
|
|||
|
|
|
|||
|
|
**Positive**
|
|||
|
|
|
|||
|
|
- Operators and extract PRs stay on known stack.
|
|||
|
|
- Clear dual-run: SH and RM side by side with same Git authority.
|
|||
|
|
- CLI `rmgr reconcile` can replace `statehub fix-consistency` gradually.
|
|||
|
|
|
|||
|
|
**Negative / cost**
|
|||
|
|
|
|||
|
|
- Another Postgres database and migration chain to operate.
|
|||
|
|
- Temporary dual registration until SH registry is strangler-cut.
|
|||
|
|
|
|||
|
|
**Follow-ons**
|
|||
|
|
|
|||
|
|
- T05: E2E on `repo-manager` itself (or a fixture repo) using P0/P1 slices.
|
|||
|
|
- STATE-WP-0079: point fix-consistency / MCP writebacks at RM adapters.
|
|||
|
|
- Optional: publish OpenAPI for `helixforge.repo-manager` 0.1 from FastAPI.
|
|||
|
|
|
|||
|
|
## Compliance with prior docs
|
|||
|
|
|
|||
|
|
| Doc | How this ADR satisfies it |
|
|||
|
|
| --- | --- |
|
|||
|
|
| REP-0001 | ORM private; snapshots are DTOs |
|
|||
|
|
| CMD-0001 | FastAPI + CLI implement observation/commands |
|
|||
|
|
| EXTRACT-0001 | Phases P0–P2 map to modules above |
|
|||
|
|
|
|||
|
|
## Acceptance (T04)
|
|||
|
|
|
|||
|
|
- [x] Runtime chosen (FastAPI/uvicorn, Python 3.12)
|
|||
|
|
- [x] Persistence chosen (Postgres + SQLAlchemy async + Alembic, own DB)
|
|||
|
|
- [x] Package/layout chosen (src/repo_manager, uv, hatchling)
|
|||
|
|
- [x] Test approach chosen (pytest-asyncio + fixtures)
|
|||
|
|
- [x] Deploy approach chosen (Docker, make; Helm later)
|
|||
|
|
- [x] Non-goals recorded
|