Add durable validation provenance
This commit is contained in:
@@ -42,6 +42,7 @@ type debugTimedEnvelope struct {
|
||||
LaneID string `json:"lane_id,omitempty"`
|
||||
ModuleKey string `json:"module_key,omitempty"`
|
||||
Attempt int `json:"attempt,omitempty"`
|
||||
AttemptKind string `json:"attempt_kind,omitempty"`
|
||||
StartedAt time.Time `json:"started_at"`
|
||||
CompletedAt time.Time `json:"completed_at"`
|
||||
DurationMS int64 `json:"duration_ms"`
|
||||
@@ -143,9 +144,37 @@ type debugLLMCallReference struct {
|
||||
PromptID string `json:"prompt_id,omitempty"`
|
||||
ProfileID string `json:"profile_id,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
PromptTokens int `json:"prompt_tokens,omitempty"`
|
||||
CompletionTokens int `json:"completion_tokens,omitempty"`
|
||||
TotalTokens int `json:"total_tokens,omitempty"`
|
||||
RepairAttempts int `json:"repair_attempts,omitempty"`
|
||||
Error bool `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type debugValidationOutcome struct {
|
||||
ValidatorName string `json:"validator_name"`
|
||||
Outcome string `json:"outcome"`
|
||||
AttemptCount int `json:"attempt_count"`
|
||||
ReasonCode string `json:"reason_code,omitempty"`
|
||||
}
|
||||
|
||||
type debugProducerAttempt struct {
|
||||
Number int `json:"number"`
|
||||
Kind string `json:"kind"`
|
||||
Outcome string `json:"outcome"`
|
||||
Validation []debugValidationOutcome `json:"validation,omitempty"`
|
||||
}
|
||||
|
||||
type debugProducerTerminal struct {
|
||||
ProducerAttemptCount int `json:"producer_attempt_count"`
|
||||
Attempts []debugProducerAttempt `json:"attempts,omitempty"`
|
||||
AggregateReasonCodes []string `json:"aggregate_reason_codes,omitempty"`
|
||||
ValidationComplete bool `json:"validation_complete"`
|
||||
EffectivePolicy ValidationPolicy `json:"effective_policy"`
|
||||
TerminalAction string `json:"terminal_action"`
|
||||
Summary artifacts.ValidationSummary `json:"validation_summary"`
|
||||
}
|
||||
|
||||
type debugValidationCall struct {
|
||||
ValidatorName string `json:"validator_name"`
|
||||
Request any `json:"request"`
|
||||
@@ -250,6 +279,10 @@ func (client *debugLLMClient) CompleteStructured(ctx context.Context, req contra
|
||||
PromptID: req.PromptID,
|
||||
ProfileID: debugFirstNonEmptyString(response.ProfileID, req.ProfileID),
|
||||
Model: debugFirstNonEmptyString(response.Model, debugResponseModel(response)),
|
||||
PromptTokens: response.PromptTokens,
|
||||
CompletionTokens: response.CompletionTokens,
|
||||
TotalTokens: response.TotalTokens,
|
||||
RepairAttempts: response.RepairAttempts,
|
||||
Error: err != nil,
|
||||
}
|
||||
if scope := debugLLMScopeFromContext(ctx); scope != nil {
|
||||
@@ -406,6 +439,50 @@ func (r attemptTerminalRecorder) record(payload any, terminalErr error) error {
|
||||
return terminalErr
|
||||
}
|
||||
|
||||
func debugValidationOutcomes(report validationReport) []debugValidationOutcome {
|
||||
if len(report.records) == 0 {
|
||||
return nil
|
||||
}
|
||||
outcomes := make([]debugValidationOutcome, 0, len(report.records))
|
||||
for _, record := range report.records {
|
||||
outcomes = append(outcomes, debugValidationOutcome{
|
||||
ValidatorName: record.validatorName,
|
||||
Outcome: string(record.outcome),
|
||||
AttemptCount: record.attemptCount,
|
||||
ReasonCode: record.reasonCode,
|
||||
})
|
||||
}
|
||||
return outcomes
|
||||
}
|
||||
|
||||
func writeProducerTerminalDebug(recorder DebugRecorder, name string, terminal producerAttemptTerminal, policy ValidationPolicy, summary artifacts.ValidationSummary) error {
|
||||
attempts := make([]debugProducerAttempt, 0, len(terminal.Provenance))
|
||||
for _, item := range terminal.Provenance {
|
||||
attempts = append(attempts, debugProducerAttempt{
|
||||
Number: item.Number,
|
||||
Kind: string(item.Kind),
|
||||
Outcome: string(item.Outcome),
|
||||
Validation: debugValidationOutcomes(item.Validation),
|
||||
})
|
||||
}
|
||||
return writeDebugTimed(recorder, name, debugTimedEnvelope{
|
||||
Stage: summary.Stage,
|
||||
StepID: summary.StepID,
|
||||
LaneID: summary.LaneID,
|
||||
ModuleKey: summary.ModuleKey,
|
||||
StartedAt: time.Now().UTC(),
|
||||
Payload: debugProducerTerminal{
|
||||
ProducerAttemptCount: summary.ProducerAttemptCount,
|
||||
Attempts: attempts,
|
||||
AggregateReasonCodes: append([]string(nil), summary.ReasonCodes...),
|
||||
ValidationComplete: summary.Status == "complete",
|
||||
EffectivePolicy: policy,
|
||||
TerminalAction: string(terminal.Action),
|
||||
Summary: artifacts.CloneValidationSummary(summary),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func debugContentEnvelope(content []byte, mediaType string, metadata map[string]any, warnings []contracts.Warning) debugBinaryEnvelope {
|
||||
content = redactSecretBytes(content)
|
||||
return debugBinaryEnvelope{
|
||||
|
||||
Reference in New Issue
Block a user