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)