Plan: Implement repository contracts and Alembic migrations (2.6.2) - #281
Plan: Implement repository contracts and Alembic migrations (2.6.2)#281leynos wants to merge 5 commits into
Conversation
…rations This plan defines the scope, stages, and validation criteria for implementing repository contracts and Alembic migrations for generation-run aggregates. The plan covers: - Verification of domain model from 2.6.1 - Definition of GenerationRunRepository and GenerationEventRepository protocols - Alembic migration for generation_runs and generation_events tables - SQLAlchemy ORM models and repository implementations - Integration tests validating event ordering and persistence semantics - Validation that all gates pass (check-fmt, typecheck, lint, test) The plan is structured as 8 stages with explicit go/no-go validation points. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Replace the initial generation-run persistence execplan, which was drafted without inspecting the codebase, with a version grounded in the actual 2.6.1 contracts, prior art, and a community-of-experts design review. Corrections over the previous draft: - Target the real ports in `episodic/canonical/generation_run_ports.py` (`create_run`, `get_run`, `list_runs`, `update_run_status`, `append_event`, `list_events`, and the checkpoint methods) rather than inventing `GenerationRunRepository.add`/`by_id` in a non-existent `episodic/generation/ports.py`. The ports already exist; this slice implements a PostgreSQL adapter for them. - Chain the migration off the true head `20260601_000009`, not the stale `20260508_000008`, and note the single linear head despite two `000009` files. - Mirror established storage patterns: `Base` declarative models, the history-table `UNIQUE(parent_id, seq)` + `CHECK (seq >= 1)` sequence pattern, `_RepositoryBase`, per-feature mappers, and `SqlAlchemyUnitOfWork` wiring. Design decisions added after the Logisphere panel (proceed-with-conditions): - Allocate per-run event `seq` as `MAX(seq)+1` under a unique constraint with a bounded retry inside a savepoint and a conflict metric, instead of escalating on first conflict; reject a global sequence (gaps) and a counter column (pattern divergence). - Widen `seq` to `BIGINT`; add `(episode_id, created_at)` and `(episode_id, status, created_at)` indexes; specify deterministic `list_runs` ordering and FK `ON DELETE` semantics; add an `updated_at` trigger. - Qualify behavioural equivalence to the single-writer case and document the py-pglite single-connection limitation; force the idempotency conflict branch in tests. Status remains DRAFT pending approval before implementation.
The previous draft was authored before commit `5af0638` (roadmap 4.3.2) landed durable generation-run and event persistence, the `20260624_000010` migration, and Hypothesis event-ordering property tests. It therefore asserted that no durable persistence existed and targeted migration head `20260601_000009`, three revisions stale. Rewrite the plan against the current tree and re-scope it to the genuine remaining gap: reviewer-checkpoint persistence, a composite `GenerationRunPort` implementation, cross-adapter contract equivalence, and the lease-reclamation repository primitive that 4.3.2 deferred here by name. Add the `Conformance basis` and `Verification plan` sections the ExecPlan format requires, including per-obligation non-vacuity checks and negative controls.
A six-lens design review found the plan promised evidence its test harness cannot produce, and justified its central decision with a requirement the API document does not state. Two independent probes showed py-pglite serializes *all* transactions globally, including unrelated sessions: it is a single WebAssembly backend. The previous AXIOM-3 claimed it reproduces PostgreSQL locking semantics. It does not, so INV-SEQ-1's concurrency obligation was unfalsifiable and its negative control provably could not fire. Scope the obligation to what is observable and move the concurrency claim to `Residual gaps`. Rebuild D-3 on prefix stability rather than gaplessness, which is what `after_seq` replay actually requires, and record all five sequencing alternatives with verdicts. Other substantive changes: - D-2 reverses the mixin decision in favour of composition, and answers whether a checkpoint table is needed at all. - D-7 renames the table to `review_checkpoints`; ADR-007 is titled "Durable generation checkpoints", so the old name walked into the confusion Risk 1 predicts. - Correct the Purpose overclaim: nothing creates a checkpoint in production today, so this is an enabling slice with zero consumers. Leave the users' guide unchanged accordingly. - Add risks and obligations for the silent no-commit window, the reaper failing runs awaiting review, editing an applied migration revision, and the shared creation-precondition blind spot. - Fold new tests into the existing SQL suite and feature file rather than duplicating them; drop the snapshot and the xfail dance; raise `max_examples` from 5-6 to 25 on measured cost. - Re-base tolerances on measurement: 130.58s for 1227 tests, 0.20-0.38s per database test.
|
Warning Your free Security trial is over. An organization admin can activate billing to continue. |
Reviewer's GuideAdds a detailed execution plan document for roadmap item 2.6.2 describing how to implement generation-run repository contracts and Alembic migrations, including constraints, risks, verification strategy, schema design for a new review_checkpoints table, adapter architecture, and milestone breakdown, but no executable code changes. Sequence diagram for durable review checkpoint responsesequenceDiagram
participant Caller
participant UOW as SqlAlchemyUnitOfWork
participant Store as SqlAlchemyReviewCheckpointStore
participant DB as PostgreSQL
Caller->>UOW: create_checkpoint(...)
UOW->>Store: create_checkpoint(...)
Store->>DB: flush()
Caller->>Store: respond_to_checkpoint(...)
Store->>DB: with_for_update()
Store->>DB: flush()
Caller->>UOW: commit()
UOW->>DB: COMMIT
Caller->>UOW: read checkpoint in fresh unit of work
UOW->>DB: SELECT review_checkpoints
DB-->>Caller: responded checkpoint
ER diagram for review checkpoint persistenceerDiagram
GENERATION_RUNS ||--o{ REVIEW_CHECKPOINTS : owns
GENERATION_RUNS {
uuid id PK
enum status
}
REVIEW_CHECKPOINTS {
uuid id PK
uuid generation_run_id FK
text prompt
jsonb options
enum status
enum response_action
timestamptz resolved_at
}
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
PR 278 takes ADR-018 and ADR-019, so this plan's ADR becomes 020. More substantially, its ADR-018 is now the governing record for versioning, concurrency shapes, immutability, and deletion policy, and it warns that "applying the wrong [concurrency shape] produces either lost updates or spurious conflicts". Three decisions change to conform: - D-10 replaces `SELECT ... FOR UPDATE` on the checkpoint row with compare-and-set, the shape ADR-018 names for concurrent writers racing on one mutable row, mirroring `SqlAlchemyEpisodeRepository.update`. This also converts an obligation py-pglite cannot verify into one it can: a `WHERE status = 'created'` predicate is exercisable sequentially, whereas lock contention is not observable at all. - The `review_checkpoints` foreign key becomes `ON DELETE RESTRICT` under ADR-018's audit-trail deletion policy. - D-11 records why a review checkpoint is not a versioned aggregate and so needs no history table. PR 277 edits the four files this plan changes most, so it is now a stated dependency. It also establishes that persisted rows survive between Hypothesis examples, which matters at `max_examples=25`; that `uow.py` imports must stay outside `TYPE_CHECKING` because `mock.create_autospec` evaluates annotations at runtime; and that `integrity_helpers` already provides the constraint classification this plan would otherwise hand-roll. Add a `Pending pull requests` section, a risk for implementing ahead of both, and the revised test baseline.
Reconciled with PRs #278 and #277Both were reviewed and the plan now depends on them. A new Pending pull requests this plan depends on section states the dependency and the rebase order. PR #278 — versioning ADR (docs only)
PR #277 — 4.3.2 alpha hardening (code + docs)
New Risk 8 covers implementing ahead of either PR.
|
Summary
Execution plan for roadmap item 2.6.2 — Implement repository contracts and Alembic migrations.
Plan document:
docs/execplans/2-6-2-repository-contracts-and-alembic-migrations.mdThis PR contains no code changes — only the plan.
Why this supersedes #142
PR #142 carries an earlier draft of the same plan, authored against a tree that predated commit
5af0638(roadmap 4.3.2). That draft asserted "there is no durable persistence for generation runs" — no longer true — and targeted migration head20260601_000009, three revisions stale. This branch rebases ontoorigin/mainand rewrites the plan against the current tree. #142 should be closed.Scope
4.3.2 already landed durable persistence for runs and events, the
20260624_000010migration, and sequencing property tests. The genuine remaining gap is:GenerationRunPort;The plan is explicit that this is an enabling slice with zero production consumers until 2.6.3:
InMemoryGenerationRunStoreis instantiated nowhere inepisodic/, and no production path callscreate_checkpointtoday.Design review
The plan was reviewed by a six-lens expert panel (structure, alternatives, scaling, contracts, failure modes, viability) after a Wyvern reconnaissance pass. Two reviewers independently probed the test database and converged on a finding that invalidated a core axiom of the first draft:
Consequences, now reflected in the plan:
AXIOM-3(py-pglite reproduces PostgreSQL locking semantics) was false.INV-SEQ-1's concurrency obligation was unfalsifiable in the harness that would run it, and its negative control provably could not fire.asyncio.gathertest intests/canonical_storage/measures sequential replay, not concurrency. They remain valid evidence for compare-and-set predicates; the plan no longer cites them as lock evidence.Residual gaps, with a real-PostgreSQL opt-in tier named as the only way to discharge it.Other substantive revisions:
BIGSERIALas incorrect rather than inelegant, and a per-run counter column as the identified strict improvement, deferred.review_checkpoints. ADR-007 is titled "Durable generation checkpoints", so the original name walked into the exact confusion Risk 1 predicts.xfaildance dropped;max_examplesraised 5-6 → 25 on measured cost.Validation
make fmt,make markdownlint, andmake nixieall pass. No code gates apply; this is a documentation-only change.References
docs/roadmap.mdSummary by Sourcery
Define the implementation plan for completing generation-run repository contracts and durable reviewer-checkpoint persistence without introducing production consumers.
Enhancements:
Documentation:
Tests: