1+ // @index Automatic postprocess policy state, decision logic, and persistence.
12package policy
23
34import (
@@ -32,12 +33,14 @@ const (
3233 DefaultStatusLimit = 5
3334)
3435
36+ // @intent scope policy status queries by namespace, tool, and recent-run history length.
3537type StatusOptions struct {
3638 Namespace string
3739 Tool string
3840 RecentLimit int
3941}
4042
43+ // @intent expose the latest persisted automatic policy state for one namespace and tool.
4144type StateSnapshot struct {
4245 Namespace string `json:"namespace"`
4346 Tool string `json:"tool"`
@@ -46,6 +49,7 @@ type StateSnapshot struct {
4649 ConsecutiveFailures int `json:"consecutive_failures"`
4750}
4851
52+ // @intent describe one recorded postprocess run for status and failure inspection.
4953type RunSnapshot struct {
5054 Namespace string `json:"namespace"`
5155 Tool string `json:"tool"`
@@ -57,17 +61,20 @@ type RunSnapshot struct {
5761 CreatedAt time.Time `json:"created_at"`
5862}
5963
64+ // @intent bundle fail-closed state and recent failures into one operator-facing policy summary.
6065type StatusSummary struct {
6166 Status string `json:"status"`
6267 FailClosed []StateSnapshot `json:"fail_closed,omitempty"`
6368 RecentFailures []RunSnapshot `json:"recent_failures,omitempty"`
6469}
6570
71+ // @intent carry the inputs that influence automatic postprocess policy resolution.
6672type DecisionInput struct {
6773 Tool string
6874 ExplicitPolicy string
6975}
7076
77+ // @intent capture the outcome and policy metadata of one postprocess execution.
7178type RunRecord struct {
7279 Tool string
7380 Policy string
@@ -78,17 +85,23 @@ type RunRecord struct {
7885 CreatedAt time.Time
7986}
8087
88+ // @intent resolve effective postprocess policy from explicit input plus stored failure history.
8189type Engine struct {}
8290
91+ // @intent persist and query namespace-scoped postprocess policy state and run history.
8392type Store struct {
8493 db * gorm.DB
8594 runLogRetention int
8695}
8796
97+ // NewStore creates a persistence helper for postprocess policy state and run logs.
98+ // @intent keep policy decisions and failure streaks queryable across build and postprocess executions.
8899func NewStore (db * gorm.DB ) * Store {
89100 return & Store {db : db , runLogRetention : DefaultRunLogRetention }
90101}
91102
103+ // Resolve selects the effective postprocess policy for the current namespace and tool.
104+ // @intent default to degraded execution while escalating to fail_closed after repeated recent failures.
92105func (e * Engine ) Resolve (ctx context.Context , store * Store , input DecisionInput ) (string , string , error ) {
93106 if input .ExplicitPolicy != "" {
94107 return input .ExplicitPolicy , SourceExplicit , nil
@@ -106,6 +119,8 @@ func (e *Engine) Resolve(ctx context.Context, store *Store, input DecisionInput)
106119 return PolicyDegraded , SourceAuto , nil
107120}
108121
122+ // GetState returns the latest stored postprocess policy for the active namespace and tool.
123+ // @intent expose the current automatic policy decision without scanning historical runs.
109124func (s * Store ) GetState (ctx context.Context , tool string ) (* model.PostprocessPolicyState , error ) {
110125 var state model.PostprocessPolicyState
111126 ns := ctxns .FromContext (ctx )
@@ -119,6 +134,9 @@ func (s *Store) GetState(ctx context.Context, tool string) (*model.PostprocessPo
119134 return & state , nil
120135}
121136
137+ // RecordRun appends one postprocess execution result and updates the latest policy snapshot.
138+ // @intent preserve the audit trail needed for failure escalation while keeping a cheap current-state lookup.
139+ // @sideEffect writes a run log row and upserts namespace-scoped policy state.
122140func (s * Store ) RecordRun (ctx context.Context , record RunRecord ) error {
123141 ns := ctxns .FromContext (ctx )
124142 createdAt := record .CreatedAt
@@ -166,6 +184,8 @@ func (s *Store) RecordRun(ctx context.Context, record RunRecord) error {
166184 })
167185}
168186
187+ // Reset records a successful reset marker for the named postprocess tool.
188+ // @intent clear automatic fail_closed escalation after an operator has remediated the underlying issue.
169189func (s * Store ) Reset (ctx context.Context , tool string ) error {
170190 if ! ValidTool (tool ) {
171191 return trace .New ("invalid postprocess tool" )
@@ -179,6 +199,8 @@ func (s *Store) Reset(ctx context.Context, tool string) error {
179199 })
180200}
181201
202+ // Status summarizes fail-closed state and recent failures for the requested scope.
203+ // @intent give operators one status view that explains why automatic postprocess execution is degraded.
182204func (s * Store ) Status (ctx context.Context , opts StatusOptions ) (* StatusSummary , error ) {
183205 limit := opts .RecentLimit
184206 if limit <= 0 {
@@ -238,6 +260,8 @@ func (s *Store) Status(ctx context.Context, opts StatusOptions) (*StatusSummary,
238260 return summary , nil
239261}
240262
263+ // ConsecutiveFailures counts recent non-success runs for the active namespace and tool.
264+ // @intent power escalation decisions without leaking cross-namespace failure history.
241265func (s * Store ) ConsecutiveFailures (ctx context.Context , tool string , limit int ) (int , error ) {
242266 if limit <= 0 {
243267 return 0 , nil
@@ -246,6 +270,8 @@ func (s *Store) ConsecutiveFailures(ctx context.Context, tool string, limit int)
246270 return s .consecutiveFailuresScoped (ctx , ns , tool , limit )
247271}
248272
273+ // ValidTool reports whether a tool participates in automatic postprocess policy tracking.
274+ // @intent reject arbitrary tool names before they can create inconsistent policy rows.
249275func ValidTool (tool string ) bool {
250276 switch tool {
251277 case ToolBuildOrUpdateGraph , ToolRunPostprocess :
@@ -255,6 +281,7 @@ func ValidTool(tool string) bool {
255281 }
256282}
257283
284+ // @intent count trailing failures for one namespace and tool without crossing reset or success boundaries.
258285func (s * Store ) consecutiveFailuresScoped (ctx context.Context , namespace , tool string , limit int ) (int , error ) {
259286 var logs []model.PostprocessRunLog
260287 if err := s .db .WithContext (ctx ).
@@ -275,6 +302,7 @@ func (s *Store) consecutiveFailuresScoped(ctx context.Context, namespace, tool s
275302 return count , nil
276303}
277304
305+ // @intent list stored postprocess policy states for the requested namespace and tool scope.
278306func (s * Store ) listStates (ctx context.Context , namespace , tool string ) ([]model.PostprocessPolicyState , error ) {
279307 query := s .db .WithContext (ctx ).Model (& model.PostprocessPolicyState {})
280308 if namespace != "" {
@@ -290,6 +318,7 @@ func (s *Store) listStates(ctx context.Context, namespace, tool string) ([]model
290318 return states , nil
291319}
292320
321+ // @intent retrieve the most recent failed runs used to explain degraded or fail-closed policy status.
293322func (s * Store ) listLatestFailedRuns (ctx context.Context , namespace , tool string , limit int ) ([]RunSnapshot , error ) {
294323 if limit <= 0 {
295324 return nil , nil
@@ -327,6 +356,7 @@ func (s *Store) listLatestFailedRuns(ctx context.Context, namespace, tool string
327356 return runs , nil
328357}
329358
359+ // @intent cap run log growth per namespace and tool while preserving the newest history.
330360func (s * Store ) pruneRunLogs (tx * gorm.DB , namespace , tool string ) error {
331361 if s .runLogRetention <= 0 {
332362 return nil
@@ -352,6 +382,7 @@ func (s *Store) pruneRunLogs(tx *gorm.DB, namespace, tool string) error {
352382 }
353383}
354384
385+ // @intent serialize failed and skipped step lists into the JSON strings stored in policy tables.
355386func marshalStringSlice (values []string ) (string , error ) {
356387 if len (values ) == 0 {
357388 return "[]" , nil
@@ -363,6 +394,7 @@ func marshalStringSlice(values []string) (string, error) {
363394 return string (raw ), nil
364395}
365396
397+ // @intent decode stored JSON step lists back into slices for status reporting.
366398func unmarshalStringSlice (raw string ) ([]string , error ) {
367399 if raw == "" {
368400 return nil , nil
0 commit comments