diff --git a/docs/cli.md b/docs/cli.md index f2877b7..6045196 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -96,7 +96,7 @@ period, prompt version, timezone, and status. Successful output has an absolute "command": "generate", "reportId": "today", "promptId": "weather.today_generated_text", - "promptVersion": "2.0.0", + "promptVersion": "2.1.0", "runId": "20260529T120000.000000000Z_today", "status": "succeeded", "timezone": "America/Chicago", diff --git a/docs/integrations/promptkit.md b/docs/integrations/promptkit.md index 54bb432..035cfe3 100644 --- a/docs/integrations/promptkit.md +++ b/docs/integrations/promptkit.md @@ -1,6 +1,6 @@ # Promptkit Integration -Weatherreporter uses Promptkit for all generated-text reports. The four logical prompts are `weather.daily_generated_text`, `weather.today_generated_text`, `weather.tomorrow_generated_text`, and `weather.hourly_generated_text`, each at version `2.0.0`. Their prompt assets, generated-text JSON Schemas, and Weatherreporter profile catalog are embedded by `internal/promptassets`. +Weatherreporter uses Promptkit for all generated-text reports. The four logical prompts are `weather.daily_generated_text`, `weather.today_generated_text`, `weather.tomorrow_generated_text`, and `weather.hourly_generated_text`, each at version `2.1.0`. Their prompt assets, generated-text JSON Schemas, and Weatherreporter profile catalog are embedded by `internal/promptassets`. ## Logical Profile Catalog @@ -44,6 +44,13 @@ request bodies, response bodies, and complete parameter maps. Promptkit receives the YAML data package as an inline input and returns structured JSON that Weatherreporter validates before rendering its own Markdown template. Before accepting that JSON, Weatherreporter requires exactly one preparation callback and reconciles its prompt/profile/backend/model and rendered/input hashes with the inspected identity and completed result. The callback output contract and completed validation must use the report's expected JSON Schema mode and path. The package contains only reviewed prompt-facing warning summaries, never source transport or provenance details. Safe active provenance remains in memory. Content-rich diagnostics are opt-in through `--llm-debug-dir`; see [operations](../operations.md) for retention and permissions. +Each embedded prompt permits one Promptkit-owned corrective generation after an +eligible failed or explicitly empty result. This is not an application retry: +Weatherreporter performs no provider retry, profile fallback, or request-level +output-contract override. Promptkit reports cumulative usage and the actual +number of corrective calls; repair exhaustion remains a completed validation +failure. + When capture is enabled, its preparation artifact projects a provider endpoint to its scheme and host and retains only reviewed execution settings. Provider extras and URL user information, paths, queries, and fragments are omitted. diff --git a/docs/policy/architecture.md b/docs/policy/architecture.md index 24d7378..bdc8190 100644 --- a/docs/policy/architecture.md +++ b/docs/policy/architecture.md @@ -56,6 +56,8 @@ directly. executes them. - Prompt and profile validation completes before weather collection. Raw output is validated before template rendering. +- PromptKit may make at most the prompt contract's one corrective generation; + exhaustion is a validation rejection, not an application-level retry. - Comparison validates every explicit profile before collection, prepares one immutable report input, and delegates backend capacity to Promptkit rather than adding an application-wide execution limit. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 173daf1..42bac61 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -332,6 +332,8 @@ GOWORK=off go test -race -count=1 ./internal/app ### Stage 6: Activate One Repair And Expose Ordinary Result Provenance +Status: Complete. + Purpose: switch the operational prompts to the accepted one-correction policy and make ordinary generate/run/batch output report what occurred. diff --git a/internal/adapters/promptkit/adapter_test.go b/internal/adapters/promptkit/adapter_test.go index a9c2a52..4d5a860 100644 --- a/internal/adapters/promptkit/adapter_test.go +++ b/internal/adapters/promptkit/adapter_test.go @@ -126,11 +126,11 @@ func (client *fakeClient) allRequests() []promptkit.GenerateRequest { func TestInspectPromptAndProfile(t *testing.T) { adapter := newTestAdapter(t, &fakeClient{}) - inspection, err := adapter.InspectPrompt(context.Background(), "weather.daily_generated_text", "2.0.0") + inspection, err := adapter.InspectPrompt(context.Background(), "weather.daily_generated_text", "2.1.0") if err != nil { t.Fatalf("InspectPrompt() error = %v", err) } - if inspection.PromptID != "weather.daily_generated_text" || inspection.PromptVersion != "2.0.0" || inspection.DefaultProfileID != "weather-balanced" { + if inspection.PromptID != "weather.daily_generated_text" || inspection.PromptVersion != "2.1.0" || inspection.DefaultProfileID != "weather-balanced" || inspection.Output.RepairAttempts != 1 { t.Fatalf("inspection = %#v", inspection) } if len(inspection.Inputs) != 1 || inspection.Inputs[0].Name != "data_package" || !inspection.Inputs[0].Required || inspection.Inputs[0].ContentType != "application/yaml" { @@ -404,7 +404,7 @@ func TestExecuteEmbeddedHourlyProfileThroughPreparedPath(t *testing.T) { } request := promptexec.ExecuteRequest{ PromptID: "weather.hourly_generated_text", - PromptVersion: "2.0.0", + PromptVersion: "2.1.0", ProfileID: "weather-light", DataPackage: []byte("report:\n id: hourly\nbriefing: {}\n"), } @@ -832,7 +832,7 @@ func writeProfileFile(t *testing.T, profile string) string { func testExecuteRequest() promptexec.ExecuteRequest { return promptexec.ExecuteRequest{ PromptID: "weather.daily_generated_text", - PromptVersion: "2.0.0", + PromptVersion: "2.1.0", ProfileID: "test-profile", DataPackage: []byte("report:\n id: daily\nbriefing: {}\n"), } diff --git a/internal/app/app.go b/internal/app/app.go index e7eac39..593706f 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -140,7 +140,7 @@ type BatchReportResult struct { ModelName string `json:"modelName,omitempty"` SourceWarnings []weatherdata.SourceWarning `json:"sourceWarnings,omitempty"` ValidationStatus promptexec.ValidationStatus `json:"validationStatus,omitempty"` - RepairAttempts *int `json:"-"` + RepairAttempts *int `json:"repairAttempts,omitempty"` LLMDebugPath string `json:"llmDebugPath,omitempty"` OutputPath string `json:"outputPath,omitempty"` } diff --git a/internal/app/comparison_execution_test.go b/internal/app/comparison_execution_test.go index 14f1762..05b71e8 100644 --- a/internal/app/comparison_execution_test.go +++ b/internal/app/comparison_execution_test.go @@ -170,7 +170,8 @@ func (e *barrierExecutor) Execute(ctx context.Context, req promptexec.ExecuteReq e.mu.Lock() profile := e.profiles[req.ProfileID] e.mu.Unlock() - if err := callback(promptexec.Preparation{PromptID: req.PromptID, PromptVersion: req.PromptVersion, PromptHash: generationPromptHash, ProfileID: req.ProfileID, BackendID: profile.BackendID, ModelName: profile.ModelName, Output: promptexec.OutputContract{Format: "json", ValidationMode: "json_schema", SchemaPath: generationDefinitionForPrompt(req.PromptID).GeneratedTextSchemaID + ".generated_text.schema.json"}, StartedAt: stamp, EndedAt: stamp}, nil); err != nil { + definition := generationDefinitionForPrompt(req.PromptID) + if err := callback(promptexec.Preparation{PromptID: req.PromptID, PromptVersion: req.PromptVersion, PromptHash: generationPromptHash, ProfileID: req.ProfileID, BackendID: profile.BackendID, ModelName: profile.ModelName, Output: promptexec.OutputContract{Format: "json", ValidationMode: "json_schema", SchemaPath: definition.GeneratedTextSchemaID + ".generated_text.schema.json", RepairAttempts: definition.GeneratedTextRepairAttempts}, StartedAt: stamp, EndedAt: stamp}, nil); err != nil { e.callbackFailures <- err return nil, err } diff --git a/internal/app/generation_test.go b/internal/app/generation_test.go index 9bfc834..3d68cc2 100644 --- a/internal/app/generation_test.go +++ b/internal/app/generation_test.go @@ -89,7 +89,7 @@ func (e *generationExecutor) InspectPrompt(_ context.Context, id, version string return promptexec.PromptInspection{}, e.inspectErr } definition := generationDefinitionForPrompt(id) - return promptexec.PromptInspection{PromptID: id, PromptVersion: version, PromptHash: generationPromptHash, DefaultProfileID: "fixture", Inputs: []promptexec.InputDefinition{{Name: "data_package", Required: true, ContentType: "application/yaml"}}, Output: promptexec.OutputContract{Format: "json", ValidationMode: "json_schema", SchemaPath: definition.GeneratedTextSchemaID + ".generated_text.schema.json"}}, nil + return promptexec.PromptInspection{PromptID: id, PromptVersion: version, PromptHash: generationPromptHash, DefaultProfileID: "fixture", Inputs: []promptexec.InputDefinition{{Name: "data_package", Required: true, ContentType: "application/yaml"}}, Output: promptexec.OutputContract{Format: "json", ValidationMode: "json_schema", SchemaPath: definition.GeneratedTextSchemaID + ".generated_text.schema.json", RepairAttempts: definition.GeneratedTextRepairAttempts}}, nil } func (e *generationExecutor) InspectProfile(_ context.Context, id string) (promptexec.ProfileInspection, error) { generationExecutorMu.Lock() @@ -113,7 +113,8 @@ func (e *generationExecutor) Execute(ctx context.Context, req promptexec.Execute calls = 1 } for range calls { - preparation := promptexec.Preparation{PromptID: req.PromptID, PromptVersion: req.PromptVersion, PromptHash: generationPromptHash, RenderedPromptHash: "rendered-hash", ProfileID: req.ProfileID, BackendID: "fixture", ModelName: "fixture-model", Output: promptexec.OutputContract{Format: "json", ValidationMode: "json_schema", SchemaPath: generationDefinitionForPrompt(req.PromptID).GeneratedTextSchemaID + ".generated_text.schema.json"}, StartedAt: stamp, EndedAt: stamp} + definition := generationDefinitionForPrompt(req.PromptID) + preparation := promptexec.Preparation{PromptID: req.PromptID, PromptVersion: req.PromptVersion, PromptHash: generationPromptHash, RenderedPromptHash: "rendered-hash", ProfileID: req.ProfileID, BackendID: "fixture", ModelName: "fixture-model", Output: promptexec.OutputContract{Format: "json", ValidationMode: "json_schema", SchemaPath: definition.GeneratedTextSchemaID + ".generated_text.schema.json", RepairAttempts: definition.GeneratedTextRepairAttempts}, StartedAt: stamp, EndedAt: stamp} if prepare != nil { prepare(&preparation) } diff --git a/internal/app/prompt_inspection_test.go b/internal/app/prompt_inspection_test.go index 0ec609b..8b14a0a 100644 --- a/internal/app/prompt_inspection_test.go +++ b/internal/app/prompt_inspection_test.go @@ -350,7 +350,7 @@ func validPromptInspection(definition report.Definition) promptexec.PromptInspec return promptexec.PromptInspection{ PromptID: definition.PromptID, PromptVersion: definition.PromptVersion, PromptHash: "prompt-hash", DefaultProfileID: "default-profile", Inputs: []promptexec.InputDefinition{{Name: "data_package", Required: true, ContentType: "application/yaml"}}, - Output: promptexec.OutputContract{Format: "json", ValidationMode: "json_schema", SchemaPath: definition.GeneratedTextSchemaID + ".generated_text.schema.json"}, + Output: promptexec.OutputContract{Format: "json", ValidationMode: "json_schema", SchemaPath: definition.GeneratedTextSchemaID + ".generated_text.schema.json", RepairAttempts: definition.GeneratedTextRepairAttempts}, } } diff --git a/internal/cli/comparison_test.go b/internal/cli/comparison_test.go index 06a70f7..65036a9 100644 --- a/internal/cli/comparison_test.go +++ b/internal/cli/comparison_test.go @@ -355,7 +355,7 @@ func comparisonResult(outputDirectory string, results []app.ComparisonProfileRes started := time.Date(2026, 5, 29, 13, 30, 0, 0, time.UTC) result := &app.ComparisonResult{ ComparisonID: "comparison_run-123", ReportID: "daily", ReportName: "Daily Report", - PromptID: "weather.daily_generated_text", PromptVersion: "2.0.0", PromptHash: strings.Repeat("a", 64), + PromptID: "weather.daily_generated_text", PromptVersion: "2.1.0", PromptHash: strings.Repeat("a", 64), StartedAt: started, FinishedAt: started.Add(time.Minute), Timezone: "America/Chicago", ValidPeriod: timeutil.Period{Start: started, End: started.Add(24 * time.Hour)}, OutputDirectory: outputDirectory, ManifestPath: filepath.Join(outputDirectory, "comparison.json"), DataPackagePath: filepath.Join(outputDirectory, "data-package.yml"), diff --git a/internal/cli/generate_test.go b/internal/cli/generate_test.go index 2d35642..c554e7b 100644 --- a/internal/cli/generate_test.go +++ b/internal/cli/generate_test.go @@ -132,7 +132,7 @@ func actionConfigPath(t *testing.T) string { func generatedReportResult() *app.ReportResult { generatedAt := time.Date(2026, 5, 29, 13, 30, 0, 0, time.UTC) return &app.ReportResult{ - ReportID: report.Daily, ReportName: "Daily Report", PromptID: "weather.daily_generated_text", PromptVersion: "2.0.0", + ReportID: report.Daily, ReportName: "Daily Report", PromptID: "weather.daily_generated_text", PromptVersion: "2.1.0", RunID: "daily-20260529", GeneratedAt: generatedAt, Timezone: "America/Chicago", ValidPeriod: timeutil.Period{Start: generatedAt, End: generatedAt.Add(24 * time.Hour)}, ProfileID: "weather-light", BackendID: "local", ModelName: "weather-model", ValidationStatus: promptexec.ValidationPassed, diff --git a/internal/cli/result.go b/internal/cli/result.go index 3094662..c9afc10 100644 --- a/internal/cli/result.go +++ b/internal/cli/result.go @@ -43,6 +43,7 @@ type generateSummary struct { ModelName string `json:"modelName,omitempty"` SourceWarnings []weatherdata.SourceWarning `json:"sourceWarnings,omitempty"` ValidationStatus string `json:"validationStatus,omitempty"` + RepairAttempts *int `json:"repairAttempts,omitempty"` Notification *generateNotificationSummary `json:"notification,omitempty"` Error string `json:"error,omitempty"` } @@ -129,6 +130,10 @@ func newGenerateSummary(result *app.ReportResult, err error) generateSummary { summary.ProfileID, summary.BackendID, summary.ModelName = result.ProfileID, result.BackendID, result.ModelName summary.SourceWarnings = append([]weatherdata.SourceWarning(nil), result.SourceWarnings...) summary.ValidationStatus = string(result.ValidationStatus) + if result.RepairAttempts != nil { + value := *result.RepairAttempts + summary.RepairAttempts = &value + } summary.OutputPath = result.OutputPath summary.LLMDebugPath = result.LLMDebugPath summary.Notification = newGenerateNotificationSummary(result.Notification) diff --git a/internal/cli/result_test.go b/internal/cli/result_test.go index adf1093..ee48439 100644 --- a/internal/cli/result_test.go +++ b/internal/cli/result_test.go @@ -19,7 +19,7 @@ import ( func TestGenerateSummaryUsesActiveResultFields(t *testing.T) { generatedAt := time.Date(2026, 5, 29, 13, 30, 0, 0, time.UTC) - summary := newGenerateSummary(&app.ReportResult{ReportID: report.Daily, ReportName: "Daily Report", PromptID: "weather.daily_generated_text", PromptVersion: "2.0.0", RunID: "run-123", GeneratedAt: generatedAt, Timezone: "America/Chicago", ValidPeriod: timeutil.Period{Start: generatedAt, End: generatedAt.Add(24 * time.Hour)}, ProfileID: "weather-balanced", BackendID: "openrouter", ModelName: "model", SourceWarnings: []weatherdata.SourceWarning{{Source: "alerts", Message: "source unavailable"}}, ValidationStatus: promptexec.ValidationPassed, OutputPath: "/reports/daily.md"}, nil) + summary := newGenerateSummary(&app.ReportResult{ReportID: report.Daily, ReportName: "Daily Report", PromptID: "weather.daily_generated_text", PromptVersion: "2.1.0", RunID: "run-123", GeneratedAt: generatedAt, Timezone: "America/Chicago", ValidPeriod: timeutil.Period{Start: generatedAt, End: generatedAt.Add(24 * time.Hour)}, ProfileID: "weather-balanced", BackendID: "openrouter", ModelName: "model", SourceWarnings: []weatherdata.SourceWarning{{Source: "alerts", Message: "source unavailable"}}, ValidationStatus: promptexec.ValidationPassed, OutputPath: "/reports/daily.md"}, nil) if summary.OutputPath == "" || summary.ProfileID == "" || summary.ValidationStatus != string(promptexec.ValidationPassed) || len(summary.SourceWarnings) != 1 { t.Fatalf("summary = %#v", summary) } @@ -39,7 +39,7 @@ func TestComparisonSummaryUsesLockedOrderAndSafeFields(t *testing.T) { profileFailure := comparison.NewSafeError("generation", "execute prompt failed") result := &app.ComparisonResult{ ComparisonID: "comparison_run-123", ReportID: report.Daily, ReportName: "Daily Report", - PromptID: "weather.daily_generated_text", PromptVersion: "2.0.0", PromptHash: strings.Repeat("a", 64), + PromptID: "weather.daily_generated_text", PromptVersion: "2.1.0", PromptHash: strings.Repeat("a", 64), StartedAt: started, FinishedAt: started.Add(time.Minute), Timezone: "America/Chicago", ValidPeriod: timeutil.Period{Start: started, End: started.Add(24 * time.Hour)}, OutputDirectory: "/reports/comparison-daily", ManifestPath: "/reports/comparison-daily/comparison.json", DataPackagePath: "/reports/comparison-daily/data-package.yml", @@ -113,7 +113,7 @@ func TestComparisonSummaryClassifiesCompleteAndAllFailedResults(t *testing.T) { started := time.Date(2026, 5, 29, 13, 30, 0, 0, time.UTC) failure := comparison.NewSafeError("generation", "execute prompt failed") complete := &app.ComparisonResult{ - ComparisonID: "comparison_run-123", ReportID: report.Daily, PromptID: "weather.daily_generated_text", PromptVersion: "2.0.0", PromptHash: strings.Repeat("a", 64), + ComparisonID: "comparison_run-123", ReportID: report.Daily, PromptID: "weather.daily_generated_text", PromptVersion: "2.1.0", PromptHash: strings.Repeat("a", 64), StartedAt: started, FinishedAt: started, Timezone: "America/Chicago", ValidPeriod: timeutil.Period{Start: started, End: started.Add(time.Hour)}, OutputDirectory: "/reports/comparison-daily", ManifestPath: "/reports/comparison-daily/comparison.json", DataPackagePath: "/reports/comparison-daily/data-package.yml", Total: 2, Succeeded: 2, diff --git a/internal/promptassets/assets/prompts/daily/daily_generated_text.yml b/internal/promptassets/assets/prompts/daily/daily_generated_text.yml index dad4fb8..1e4a646 100644 --- a/internal/promptassets/assets/prompts/daily/daily_generated_text.yml +++ b/internal/promptassets/assets/prompts/daily/daily_generated_text.yml @@ -1,5 +1,5 @@ id: weather.daily_generated_text -version: "2.0.0" +version: "2.1.0" default_profile: weather-balanced description: Daily weather report analysis prompt. inputs: @@ -21,3 +21,4 @@ output: format: json validation_mode: json_schema schema_path: daily.generated_text.schema.json + repair_attempts: 1 diff --git a/internal/promptassets/assets/prompts/hourly/hourly_generated_text.yml b/internal/promptassets/assets/prompts/hourly/hourly_generated_text.yml index 8371b6b..1fed4e3 100644 --- a/internal/promptassets/assets/prompts/hourly/hourly_generated_text.yml +++ b/internal/promptassets/assets/prompts/hourly/hourly_generated_text.yml @@ -1,5 +1,5 @@ id: weather.hourly_generated_text -version: "2.0.0" +version: "2.1.0" default_profile: weather-light description: Hourly weather report analysis prompt. inputs: @@ -21,3 +21,4 @@ output: format: json validation_mode: json_schema schema_path: hourly.generated_text.schema.json + repair_attempts: 1 diff --git a/internal/promptassets/assets/prompts/today/today_generated_text.yml b/internal/promptassets/assets/prompts/today/today_generated_text.yml index 7c99dbb..aeef471 100644 --- a/internal/promptassets/assets/prompts/today/today_generated_text.yml +++ b/internal/promptassets/assets/prompts/today/today_generated_text.yml @@ -1,5 +1,5 @@ id: weather.today_generated_text -version: "2.0.0" +version: "2.1.0" default_profile: weather-balanced description: Today's weather report analysis prompt. inputs: @@ -21,3 +21,4 @@ output: format: json validation_mode: json_schema schema_path: today.generated_text.schema.json + repair_attempts: 1 diff --git a/internal/promptassets/assets/prompts/tomorrow/tomorrow_generated_text.yml b/internal/promptassets/assets/prompts/tomorrow/tomorrow_generated_text.yml index a97509c..be902fb 100644 --- a/internal/promptassets/assets/prompts/tomorrow/tomorrow_generated_text.yml +++ b/internal/promptassets/assets/prompts/tomorrow/tomorrow_generated_text.yml @@ -1,5 +1,5 @@ id: weather.tomorrow_generated_text -version: "2.0.0" +version: "2.1.0" default_profile: weather-balanced description: Tomorrow's weather report analysis prompt. inputs: @@ -21,3 +21,4 @@ output: format: json validation_mode: json_schema schema_path: tomorrow.generated_text.schema.json + repair_attempts: 1 diff --git a/internal/promptassets/promptassets_test.go b/internal/promptassets/promptassets_test.go index 692e22b..ac8b056 100644 --- a/internal/promptassets/promptassets_test.go +++ b/internal/promptassets/promptassets_test.go @@ -77,8 +77,8 @@ func TestPromptAssetsDeclareTheFourGeneratedTextPrompts(t *testing.T) { if err := yaml.Unmarshal(data, &definition); err != nil { t.Fatalf("decode prompt definition: %v", err) } - if definition.ID != tc.id || definition.Version != "2.0.0" || definition.DefaultProfile != tc.profile { - t.Fatalf("definition = %#v, want %s version 2.0.0 and profile %s", definition, tc.id, tc.profile) + if definition.ID != tc.id || definition.Version != "2.1.0" || definition.DefaultProfile != tc.profile { + t.Fatalf("definition = %#v, want %s version 2.1.0 and profile %s", definition, tc.id, tc.profile) } sharedInstruction := false for _, message := range definition.Messages { @@ -92,8 +92,8 @@ func TestPromptAssetsDeclareTheFourGeneratedTextPrompts(t *testing.T) { if len(definition.Inputs) != 1 || definition.Inputs[0].Name != "data_package" || !definition.Inputs[0].Required || definition.Inputs[0].ContentType != "application/yaml" { t.Fatalf("inputs = %#v, want one required YAML data_package", definition.Inputs) } - if definition.Output.Format != "json" || definition.Output.ValidationMode != "json_schema" || definition.Output.SchemaPath != tc.schemaID+".generated_text.schema.json" || definition.Output.RepairAttempts != nil { - t.Fatalf("output = %#v, want JSON schema output without repair attempts", definition.Output) + if definition.Output.Format != "json" || definition.Output.ValidationMode != "json_schema" || definition.Output.SchemaPath != tc.schemaID+".generated_text.schema.json" || definition.Output.RepairAttempts == nil || *definition.Output.RepairAttempts != 1 { + t.Fatalf("output = %#v, want JSON schema output with one repair attempt", definition.Output) } if _, err := promptassets.Schema(tc.schemaID); err != nil { t.Fatalf("Schema(%q) error = %v", tc.schemaID, err) @@ -286,11 +286,11 @@ func TestPromptkitInspectsEmbeddedPromptsOffline(t *testing.T) { {"weather.hourly_generated_text", "weather-light", "deepseek/deepseek-v4-flash"}, } { t.Run(want.id, func(t *testing.T) { - inspection, err := engine.InspectPrompt(context.Background(), want.id, "2.0.0") + inspection, err := engine.InspectPrompt(context.Background(), want.id, "2.1.0") if err != nil { t.Fatalf("InspectPrompt() error = %v", err) } - if inspection.PromptID != want.id || inspection.PromptVersion != "2.0.0" || inspection.DefaultProfileID != want.profile { + if inspection.PromptID != want.id || inspection.PromptVersion != "2.1.0" || inspection.DefaultProfileID != want.profile || inspection.OutputContract.RepairAttempts != 1 { t.Fatalf("inspection = %#v", inspection) } profile, err := engine.InspectProfile(context.Background(), inspection.DefaultProfileID) @@ -414,7 +414,7 @@ func TestPromptAssetsExcludeRetiredRuntimeSettings(t *testing.T) { if err != nil { return err } - for _, unwanted := range []string{"local-heavy", "pipeline-weather/", "application/json", "repair_attempts:", "weather.daily_report"} { + for _, unwanted := range []string{"local-heavy", "pipeline-weather/", "application/json", "weather.daily_report"} { if strings.Contains(string(data), unwanted) { t.Fatalf("%s contains retired runtime setting %q", path, unwanted) } diff --git a/internal/report/daily_report.go b/internal/report/daily_report.go index bbff680..4661861 100644 --- a/internal/report/daily_report.go +++ b/internal/report/daily_report.go @@ -12,10 +12,10 @@ func dailyDefinition() Definition { ID: Daily, Name: "Daily Report", PromptID: "weather.daily_generated_text", - PromptVersion: "2.0.0", + PromptVersion: "2.1.0", TemplateID: "daily", GeneratedTextSchemaID: "daily", - GeneratedTextRepairAttempts: 0, + GeneratedTextRepairAttempts: 1, ArtifactGroup: "daily", OutputName: "daily.md", DistributorPathTemplates: []string{ diff --git a/internal/report/hourly_report.go b/internal/report/hourly_report.go index bf0e757..973c6e3 100644 --- a/internal/report/hourly_report.go +++ b/internal/report/hourly_report.go @@ -14,10 +14,10 @@ func hourlyDefinition() Definition { ID: Hourly, Name: "Hourly Report", PromptID: "weather.hourly_generated_text", - PromptVersion: "2.0.0", + PromptVersion: "2.1.0", TemplateID: "hourly", GeneratedTextSchemaID: "hourly", - GeneratedTextRepairAttempts: 0, + GeneratedTextRepairAttempts: 1, ArtifactGroup: "hourly", OutputName: "hourly.md", DistributorPathTemplates: []string{ diff --git a/internal/report/period_test.go b/internal/report/period_test.go index 382436c..e3bcd80 100644 --- a/internal/report/period_test.go +++ b/internal/report/period_test.go @@ -82,8 +82,8 @@ func TestRegistryContainsOnlyPromptBackedReports(t *testing.T) { } for _, definition := range definitions { - if definition.PromptVersion != "2.0.0" { - t.Fatalf("%s PromptVersion = %q, want 2.0.0", definition.ID, definition.PromptVersion) + if definition.PromptVersion != "2.1.0" { + t.Fatalf("%s PromptVersion = %q, want 2.1.0", definition.ID, definition.PromptVersion) } if definition.PromptID == "" { t.Fatalf("%s PromptID is empty", definition.ID) @@ -91,8 +91,8 @@ func TestRegistryContainsOnlyPromptBackedReports(t *testing.T) { if definition.TemplateID == "" || definition.GeneratedTextSchemaID == "" { t.Fatalf("%s template/schema = %q/%q, want both set", definition.ID, definition.TemplateID, definition.GeneratedTextSchemaID) } - if definition.GeneratedTextRepairAttempts != 0 { - t.Fatalf("%s repair attempts = %d, want 0", definition.ID, definition.GeneratedTextRepairAttempts) + if definition.GeneratedTextRepairAttempts != 1 { + t.Fatalf("%s repair attempts = %d, want 1", definition.ID, definition.GeneratedTextRepairAttempts) } } diff --git a/internal/report/today_report.go b/internal/report/today_report.go index 9423339..bbe01a6 100644 --- a/internal/report/today_report.go +++ b/internal/report/today_report.go @@ -10,10 +10,10 @@ func todayDefinition() Definition { ID: Today, Name: "Today Report", PromptID: "weather.today_generated_text", - PromptVersion: "2.0.0", + PromptVersion: "2.1.0", TemplateID: "today", GeneratedTextSchemaID: "today", - GeneratedTextRepairAttempts: 0, + GeneratedTextRepairAttempts: 1, ArtifactGroup: "today", OutputName: "today.md", DistributorPathTemplates: []string{ diff --git a/internal/report/tomorrow_report.go b/internal/report/tomorrow_report.go index fdca49c..2e85b59 100644 --- a/internal/report/tomorrow_report.go +++ b/internal/report/tomorrow_report.go @@ -10,10 +10,10 @@ func tomorrowDefinition() Definition { ID: Tomorrow, Name: "Tomorrow Report", PromptID: "weather.tomorrow_generated_text", - PromptVersion: "2.0.0", + PromptVersion: "2.1.0", TemplateID: "tomorrow", GeneratedTextSchemaID: "tomorrow", - GeneratedTextRepairAttempts: 0, + GeneratedTextRepairAttempts: 1, ArtifactGroup: "tomorrow", OutputName: "tomorrow.md", DistributorPathTemplates: []string{