package graph import ( "context" "sourcecraft.dev/bigbes/sr-ht-spec/core" "sourcecraft.dev/bigbes/sr-ht-spec/service" ) // proposalLister is the service-layer proposal read this package adapts. It is // the method *service.Service grew in Phase 3, named as an interface here so the // adapter is testable without a whole Service and so this file states exactly // what it depends on. type proposalLister interface { ListProposals(ctx context.Context, space core.SpaceRef, state core.ProposalState) ([]service.Proposal, error) } // serviceProposals adapts the service layer to the Proposals port. // // The port yields graph.Proposal (core types, no db/ leak) while the service // yields service.Proposal, and the two cannot be one type without a dependency // cycle — service/ must not import graph/. So the mapping lives here, at the // edge, exactly as web.NewReader adapts the same service to the web surface's // read shape. It is a field-for-field copy; the two structs are deliberately // identical so this stays a rename rather than a translation. type serviceProposals struct{ svc proposalLister } // NewProposals wires the service layer into the schema's proposals field, // closing the gap the Proposals port documented: with this set, Options.Proposals // is no longer nil and the `proposals` query answers from service/ instead of // failing with "no proposal listing yet". func NewProposals(svc proposalLister) Proposals { return serviceProposals{svc: svc} } func (s serviceProposals) ListProposals(ctx context.Context, space core.SpaceRef, state core.ProposalState) ([]Proposal, error) { ps, err := s.svc.ListProposals(ctx, space, state) if err != nil { return nil, err } out := make([]Proposal, 0, len(ps)) for _, p := range ps { out = append(out, Proposal{ ID: p.ID, Space: p.Space, Title: p.Title, Rationale: p.Rationale, BaseRev: p.BaseRev, Branch: p.Branch, State: p.State, Approval: p.Approval, MergedRev: p.MergedRev, Agent: p.Agent, AgentSession: p.AgentSession, Created: p.Created, Resolved: p.Resolved, }) } return out, nil } // Compile-time assertion that the production service satisfies the read this // adapter needs. It lives here, beside the assertions in resolver.go, so a // signature drift in service/ breaks the build rather than a test. var _ proposalLister = (*service.Service)(nil)