refactor(backend): collapse duplicate PR row types into one domain definition#60
Conversation
Greptile SummaryThis PR collapses three layers of near-identical PR-row structs (
Confidence Score: 5/5Safe to merge — purely structural, no logic added or removed. Every behavioural path is preserved exactly. The state-column encoding round-trips correctly through the new helper functions, the PRFactsForSession predicate change is semantically equivalent, default enum handling is faithfully replicated, and compile-time interface guards are present. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
subgraph Before
LCM_OLD["lifecycle.Manager"] -->|"ports.PRRow/PRCheckRow/PRComment"| WA["wiring.Adapter"]
WA -->|"sqlite.PRRow/PRCheckRow/PRCommentRow"| STORE_OLD["*sqlite.Store"]
STORE_OLD -->|"gen.* params"| DB[("SQLite DB")]
WA -.->|"3 struct copies"| STRUCTS["ports.* + sqlite.* + gen.*"]
end
subgraph After
LCM_NEW["lifecycle.Manager"] -->|"domain.PRRow/PRCheckRow/PRComment"| STORE_NEW["*sqlite.Store"]
STORE_NEW -->|"genPRParams / genCheckParams / genCommentParams"| DB2[("SQLite DB")]
STORE_NEW -.->|"2 struct copies"| STRUCTS2["domain.* + gen.*"]
end
style WA fill:#f99,stroke:#900
style STRUCTS fill:#f99,stroke:#900
style STORE_NEW fill:#9f9,stroke:#090
style STRUCTS2 fill:#9f9,stroke:#090
Reviews (2): Last reviewed commit: "refactor(storage): add compile-time port..." | Re-trigger Greptile |
Re-add the blank-identifier interface assertions lost when wiring.Adapter was collapsed: *Store now directly satisfies ports.SessionStore and ports.PRWriter, so prove it at the point of definition. Drift between either port and the implementation now fails here instead of at the call sites in lifecycle_wiring or tests. Addresses greptile review comment on #60. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…finition Each PR-child table (pr / pr_checks / pr_comment) had three near-identical structs — gen.* (generated), sqlite.*Row, and ports.* — with wiring.Adapter copying field-by-field between them. Collapse to one shared definition per table in domain (PRRow / PRCheckRow / PRComment), used by both the PRWriter port and the sqlite store; gen.* stays sealed inside the storage layer. - *sqlite.Store now satisfies ports.SessionStore + ports.PRWriter directly, so the entire wiring.Adapter package is deleted (lifecycle.New(store, store)). - The bool PR state <-> single state column, int<->int64, and enum-default translation now lives only at the gen<->domain boundary in pr_store.go. - WritePRObservation renamed WritePR to match the port; the integration test and composition root drop their adapter copies. Net -280 lines, behaviour unchanged. go test -race ./... green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Re-add the blank-identifier interface assertions lost when wiring.Adapter was collapsed: *Store now directly satisfies ports.SessionStore and ports.PRWriter, so prove it at the point of definition. Drift between either port and the implementation now fails here instead of at the call sites in lifecycle_wiring or tests. Addresses greptile review comment on #60. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
0baa4f0 to
42eab57
Compare
What
Collapses the duplicate PR row types. Each PR-child table (
pr/pr_checks/pr_comment) had three near-identical structs —gen.*(sqlc-generated),sqlite.*Row, andports.*— withwiring.Adaptercopying field-by-field between them. This keeps one shared definition per table indomain, used by both thePRWriterport and the sqlite store. The generatedgen.*stays sealed inside the storage layer (it's the one layer that legitimately can't be the canonical model — driver-typed, flat, generated).Changes
wiring.Adapterpackage.*sqlite.Storenow satisfiesports.SessionStore+ports.PRWriterdirectly, so the composition root is justlifecycle.New(store, store, …)— no bridge.domain.PRRow/domain.PRCheckRow/domain.PRComment; removed thesqlite.*Rowandports.PR*copies.statecolumn,int↔int64, enum defaults) now lives in exactly one place —pr_store.go'sgen ↔ domainboundary.WritePRObservation→WritePRto match the port. The integration test andwiring_test.godrop their adapter copies.Impact
From 3 structs per table → 2 (the generated one + one shared domain type), behaviour unchanged.
go build,go vet, andgo test -race ./...all green.Note for review
PRFactsForSession's "which PR drives display status" rule was already a*Storemethod (pr_facts.go); deleting the adapter leaves it there. It's a read-query but mild product logic in the storage layer — happy to pull it into a thin helper if reviewers prefer storage stay rule-free.🤖 Generated with Claude Code