Documentation
¶
Overview ¶
Package policydecision defines the protocol-neutral policy decision vocabulary, record model, observer contracts, and bounded evidence normalization shared by core extension runners, diagnostics, and tests.
Safety rules ¶
Records and contexts carry only safe scope values and bounded strings. Raw prompts, raw backend payloads, transport headers, credentials, resume tokens, and unvetted claims must never be placed in a Record or Context. ClientMessage and ClientCategory are the only fields intended for frontend use.
Dependency boundaries ¶
This package may depend only on other public SDK packages under pkg/lipsdk and the standard library. It must not import internal packages, frontend or backend plugin packages, provider SDKs, or transport wire/server packages.
Index ¶
- Constants
- func IsLegalPair(stage string, outcome Outcome, effect Effect) bool
- func IsLegalStageID(stage string) bool
- func IsNoopObserver(obs Observer) bool
- func LegalDecisionStages() []string
- func LegalStageIDs() []string
- func ValidateRecord(record Record) error
- type AccountingProjection
- type AccountingReasonCode
- type AllowedDecision
- type ChainObserver
- type Context
- type Effect
- type EvidenceVisibility
- type FailureBehavior
- type NoopObserver
- type Observer
- type Outcome
- type ProviderRef
- type Record
Constants ¶
const ( CategoryAllowed = "policy_allowed" CategorySkipped = "policy_skipped" CategoryDenied = "policy_denied" CategoryFailure = "policy_failure" CategoryObserved = "policy_observed" CategoryMalformed = "policy_malformed" )
Client category values carried on Record.ClientCategory. They are the evidence taxonomy shared by core extension runners and projected records (requirements 1.7, 4.6, 9.1). Only ClientCategory and ClientMessage are intended for frontend use; the values mirror the stable policy error kinds so a projected record can be classified the same way as an explicit policy error. These constants are the canonical owner of the category strings; extensions aliases and policy error helpers reference them where boundary rules permit. Wire/JSON values are unchanged.
const ( MaxProviderIDBytes = 128 MaxIdentifierBytes = 128 MaxReasonCodeBytes = 96 MaxClientCategoryBytes = 96 MaxClientMessageBytes = lipapi.MaxClientMessageBytes MaxAnnotationEntries = 40 MaxAnnotationKeyBytes = 64 MaxAnnotationValueBytes = 256 )
Normalization bounds for evidence fields (design §Evidence Normalization Contract). Exported so operators, diagnostics, and tests can rely on the same bounds the normalizer applies.
Variables ¶
This section is empty.
Functions ¶
func IsLegalPair ¶
IsLegalPair reports whether (stage, outcome, effect) is one of the allowed combinations in the legality table. Unknown stages, OutcomeUnknown, unknown effects, or pairs not listed return false.
func IsLegalStageID ¶
IsLegalStageID reports whether stage is one of the legal pipeline stages.
func IsNoopObserver ¶
IsNoopObserver reports whether obs is a disabled default observer: a nil observer, NoopObserver, or an empty ChainObserver. Composition roots use it to skip evidence attachment and logging for deployments without policy decision observation, keeping the no-op path cheap (requirements 7.6, 10.5). A ChainObserver wrapping only NoopObserver children is not treated as no-op here; such wiring is not produced by the default composition root.
func LegalDecisionStages ¶
func LegalDecisionStages() []string
LegalDecisionStages returns the unique legal stage IDs that have at least one allowed decision, in canonical pipeline order. It is the set of stages for which policy decision records may be emitted or accepted.
func LegalStageIDs ¶
func LegalStageIDs() []string
LegalStageIDs returns the ordered legal pipeline stage IDs (delegates to pkg/lipsdk/feature so callers do not need a second stage taxonomy).
func ValidateRecord ¶
ValidateRecord validates a policy decision record against the legality descriptors (requirements 1.5, 3.6, 4.4, 6.6). It rejects unknown stages, OutcomeUnknown, unknown effects, and illegal outcome/effect pairs as malformed policy decisions. It does not merge or order records: deterministic application order remains with the stage runners.
Stage identifiers may carry surrounding whitespace that normalization would trim; callers that want whitespace-tolerant validation must trim the stage before calling ValidateRecord.
Types ¶
type AccountingProjection ¶
type AccountingProjection struct {
ReasonCode AccountingReasonCode
RuleID string
Authority string
ReservationID string
SettlementStatus string
}
AccountingProjection carries safe accounting metadata that may be projected into a policydecision.Record without changing the base policy outcome/effect.
type AccountingReasonCode ¶
type AccountingReasonCode string
AccountingReasonCode is the bounded reason taxonomy used when projecting accounting decisions into policy-compatible evidence.
const ( AccountingReasonAllowed AccountingReasonCode = "allowed" AccountingReasonAdvisory AccountingReasonCode = "advisory" AccountingReasonClamped AccountingReasonCode = "clamped" AccountingReasonReserved AccountingReasonCode = "reserved" AccountingReasonReconciled AccountingReasonCode = "reconciled" AccountingReasonQuotaExceeded AccountingReasonCode = "quota_exceeded" AccountingReasonRateLimited AccountingReasonCode = "rate_limited" AccountingReasonBudgetExceeded AccountingReasonCode = "budget_exceeded" AccountingReasonReservationFailed AccountingReasonCode = "reservation_failed" AccountingReasonError AccountingReasonCode = "error" )
func (AccountingReasonCode) IsKnown ¶
func (r AccountingReasonCode) IsKnown() bool
IsKnown reports whether r is one of the documented accounting reason codes.
type AllowedDecision ¶
AllowedDecision describes one legal (stage, outcome, effect) combination that core may emit or accept for a stage (requirements 1.5, 3.6, 4.4, 6.6). The table is intentionally stricter than feature.StageMutationRole: the feature role says what the stage family may do, while this table says which shared policy-decision records core may emit or accept for that stage.
func AllowedDecisionsForStage ¶
func AllowedDecisionsForStage(stage string) []AllowedDecision
AllowedDecisionsForStage returns the legal decision descriptors for stage in canonical order, or nil if the stage is unknown. The returned slice and its effect sub-slices are defensive copies; callers may mutate them without affecting the package table (requirements 1.5, 3.6).
type ChainObserver ¶
type ChainObserver struct {
// contains filtered or unexported fields
}
ChainObserver fans a record out to each non-nil child observer in registration order. Each child receives its own cloned copy of the record; child errors are ignored (fail-open) so a misbehaving observer cannot change request execution. A nil or empty chain behaves as NoopObserver.
func NewChainObserver ¶
func NewChainObserver(observers ...Observer) ChainObserver
NewChainObserver returns a ChainObserver that fans records out to the supplied observers in order. nil observers are dropped.
func (ChainObserver) Observers ¶
func (c ChainObserver) Observers() []Observer
Observers returns a defensive copy of the child observers in chain order.
func (ChainObserver) OnPolicyDecision ¶
func (c ChainObserver) OnPolicyDecision(ctx context.Context, record Record) error
OnPolicyDecision implements Observer by delivering a fresh clone of record to each child. Errors are ignored so request execution is unaffected (requirement 7.6).
type Context ¶
type Context struct {
TraceID string `json:"trace_id"`
ALegID string `json:"a_leg_id"`
BLegID string `json:"b_leg_id"`
AttemptSeq int `json:"attempt_seq"`
Stage string `json:"stage"`
ProviderID string `json:"provider_id"`
Scope scope.PrincipalScopeView `json:"scope"`
Principal execview.PrincipalView `json:"principal"`
Session session.SessionView `json:"session"`
Workspace workspace.WorkspaceView `json:"workspace"`
Annotations map[string]string `json:"annotations,omitempty"`
OutputCommitted bool `json:"output_committed"`
EvaluationTimeout time.Duration `json:"evaluation_timeout,omitempty"`
EvaluationDeadline time.Time `json:"evaluation_deadline,omitzero"`
}
Context is the safe, request-scoped attribution and lifecycle metadata for one decision evaluation or emitted record (requirements 2.1-2.6, 7.5). It is safe-by-construction: raw credentials, headers, resume tokens, and unvetted claims are never fields here. Authority comes from the accepted request's authoritative scope view; legacy principal projection is carried separately so policy code can distinguish authoritative scope from compatibility fields.
type Effect ¶
type Effect string
Effect describes what a decision does to request or response content beyond the outcome itself (requirement 1.2). EffectNone is the zero value and is always legal when paired with a known outcome that does not require mutation.
type EvidenceVisibility ¶
type EvidenceVisibility string
EvidenceVisibility controls whether privileged diagnostic detail may leave the core extension runner (requirement 7.4). EvidenceDefault is the zero value and the only value emitted unless explicit diagnostics exposure posture is enabled.
const ( EvidenceDefault EvidenceVisibility = "default" EvidencePrivileged EvidenceVisibility = "privileged" )
func (EvidenceVisibility) IsKnown ¶
func (v EvidenceVisibility) IsKnown() bool
IsKnown reports whether v is one of the documented visibility values.
type FailureBehavior ¶
type FailureBehavior string
FailureBehavior records how a stage runner should treat provider failures for the decision (requirement 6.1, 6.2). FailureBehaviorUnspecified is the zero value.
const ( FailureBehaviorUnspecified FailureBehavior = "" FailureBehaviorFailOpen FailureBehavior = "fail_open" FailureBehaviorFailClosed FailureBehavior = "fail_closed" )
func (FailureBehavior) IsKnown ¶
func (b FailureBehavior) IsKnown() bool
IsKnown reports whether b is one of the documented non-unspecified behaviors.
type NoopObserver ¶
type NoopObserver struct{}
NoopObserver is the default disabled observer. It is cheap and safe to share.
func (NoopObserver) OnPolicyDecision ¶
func (NoopObserver) OnPolicyDecision(context.Context, Record) error
OnPolicyDecision implements Observer by returning nil without touching the record.
type Observer ¶
Observer receives normalized policy decision records from the core evidence emitter (requirements 7.6, 7.7). Implementations must not change request execution; the evidence emitter isolates observer failures from runtime outcomes. Each observer in a chain receives its own cloned record so observer mutation cannot affect another observer or runtime state.
type Outcome ¶
type Outcome string
Outcome is the protocol-neutral result of one policy decision provider at a lifecycle position. OutcomeUnknown is the zero value and is never legal in an emitted record (requirement 1.1, 1.5).
type ProviderRef ¶
ProviderRef identifies the decision provider that produced a record and the stage it ran at. IDs are stable plugin identifiers; Stage is a legal feature stage ID.
type Record ¶
type Record struct {
TraceID string `json:"trace_id"`
ALegID string `json:"a_leg_id"`
BLegID string `json:"b_leg_id"`
AttemptSeq int `json:"attempt_seq"`
Stage string `json:"stage"`
Provider ProviderRef `json:"provider"`
Outcome Outcome `json:"outcome"`
Effect Effect `json:"effect"`
ReasonCode string `json:"reason_code"`
ClientCategory string `json:"client_category"`
ClientMessage string `json:"client_message"`
FailureBehavior FailureBehavior `json:"failure_behavior"`
Visibility EvidenceVisibility `json:"visibility"`
Scope scope.PrincipalScopeView `json:"scope"`
Annotations map[string]string `json:"annotations,omitempty"`
OutputCommitted bool `json:"output_committed"`
BackendAttempted bool `json:"backend_attempted"`
EvaluationTimeout time.Duration `json:"evaluation_timeout,omitempty"`
EvaluationDeadline time.Time `json:"evaluation_deadline,omitzero"`
}
Record is the in-memory decision evidence DTO for one provider decision or one projected extension outcome (requirements 1.1, 1.6, 7.1). Mutable maps and the embedded scope view are deep-cloned at observer boundaries; callers and observers must not mutate a shared record in place.
func NormalizeRecord ¶
NormalizeRecord returns a bounded, safe copy of record suitable for observer delivery and structured logging (requirements 7.3, 7.7). It clones maps and the embedded scope view, trims and bounds strings, normalizes reason codes and client categories to safe-token form, removes control characters from client messages, drops oversized or invalid annotation keys, truncates annotation values, and marks truncation with a bounded annotation. It does not validate legality; validation is performed by core before normalization is applied.
func ProjectAccountingRecord ¶
func ProjectAccountingRecord(record Record, projection AccountingProjection) (Record, bool)
ProjectAccountingRecord attaches bounded accounting annotations to record while preserving the base decision fields. It returns ok=false when a caller supplies an unknown accounting reason code or when the resulting record is not a legal policydecision record.