// Package capture is the Clean-Architecture use-case for the uniform // capture capability (issue #49/#51): persist a finished session's // valuable output — insights → brain, action items → Gitea tickets, // optional summary → ai-sessions — with one invocation, identical core // behaviour across every harness. // // This package is pure orchestration. It depends only on ports // (interfaces) and plain entities — no HTTP, no live Gitea, no embedding // or audit I/O. The real adapters are wired in #52 (Gitea tracker), #53 // (REST + I1 origin gate), and #54/#55 (audit path + relay). The I1 // sovereignty refusal and the classification-aware audit degradation are // deliberately NOT here — those need the server-derived principal origin // (#53) and the loki/buffer machinery (#54). What lives here is everything // testable against fakes: validation, effective-classification resolution // (stricter wins), best-effort orchestration, and the partial receipt. package capture // CaptureContext is the per-session metadata accompanying a capture. // // Classification is the caller-declared sensitivity (model C, spec §4.1): // the server independently derives the target's classification and gates // on the stricter of the two. Principal is server-derived from the // authenticated identity (#53 populates it); it is never caller-asserted. // Harness is descriptive telemetry only — never a gate input. type CaptureContext struct { Harness string SessionRef string Fidelity string Actor string Classification string // caller-declared level token ("" = unspecified) Principal string // server-derived (auth); audit identity } // Insight is one piece of session knowledge bound for the brain. A // non-empty SupersedeSlug routes to Update (revise in place); otherwise // Write (create). type Insight struct { Text string Wing string Hall string SupersedeSlug string } // Ticket is one action item bound for a Gitea repo. Owner is always the // operator (set by the tracker adapter), never carried here. type Ticket struct { Repo string Action string // create | close | comment Number int // required for close/comment Title string // required for create Body string } // Summary is an optional session summary bound for ai-sessions. type Summary struct { Title string Body string ReposTouched []string } // CaptureInput is the whole capture request. type CaptureInput struct { Context CaptureContext Insights []Insight Tickets []Ticket Summary *Summary DryRun bool } // InsightResult is the per-insight outcome in the receipt. type InsightResult struct { ID string `json:"id,omitempty"` Path string `json:"path,omitempty"` ContentHash string `json:"content_hash,omitempty"` Superseded bool `json:"superseded"` OK bool `json:"ok"` } // TicketResult is the per-ticket outcome in the receipt. type TicketResult struct { Repo string `json:"repo"` Number int `json:"number,omitempty"` Action string `json:"action"` URL string `json:"url,omitempty"` OK bool `json:"ok"` } // SummaryResult is the summary outcome in the receipt. type SummaryResult struct { Path string `json:"path,omitempty"` OK bool `json:"ok"` } // ItemError pins a failure to a specific request item for the partial // receipt. Item is a stable locator like "insight[1]" or "ticket[0]". type ItemError struct { Item string `json:"item"` Error string `json:"error"` } // CaptureReceipt is the structured, partial-aware result. Per-item ok // flags plus a flat Errors list make partial success explicit; the // caller never has to infer what landed. type CaptureReceipt struct { Insights []InsightResult `json:"insights"` Tickets []TicketResult `json:"tickets"` Summary *SummaryResult `json:"summary,omitempty"` Errors []ItemError `json:"errors"` EffectiveClassification string `json:"effective_classification,omitempty"` DryRun bool `json:"dry_run"` }