2026-07-02 11:13:03 +02:00
|
|
|
.PHONY: help install dev test test-minio test-minio-local lint format type migrate migrate-fresh clean
|
WP-0001-T001: service scaffold (Python, FastAPI, uv, ruff, mypy, pytest)
Lands the smallest credible foundation per ADR-0005:
- pyproject.toml: hatchling build, runtime deps (FastAPI, uvicorn, SQLAlchemy 2.0,
asyncpg, aiosqlite, alembic, blake3, cbor2, typer, structlog, pydantic,
pydantic-settings); dev deps (pytest, pytest-asyncio, httpx, hypothesis, ruff,
mypy); ruff + mypy --strict + pytest configured.
- uv.lock committed.
- Makefile thin shims: install / dev / test / lint / format / type / migrate / clean.
- src/artifactstore/ package skeleton with placeholder __init__.py per concern:
identity, manifest, events, retention, audit, storage, dataplane, registry,
api/http (minimal FastAPI app, GET / scaffold banner), cli (typer app with
version subcommand), config (pydantic-settings).
- tests/{unit,integration}/conftest.py present; unit smoke tests assert package
imports, HTTP root route, CLI version round-trip, settings defaults.
- .env.example documents ARTIFACTSTORE_DATABASE_URL,
ARTIFACTSTORE_STORAGE_LOCAL_ROOT, ARTIFACTSTORE_LOG_LEVEL.
- README updated with install / dev / test instructions.
- .gitignore: claude local state, local runtime data (var/, sqlite db).
make lint && make type && make test pass on a clean checkout (4 tests, 20
source files type-clean under mypy --strict).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 01:30:22 +02:00
|
|
|
|
|
|
|
|
help:
|
|
|
|
|
@echo "artifact-store — make targets"
|
WP-0001-T002: registry data model, Alembic, initial migration with retention seed
Schema (src/artifactstore/db/schema.py):
- events table (ADR-0002 source of truth): sequence BIGSERIAL PK, created_at,
event_type, subject_kind, subject_id, actor, payload (CBOR bytes),
payload_digest. Indexes on (subject_kind, subject_id) and
(event_type, sequence).
- artifact_packages, artifact_files, storage_locations, retention_state
(materialised views over events).
- retention_classes (seed table) and metadata_schemas (config table).
- ADR-0001 columns present: digest_algorithm, digest_primary, digest_sha256,
content_address. Blueprint tiering columns present: retrieval_tier
(default 'hot'), restore_status.
- Types portable: SQLAlchemy 2.0 Core with JSON().with_variant(JSONB, 'postgresql'),
Uuid, LargeBinary, DateTime(timezone=True), Boolean false() default.
Seed (src/artifactstore/db/seed.py): five v1 retention classes (transient,
raw-evidence, summary-evidence, release-evidence, permanent-record) with
default durations in seconds; permanent-record has no expiry.
Alembic:
- alembic.ini with sync sqlite URL default; path_separator=os to silence the
1.13 deprecation warning.
- migrations/env.py: translates async URLs (+aiosqlite, +asyncpg) to sync
counterparts at migrate-time so a single ARTIFACTSTORE_DATABASE_URL works
for both runtime (async) and Alembic (sync).
- migrations/script.py.mako template.
- migrations/versions/20260516_0001_initial.py: metadata.create_all + bulk
insert of retention class seeds.
Make:
- make migrate: alembic upgrade head (ensures var/ exists).
- make migrate-fresh: drop local SQLite + re-run.
Deps: psycopg[binary] added as optional `postgres` extra (PostgreSQL prod
path; SQLite default for dev needs no extra).
Tests:
- tests/unit/test_db_schema.py: every expected table present; ADR-0001 and
tiering columns present; seed has the five v1 classes; permanent-record
has no default_duration; create_all + FK insert + Boolean default
round-trip on in-memory SQLite.
- tests/integration/test_migrations.py: alembic upgrade head against a
tempfile SQLite produces all tables (+ alembic_version) and the seed rows.
Gates: ruff clean, mypy --strict clean on 32 files, 38 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 01:50:38 +02:00
|
|
|
@echo " install install / sync dependencies via uv"
|
|
|
|
|
@echo " dev run the FastAPI app with reload (uvicorn)"
|
|
|
|
|
@echo " test run the pytest suite"
|
2026-06-27 23:37:55 +02:00
|
|
|
@echo " test-minio run opt-in live MinIO compatibility tests"
|
2026-07-02 11:13:03 +02:00
|
|
|
@echo " test-minio-local run the same tests against a throwaway local MinIO container"
|
WP-0001-T002: registry data model, Alembic, initial migration with retention seed
Schema (src/artifactstore/db/schema.py):
- events table (ADR-0002 source of truth): sequence BIGSERIAL PK, created_at,
event_type, subject_kind, subject_id, actor, payload (CBOR bytes),
payload_digest. Indexes on (subject_kind, subject_id) and
(event_type, sequence).
- artifact_packages, artifact_files, storage_locations, retention_state
(materialised views over events).
- retention_classes (seed table) and metadata_schemas (config table).
- ADR-0001 columns present: digest_algorithm, digest_primary, digest_sha256,
content_address. Blueprint tiering columns present: retrieval_tier
(default 'hot'), restore_status.
- Types portable: SQLAlchemy 2.0 Core with JSON().with_variant(JSONB, 'postgresql'),
Uuid, LargeBinary, DateTime(timezone=True), Boolean false() default.
Seed (src/artifactstore/db/seed.py): five v1 retention classes (transient,
raw-evidence, summary-evidence, release-evidence, permanent-record) with
default durations in seconds; permanent-record has no expiry.
Alembic:
- alembic.ini with sync sqlite URL default; path_separator=os to silence the
1.13 deprecation warning.
- migrations/env.py: translates async URLs (+aiosqlite, +asyncpg) to sync
counterparts at migrate-time so a single ARTIFACTSTORE_DATABASE_URL works
for both runtime (async) and Alembic (sync).
- migrations/script.py.mako template.
- migrations/versions/20260516_0001_initial.py: metadata.create_all + bulk
insert of retention class seeds.
Make:
- make migrate: alembic upgrade head (ensures var/ exists).
- make migrate-fresh: drop local SQLite + re-run.
Deps: psycopg[binary] added as optional `postgres` extra (PostgreSQL prod
path; SQLite default for dev needs no extra).
Tests:
- tests/unit/test_db_schema.py: every expected table present; ADR-0001 and
tiering columns present; seed has the five v1 classes; permanent-record
has no default_duration; create_all + FK insert + Boolean default
round-trip on in-memory SQLite.
- tests/integration/test_migrations.py: alembic upgrade head against a
tempfile SQLite produces all tables (+ alembic_version) and the seed rows.
Gates: ruff clean, mypy --strict clean on 32 files, 38 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 01:50:38 +02:00
|
|
|
@echo " lint ruff check + ruff format --check"
|
|
|
|
|
@echo " format ruff format (write changes)"
|
|
|
|
|
@echo " type mypy --strict over src and tests"
|
|
|
|
|
@echo " migrate alembic upgrade head"
|
|
|
|
|
@echo " migrate-fresh drop the local SQLite DB and re-run migrations"
|
|
|
|
|
@echo " clean remove caches and build artefacts"
|
WP-0001-T001: service scaffold (Python, FastAPI, uv, ruff, mypy, pytest)
Lands the smallest credible foundation per ADR-0005:
- pyproject.toml: hatchling build, runtime deps (FastAPI, uvicorn, SQLAlchemy 2.0,
asyncpg, aiosqlite, alembic, blake3, cbor2, typer, structlog, pydantic,
pydantic-settings); dev deps (pytest, pytest-asyncio, httpx, hypothesis, ruff,
mypy); ruff + mypy --strict + pytest configured.
- uv.lock committed.
- Makefile thin shims: install / dev / test / lint / format / type / migrate / clean.
- src/artifactstore/ package skeleton with placeholder __init__.py per concern:
identity, manifest, events, retention, audit, storage, dataplane, registry,
api/http (minimal FastAPI app, GET / scaffold banner), cli (typer app with
version subcommand), config (pydantic-settings).
- tests/{unit,integration}/conftest.py present; unit smoke tests assert package
imports, HTTP root route, CLI version round-trip, settings defaults.
- .env.example documents ARTIFACTSTORE_DATABASE_URL,
ARTIFACTSTORE_STORAGE_LOCAL_ROOT, ARTIFACTSTORE_LOG_LEVEL.
- README updated with install / dev / test instructions.
- .gitignore: claude local state, local runtime data (var/, sqlite db).
make lint && make type && make test pass on a clean checkout (4 tests, 20
source files type-clean under mypy --strict).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 01:30:22 +02:00
|
|
|
|
|
|
|
|
install:
|
|
|
|
|
uv sync --all-extras
|
|
|
|
|
|
|
|
|
|
dev:
|
|
|
|
|
uv run uvicorn artifactstore.api.http:app --reload --host 127.0.0.1 --port 8000
|
|
|
|
|
|
|
|
|
|
test:
|
|
|
|
|
uv run pytest
|
|
|
|
|
|
2026-06-27 23:37:55 +02:00
|
|
|
test-minio:
|
|
|
|
|
uv run --all-extras pytest tests/integration/test_storage_s3_minio.py -m integration
|
|
|
|
|
|
2026-07-02 11:13:03 +02:00
|
|
|
test-minio-local:
|
|
|
|
|
bash scripts/minio_local_smoke.sh
|
|
|
|
|
|
WP-0001-T001: service scaffold (Python, FastAPI, uv, ruff, mypy, pytest)
Lands the smallest credible foundation per ADR-0005:
- pyproject.toml: hatchling build, runtime deps (FastAPI, uvicorn, SQLAlchemy 2.0,
asyncpg, aiosqlite, alembic, blake3, cbor2, typer, structlog, pydantic,
pydantic-settings); dev deps (pytest, pytest-asyncio, httpx, hypothesis, ruff,
mypy); ruff + mypy --strict + pytest configured.
- uv.lock committed.
- Makefile thin shims: install / dev / test / lint / format / type / migrate / clean.
- src/artifactstore/ package skeleton with placeholder __init__.py per concern:
identity, manifest, events, retention, audit, storage, dataplane, registry,
api/http (minimal FastAPI app, GET / scaffold banner), cli (typer app with
version subcommand), config (pydantic-settings).
- tests/{unit,integration}/conftest.py present; unit smoke tests assert package
imports, HTTP root route, CLI version round-trip, settings defaults.
- .env.example documents ARTIFACTSTORE_DATABASE_URL,
ARTIFACTSTORE_STORAGE_LOCAL_ROOT, ARTIFACTSTORE_LOG_LEVEL.
- README updated with install / dev / test instructions.
- .gitignore: claude local state, local runtime data (var/, sqlite db).
make lint && make type && make test pass on a clean checkout (4 tests, 20
source files type-clean under mypy --strict).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 01:30:22 +02:00
|
|
|
lint:
|
|
|
|
|
uv run ruff check .
|
|
|
|
|
uv run ruff format --check .
|
|
|
|
|
|
|
|
|
|
format:
|
|
|
|
|
uv run ruff format .
|
|
|
|
|
uv run ruff check --fix .
|
|
|
|
|
|
|
|
|
|
type:
|
|
|
|
|
uv run mypy
|
|
|
|
|
|
|
|
|
|
migrate:
|
WP-0001-T002: registry data model, Alembic, initial migration with retention seed
Schema (src/artifactstore/db/schema.py):
- events table (ADR-0002 source of truth): sequence BIGSERIAL PK, created_at,
event_type, subject_kind, subject_id, actor, payload (CBOR bytes),
payload_digest. Indexes on (subject_kind, subject_id) and
(event_type, sequence).
- artifact_packages, artifact_files, storage_locations, retention_state
(materialised views over events).
- retention_classes (seed table) and metadata_schemas (config table).
- ADR-0001 columns present: digest_algorithm, digest_primary, digest_sha256,
content_address. Blueprint tiering columns present: retrieval_tier
(default 'hot'), restore_status.
- Types portable: SQLAlchemy 2.0 Core with JSON().with_variant(JSONB, 'postgresql'),
Uuid, LargeBinary, DateTime(timezone=True), Boolean false() default.
Seed (src/artifactstore/db/seed.py): five v1 retention classes (transient,
raw-evidence, summary-evidence, release-evidence, permanent-record) with
default durations in seconds; permanent-record has no expiry.
Alembic:
- alembic.ini with sync sqlite URL default; path_separator=os to silence the
1.13 deprecation warning.
- migrations/env.py: translates async URLs (+aiosqlite, +asyncpg) to sync
counterparts at migrate-time so a single ARTIFACTSTORE_DATABASE_URL works
for both runtime (async) and Alembic (sync).
- migrations/script.py.mako template.
- migrations/versions/20260516_0001_initial.py: metadata.create_all + bulk
insert of retention class seeds.
Make:
- make migrate: alembic upgrade head (ensures var/ exists).
- make migrate-fresh: drop local SQLite + re-run.
Deps: psycopg[binary] added as optional `postgres` extra (PostgreSQL prod
path; SQLite default for dev needs no extra).
Tests:
- tests/unit/test_db_schema.py: every expected table present; ADR-0001 and
tiering columns present; seed has the five v1 classes; permanent-record
has no default_duration; create_all + FK insert + Boolean default
round-trip on in-memory SQLite.
- tests/integration/test_migrations.py: alembic upgrade head against a
tempfile SQLite produces all tables (+ alembic_version) and the seed rows.
Gates: ruff clean, mypy --strict clean on 32 files, 38 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 01:50:38 +02:00
|
|
|
@mkdir -p var
|
|
|
|
|
uv run alembic upgrade head
|
|
|
|
|
|
|
|
|
|
migrate-fresh:
|
|
|
|
|
@rm -f var/artifactstore.db var/artifactstore.db-journal
|
|
|
|
|
@mkdir -p var
|
|
|
|
|
uv run alembic upgrade head
|
WP-0001-T001: service scaffold (Python, FastAPI, uv, ruff, mypy, pytest)
Lands the smallest credible foundation per ADR-0005:
- pyproject.toml: hatchling build, runtime deps (FastAPI, uvicorn, SQLAlchemy 2.0,
asyncpg, aiosqlite, alembic, blake3, cbor2, typer, structlog, pydantic,
pydantic-settings); dev deps (pytest, pytest-asyncio, httpx, hypothesis, ruff,
mypy); ruff + mypy --strict + pytest configured.
- uv.lock committed.
- Makefile thin shims: install / dev / test / lint / format / type / migrate / clean.
- src/artifactstore/ package skeleton with placeholder __init__.py per concern:
identity, manifest, events, retention, audit, storage, dataplane, registry,
api/http (minimal FastAPI app, GET / scaffold banner), cli (typer app with
version subcommand), config (pydantic-settings).
- tests/{unit,integration}/conftest.py present; unit smoke tests assert package
imports, HTTP root route, CLI version round-trip, settings defaults.
- .env.example documents ARTIFACTSTORE_DATABASE_URL,
ARTIFACTSTORE_STORAGE_LOCAL_ROOT, ARTIFACTSTORE_LOG_LEVEL.
- README updated with install / dev / test instructions.
- .gitignore: claude local state, local runtime data (var/, sqlite db).
make lint && make type && make test pass on a clean checkout (4 tests, 20
source files type-clean under mypy --strict).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 01:30:22 +02:00
|
|
|
|
|
|
|
|
clean:
|
|
|
|
|
rm -rf .pytest_cache .mypy_cache .ruff_cache build dist *.egg-info
|
|
|
|
|
find . -type d -name __pycache__ -prune -exec rm -rf {} +
|