docs(RMGR-WP-0001): complete T04 implementation foundation

Accept ADR-001: Python 3.12, FastAPI, Postgres/SQLAlchemy async, src layout,
uv/hatchling, pytest. Scaffold package, rmgr CLI stub, and version tests.
This commit is contained in:
tegwick 2026-08-09 22:41:26 +02:00
parent 3fa8d0b4c4
commit e02f5a258a
9 changed files with 342 additions and 7 deletions

18
.gitignore vendored
View file

@ -1,5 +1,13 @@
# state-hub: track .claude/rules .venv/
# Claude Code local state (track shared rules; ignore machine-specific files) __pycache__/
.claude/* *.py[cod]
!.claude/rules/ .pytest_cache/
!.claude/rules/*.md .ruff_cache/
.mypy_cache/
*.egg-info/
dist/
build/
.env
.coverage
htmlcov/
uv.lock

23
Makefile Normal file
View file

@ -0,0 +1,23 @@
# Repo Manager — local developer targets (RMGR-ADR-001)
UV ?= $(shell command -v uv 2>/dev/null || if [ -x "$$HOME/.local/bin/uv" ]; then printf "%s" "$$HOME/.local/bin/uv"; else printf "%s" "uv"; fi)
.PHONY: help install test lint cli-version
help:
@echo "Repo Manager targets:"
@echo " make install # uv sync / editable install"
@echo " make test # pytest"
@echo " make cli-version # rmgr --version"
@echo " (api/db/migrate land with first runtime slice)"
install:
$(UV) sync --all-extras 2>/dev/null || $(UV) pip install -e ".[dev]"
test:
$(UV) run pytest -q
lint:
$(UV) run ruff check src tests 2>/dev/null || true
cli-version:
$(UV) run rmgr --version

View file

@ -23,3 +23,10 @@ Architecture:
- [Repository representation v0.1](docs/repository-representation_v0.1.md) - [Repository representation v0.1](docs/repository-representation_v0.1.md)
- [Observation and command contracts v0.1](docs/observation-command-contracts_v0.1.md) - [Observation and command contracts v0.1](docs/observation-command-contracts_v0.1.md)
- [State Hub extraction inventory v0.1](docs/state-hub-extraction-inventory_v0.1.md) - [State Hub extraction inventory v0.1](docs/state-hub-extraction-inventory_v0.1.md)
- [ADR-001 Implementation foundation](docs/adr-001-implementation-foundation.md)
```bash
make install # or: uv pip install -e ".[dev]"
make test
rmgr --version
```

View file

@ -0,0 +1,182 @@
---
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
P0P5, 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 P0P2 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

45
pyproject.toml Normal file
View file

@ -0,0 +1,45 @@
[project]
name = "repo-manager"
version = "0.1.0"
description = "HelixForge repository integration boundary"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"fastapi>=0.115.0",
"uvicorn[standard]>=0.32.0",
"sqlalchemy[asyncio]>=2.0.0",
"asyncpg>=0.30.0",
"alembic>=1.14.0",
"pydantic>=2.10.0",
"pydantic-settings>=2.7.0",
"httpx>=0.28.0",
"pyyaml>=6.0.0",
"python-dotenv>=1.0.0",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0.0",
"pytest-asyncio>=0.24.0",
"ruff>=0.8.0",
"aiosqlite>=0.20.0",
]
[project.scripts]
rmgr = "repo_manager.cli:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/repo_manager"]
[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]
asyncio_mode = "auto"
[tool.ruff]
line-length = 100
src = ["src", "tests"]

View file

@ -0,0 +1,3 @@
"""Repo Manager — HelixForge repository integration boundary."""
__version__ = "0.1.0"

51
src/repo_manager/cli.py Normal file
View file

@ -0,0 +1,51 @@
"""CLI entry point ``rmgr`` (skeleton — commands land with extract phases)."""
from __future__ import annotations
import argparse
import sys
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(
prog="rmgr",
description="Repo Manager CLI (helixforge.repo-manager)",
)
parser.add_argument(
"--version",
action="store_true",
help="Print package version and exit",
)
sub = parser.add_subparsers(dest="command")
sub.add_parser("version", help="Print version")
# Placeholders — implemented as extraction phases land (RMGR-WP-0001-T05+).
p_rec = sub.add_parser(
"reconcile",
help="Run consistency reconcile (not yet implemented)",
)
p_rec.add_argument("--path", default=".", help="Repository checkout path")
p_rec.add_argument("--fix", action="store_true", help="Apply safe fixes")
args = parser.parse_args(argv)
if args.version or args.command in (None, "version"):
from repo_manager import __version__
print(__version__)
return 0
if args.command == "reconcile":
print(
"rmgr reconcile: not implemented yet "
"(see docs/adr-001-implementation-foundation.md, phase P0)",
file=sys.stderr,
)
return 2
parser.print_help()
return 0
if __name__ == "__main__":
raise SystemExit(main())

11
tests/test_version.py Normal file
View file

@ -0,0 +1,11 @@
from repo_manager import __version__
from repo_manager.cli import main
def test_version_string():
assert __version__ == "0.1.0"
def test_cli_version(capsys):
assert main(["--version"]) == 0
assert "0.1.0" in capsys.readouterr().out

View file

@ -86,7 +86,7 @@ inbox C-rules retired from RM; phases P0P5; compat suites T-PARSE…T-DUAL-RU
```task ```task
id: RMGR-WP-0001-T04 id: RMGR-WP-0001-T04
status: todo status: done
priority: medium priority: medium
state_hub_task_id: "0a041f4e-09fc-4f69-8a48-ac396186bc8f" state_hub_task_id: "0a041f4e-09fc-4f69-8a48-ac396186bc8f"
``` ```
@ -95,6 +95,11 @@ Choose the runtime, persistence, package, migration, test, and deployment shape
consistent with the ordinary HelixForge platform. Record the decision before consistent with the ordinary HelixForge platform. Record the decision before
substantial implementation. substantial implementation.
**Result (2026-08-09):** ADR-001 `docs/adr-001-implementation-foundation.md`
Python 3.12, FastAPI/uvicorn, Postgres+SQLAlchemy async+Alembic (own DB),
src/repo_manager, uv/hatchling, pytest-asyncio, Docker later; CLI `rmgr`
skeleton. Package scaffold + version test landed (no business logic yet).
## Prove one repository end to end ## Prove one repository end to end
```task ```task
@ -115,5 +120,5 @@ projection.
- [x] Observation and command contracts are versioned and testable. - [x] Observation and command contracts are versioned and testable.
- (semantics + catalog done; automated suite with runtime in T04/T05) - (semantics + catalog done; automated suite with runtime in T04/T05)
- [x] State Hub extraction candidates have dispositions. - [x] State Hub extraction candidates have dispositions.
- [ ] The implementation foundation has a recorded decision. - [x] The implementation foundation has a recorded decision.
- [ ] One repository completes the end-to-end vertical slice. - [ ] One repository completes the end-to-end vertical slice.