Accept ADR-001: Python 3.12, FastAPI, Postgres/SQLAlchemy async, src layout, uv/hatchling, pytest. Scaffold package, rmgr CLI stub, and version tests.
182 lines
6.5 KiB
Markdown
182 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
|