Verify the integrated application and complete the migration
This commit is contained in:
278
cmd/audita/main_integration_test.go
Normal file
278
cmd/audita/main_integration_test.go
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gitea.maximumdirect.net/eric/audita/internal/cli"
|
||||||
|
"gitea.maximumdirect.net/eric/audita/internal/core/reporting"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestProcessSubprocessHelper(t *testing.T) {
|
||||||
|
if os.Getenv("AUDITA_HELPER_PROCESS") != "1" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i, arg := range os.Args {
|
||||||
|
if arg == "--" {
|
||||||
|
os.Exit(cli.Run(os.Args[i+1:], os.Stdout, os.Stderr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
type outboundCall struct {
|
||||||
|
Model string
|
||||||
|
Validation bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type controlledProvider struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
calls []outboundCall
|
||||||
|
proposalCount int
|
||||||
|
mode string
|
||||||
|
secret string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *controlledProvider) serve(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var request struct {
|
||||||
|
Model string `json:"model"`
|
||||||
|
ResponseFormat struct {
|
||||||
|
JSONSchema struct {
|
||||||
|
Schema struct {
|
||||||
|
Properties map[string]any `json:"properties"`
|
||||||
|
} `json:"schema"`
|
||||||
|
} `json:"json_schema"`
|
||||||
|
} `json:"response_format"`
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
||||||
|
http.Error(w, err.Error(), 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, validation := request.ResponseFormat.JSONSchema.Schema.Properties["validations"]
|
||||||
|
p.mu.Lock()
|
||||||
|
p.calls = append(p.calls, outboundCall{request.Model, validation})
|
||||||
|
if !validation {
|
||||||
|
p.proposalCount++
|
||||||
|
}
|
||||||
|
proposalCount := p.proposalCount
|
||||||
|
p.mu.Unlock()
|
||||||
|
if p.mode == "failure" {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
_, _ = fmt.Fprintf(w, `{"error":{"message":"provider echoed %s"}}`, p.secret)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response := `{"corrections":[{"id":1,"original_text":"hello world","corrected_text":"Hello world","confidence":0.99}]}`
|
||||||
|
if validation {
|
||||||
|
response = `{"validations":[{"correction_index":0,"approved":true,"confidence":0.99,"reason":"ok"}]}`
|
||||||
|
}
|
||||||
|
if p.mode == "repair" && !validation && proposalCount == 1 {
|
||||||
|
response = `{"wrong":true}`
|
||||||
|
}
|
||||||
|
if p.mode == "warning" && !validation {
|
||||||
|
response = `{"wrong":true}`
|
||||||
|
}
|
||||||
|
if p.mode == "noop" && !validation {
|
||||||
|
response = `{"corrections":[]}`
|
||||||
|
}
|
||||||
|
if p.mode == "low-confidence" && !validation {
|
||||||
|
response = `{"corrections":[{"id":1,"original_text":"hello world","corrected_text":"Hello world","confidence":0.1}]}`
|
||||||
|
}
|
||||||
|
content, _ := json.Marshal(response)
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
_, _ = fmt.Fprintf(w, `{"model":"synthetic-result","choices":[{"message":{"content":%s}}],"usage":{"prompt_tokens":2,"completion_tokens":3,"total_tokens":5}}`, content)
|
||||||
|
}
|
||||||
|
|
||||||
|
type processFixture struct {
|
||||||
|
dir, config, transcript, glossary, report, output string
|
||||||
|
provider *controlledProvider
|
||||||
|
server *httptest.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
func newProcessFixture(t *testing.T, mode, modules string) processFixture {
|
||||||
|
t.Helper()
|
||||||
|
dir := t.TempDir()
|
||||||
|
p := &controlledProvider{mode: mode, secret: "synthetic-provider-secret-2468"}
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(p.serve))
|
||||||
|
t.Cleanup(server.Close)
|
||||||
|
if err := os.MkdirAll(filepath.Join(dir, "profiles"), 0700); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(filepath.Join(dir, "overlays"), 0700); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for name, model := range map[string]string{"proposal": "base-proposal", "validation": "base-validation", "proposal-testing": "testing-proposal", "validation-testing": "testing-validation", "alternate": "alternate-validation"} {
|
||||||
|
profile := fmt.Sprintf("id: %s\nbackend: local\nmodel: %s\ntimeout_seconds: 5\n", name, model)
|
||||||
|
if err := os.WriteFile(filepath.Join(dir, "profiles", name+".yaml"), []byte(profile), 0600); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(filepath.Join(dir, "overlays", "testing.yml"), []byte("llm:\n proposal_profile: proposal-testing\n validation_profile: validation-testing\n"), 0600); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
configPath := filepath.Join(dir, "config.yml")
|
||||||
|
configText := fmt.Sprintf("version: 2\nbackends:\n local:\n endpoint: %s/v1\n credential: AUDITA_TEST_PROVIDER_KEY\n concurrency: 2\nllm:\n proposal_profile: proposal\n validation_profile: validation\n transient_retries: 0\n repair_attempts: 1\npipeline:\n modules: %s\ndiagnostics:\n work_dir: %s\n retention: always\n", server.URL, modules, filepath.Join(dir, "runs"))
|
||||||
|
if err := os.WriteFile(configPath, []byte(configText), 0600); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
transcriptPath := filepath.Join(dir, "transcript.json")
|
||||||
|
if err := os.WriteFile(transcriptPath, []byte(`[{"id":1,"speaker":"A","start":0,"end":1,"text":"hello world"}]`), 0600); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
glossaryPath := filepath.Join(dir, "glossary.yaml")
|
||||||
|
if err := os.WriteFile(glossaryPath, []byte("glossary:\n - name: Example\n category: product\n summary: A sample.\n"), 0600); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return processFixture{dir: dir, config: configPath, transcript: transcriptPath, glossary: glossaryPath, report: filepath.Join(dir, "report.json"), output: filepath.Join(dir, "output.json"), provider: p, server: server}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f processFixture) run(t *testing.T, extra ...string) (int, string, string, reporting.ProcessReport) {
|
||||||
|
t.Helper()
|
||||||
|
args := []string{"-test.run=^TestProcessSubprocessHelper$", "--", "process", f.transcript, "--config", f.config, "--glossary", f.glossary, "--report-json", f.report, "--output", f.output}
|
||||||
|
args = append(args, extra...)
|
||||||
|
cmd := exec.Command(os.Args[0], args...)
|
||||||
|
cmd.Env = append(os.Environ(), "AUDITA_HELPER_PROCESS=1", "AUDITA_TEST_PROVIDER_KEY="+f.provider.secret)
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
cmd.Stdout, cmd.Stderr = &stdout, &stderr
|
||||||
|
err := cmd.Run()
|
||||||
|
code := 0
|
||||||
|
if err != nil {
|
||||||
|
if exit, ok := err.(*exec.ExitError); ok {
|
||||||
|
code = exit.ExitCode()
|
||||||
|
} else {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
raw, err := os.ReadFile(f.report)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("report missing: %v, stderr=%s", err, stderr.String())
|
||||||
|
}
|
||||||
|
var report reporting.ProcessReport
|
||||||
|
if err := json.Unmarshal(raw, &report); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return code, stdout.String(), stderr.String(), report
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f processFixture) calls() []outboundCall {
|
||||||
|
f.provider.mu.Lock()
|
||||||
|
defer f.provider.mu.Unlock()
|
||||||
|
return append([]outboundCall(nil), f.provider.calls...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSubprocessSelectionAndRepair(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
extra []string
|
||||||
|
proposal, validation string
|
||||||
|
}{
|
||||||
|
{"base", nil, "base-proposal", "base-validation"},
|
||||||
|
{"overlay and explicit validation", []string{"--overlay", "testing", "--validation-profile", "alternate", "--grammar-confidence-threshold", "0.9"}, "testing-proposal", "alternate-validation"},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
f := newProcessFixture(t, "repair", "[grammar]")
|
||||||
|
code, stdout, stderr, report := f.run(t, tc.extra...)
|
||||||
|
if code != 0 || stdout != "" || stderr != "" || report.Status != "success" {
|
||||||
|
t.Fatalf("code=%d stdout=%q stderr=%q report=%+v", code, stdout, stderr, report)
|
||||||
|
}
|
||||||
|
raw, err := os.ReadFile(f.output)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !bytes.Contains(raw, []byte("Hello world")) {
|
||||||
|
t.Fatalf("correction missing: %s", raw)
|
||||||
|
}
|
||||||
|
calls := f.calls()
|
||||||
|
if len(calls) < 3 || calls[0].Model != tc.proposal || calls[1].Model != tc.proposal {
|
||||||
|
t.Fatalf("proposal models: %+v", calls)
|
||||||
|
}
|
||||||
|
for _, call := range calls[2:] {
|
||||||
|
if !call.Validation || call.Model != tc.validation {
|
||||||
|
t.Fatalf("validation model: %+v", calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if report.LLMSummary == nil || report.LLMSummary.StructuralRepairs != 1 || report.LLMSummary.ProviderAttempts != uint64(len(calls)) {
|
||||||
|
t.Fatalf("LLM summary: %+v", report.LLMSummary)
|
||||||
|
}
|
||||||
|
if report.Diagnostics == nil || report.Diagnostics.LLMExecutionPath == "" || report.Diagnostics.SelectedProfilesPath == "" {
|
||||||
|
t.Fatalf("paths: %+v", report.Diagnostics)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSubprocessWarningEmptyRepeatedAndFailure(t *testing.T) {
|
||||||
|
t.Run("domain rejection", func(t *testing.T) {
|
||||||
|
f := newProcessFixture(t, "low-confidence", "[grammar]")
|
||||||
|
code, _, stderr, report := f.run(t)
|
||||||
|
if code != 0 || stderr != "" || report.Status != "success" || len(report.ModuleResults) != 1 || len(report.ModuleResults[0].ValidatorRejected) == 0 {
|
||||||
|
t.Fatalf("domain rejection: %d %q %+v", code, stderr, report)
|
||||||
|
}
|
||||||
|
if len(f.calls()) != 1 {
|
||||||
|
t.Fatalf("semantic rejection retried: %+v", f.calls())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("warning", func(t *testing.T) {
|
||||||
|
f := newProcessFixture(t, "warning", "[grammar]")
|
||||||
|
code, _, stderr, report := f.run(t)
|
||||||
|
if code != 0 || stderr != "" || report.Status != "success" || len(report.ModuleResults) != 1 || len(report.ModuleResults[0].Warnings) == 0 {
|
||||||
|
t.Fatalf("warning result: %d %q %+v", code, stderr, report)
|
||||||
|
}
|
||||||
|
if len(f.calls()) != 2 || report.LLMSummary == nil || report.LLMSummary.StructuralRepairs != 1 {
|
||||||
|
t.Fatalf("warning observations: %+v %+v", f.calls(), report.LLMSummary)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("empty", func(t *testing.T) {
|
||||||
|
f := newProcessFixture(t, "noop", "[]")
|
||||||
|
code, _, stderr, report := f.run(t)
|
||||||
|
if code != 0 || stderr != "" || len(f.calls()) != 0 || report.LLMSummary == nil || !report.LLMSummary.Usage.Total.Known || !report.LLMSummary.Usage.Total.Complete {
|
||||||
|
t.Fatalf("empty result: %d %q %+v", code, stderr, report.LLMSummary)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("repeated", func(t *testing.T) {
|
||||||
|
f := newProcessFixture(t, "noop", "[grammar, grammar]")
|
||||||
|
code, _, stderr, report := f.run(t)
|
||||||
|
if code != 0 || stderr != "" || len(report.ModuleResults) != 2 || report.ModuleResults[0].ModuleInstance == report.ModuleResults[1].ModuleInstance || len(f.calls()) != 2 {
|
||||||
|
t.Fatalf("repeated result: %d %q %+v %+v", code, stderr, report.ModuleResults, f.calls())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("failure redaction", func(t *testing.T) {
|
||||||
|
f := newProcessFixture(t, "failure", "[grammar]")
|
||||||
|
code, stdout, stderr, report := f.run(t)
|
||||||
|
if code != 1 || stdout != "" || report.Status != "failed" || report.ErrorPhase != "runner_execution" || report.LLMSummary == nil || report.LLMSummary.LogicalCalls != 1 {
|
||||||
|
t.Fatalf("failure result: %d %q %q %+v", code, stdout, stderr, report)
|
||||||
|
}
|
||||||
|
if strings.Contains(stderr, f.provider.secret) {
|
||||||
|
t.Fatal("secret in stderr")
|
||||||
|
}
|
||||||
|
for _, path := range []string{f.report, report.Diagnostics.DirectoryPath} {
|
||||||
|
_ = filepath.Walk(path, func(name string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
content, err := os.ReadFile(name)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if bytes.Contains(content, []byte(f.provider.secret)) {
|
||||||
|
t.Fatalf("secret in %s", name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(report.Diagnostics.LLMExecutionPath); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ the [CLI](../cli.md#streams-and-exit-status).
|
|||||||
|
|
||||||
## Corrected Transcript
|
## Corrected Transcript
|
||||||
|
|
||||||
The [output setting](../config.md#pipeline-and-output) selects the envelope:
|
The [output setting](../config.md#settings) selects the envelope:
|
||||||
|
|
||||||
| Encoder | JSON shape |
|
| Encoder | JSON shape |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ The top-level object contains a `glossary` list with at least one entry.
|
|||||||
|
|
||||||
The parser checks empty strings without trimming them. Unknown YAML fields are
|
The parser checks empty strings without trimming them. Unknown YAML fields are
|
||||||
ignored by the glossary parser, unlike the stricter
|
ignored by the glossary parser, unlike the stricter
|
||||||
[configuration-file schema](../config.md#file-schema).
|
[configuration-file schema](../config.md#loading-and-precedence).
|
||||||
|
|
||||||
The [tiny glossary](../../examples/tiny-glossary.yaml) is a complete copyable input.
|
The [tiny glossary](../../examples/tiny-glossary.yaml) is a complete copyable input.
|
||||||
Malformed YAML, an empty/missing glossary, invalid shapes, missing required text,
|
Malformed YAML, an empty/missing glossary, invalid shapes, missing required text,
|
||||||
|
|||||||
@@ -75,5 +75,4 @@ Operational handling of transcript-bearing artifacts belongs to
|
|||||||
- `internal/core/diagnostics/*_test.go`
|
- `internal/core/diagnostics/*_test.go`
|
||||||
- `internal/framework/processreport/*_test.go`
|
- `internal/framework/processreport/*_test.go`
|
||||||
- `internal/core/reporting/report_test.go`
|
- `internal/core/reporting/report_test.go`
|
||||||
- `internal/cli/run_test.go`
|
|
||||||
- `cmd/audita/main_integration_test.go`
|
- `cmd/audita/main_integration_test.go`
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
## Scope
|
## Scope
|
||||||
|
|
||||||
This document covers internal module contracts and packages. User-selectable keys
|
This document covers internal module contracts and packages. User-selectable keys
|
||||||
and the default sequence belong to [configuration](../config.md#pipeline-and-output).
|
and the default sequence belong to [configuration](../config.md#settings).
|
||||||
|
|
||||||
## Module Contract
|
## Module Contract
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
JSON envelopes and segment fields are defined by the
|
JSON envelopes and segment fields are defined by the
|
||||||
[output-file contract](../integrations/output-files.md#corrected-transcript);
|
[output-file contract](../integrations/output-files.md#corrected-transcript);
|
||||||
selectable values and defaults belong to
|
selectable values and defaults belong to
|
||||||
[configuration](../config.md#pipeline-and-output).
|
[configuration](../config.md#settings).
|
||||||
|
|
||||||
## Resolution and Encoding
|
## Resolution and Encoding
|
||||||
|
|
||||||
|
|||||||
@@ -63,5 +63,4 @@ reports are derived from actual run results. Global requirements are owned by th
|
|||||||
|
|
||||||
- `internal/framework/runner/runner_test.go`
|
- `internal/framework/runner/runner_test.go`
|
||||||
- `internal/framework/proposal_generation/*_test.go`
|
- `internal/framework/proposal_generation/*_test.go`
|
||||||
- `internal/cli/run_test.go`
|
|
||||||
- `cmd/audita/main_integration_test.go`
|
- `cmd/audita/main_integration_test.go`
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
This document describes internal validator composition, execution order, and
|
This document describes internal validator composition, execution order, and
|
||||||
decision handling. These registry keys identify implementation components; they
|
decision handling. These registry keys identify implementation components; they
|
||||||
are not independently selectable through [configuration](../config.md#pipeline-and-output).
|
are not independently selectable through [configuration](../config.md#settings).
|
||||||
|
|
||||||
## Ownership
|
## Ownership
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ output files elsewhere.
|
|||||||
|
|
||||||
## Diagnostics Directory
|
## Diagnostics Directory
|
||||||
|
|
||||||
The [diagnostics configuration](config.md#thresholds-context-and-diagnostics)
|
The [diagnostics configuration](config.md#settings)
|
||||||
selects the parent work directory. Runs create children named like
|
selects the parent work directory. Runs create children named like
|
||||||
`run-<unix-nanoseconds>`. The runtime creates the work directory if needed.
|
`run-<unix-nanoseconds>`. The runtime creates the work directory if needed.
|
||||||
Report paths may be relative when the supplied work directory is relative;
|
Report paths may be relative when the supplied work directory is relative;
|
||||||
@@ -68,7 +68,7 @@ write succeeded or that the files still exist after retention.
|
|||||||
|
|
||||||
## Retention Behavior
|
## Retention Behavior
|
||||||
|
|
||||||
[Configuration](config.md#thresholds-context-and-diagnostics) owns accepted
|
[Configuration](config.md#settings) owns accepted
|
||||||
retention values and the default. Current lifecycle behavior is:
|
retention values and the default. Current lifecycle behavior is:
|
||||||
|
|
||||||
| Run outcome / selection | Directory outcome |
|
| Run outcome / selection | Directory outcome |
|
||||||
@@ -89,10 +89,10 @@ Run artifacts can contain full transcripts, glossary-related context, and LLM
|
|||||||
prompts/responses. Configured-key redaction does not anonymize those contents.
|
prompts/responses. Configured-key redaction does not anonymize those contents.
|
||||||
Choose a work directory whose ownership and permissions fit the transcript data,
|
Choose a work directory whose ownership and permissions fit the transcript data,
|
||||||
and retain or share artifacts intentionally. Credential-supply mechanisms are
|
and retain or share artifacts intentionally. Credential-supply mechanisms are
|
||||||
owned by [configuration](config.md#secrets).
|
owned by [configuration](config.md#credentials).
|
||||||
|
|
||||||
For a debugging run, select retained diagnostics using the
|
For a debugging run, select retained diagnostics using the
|
||||||
[retention flag](cli.md#process-flag-reference). Copy needed artifacts before
|
[retention flag](cli.md#setting-overrides). Copy needed artifacts before
|
||||||
removing completed run directories manually. Avoid deleting a directory while
|
removing completed run directories manually. Avoid deleting a directory while
|
||||||
its run is active. Audita does not provide a separate archival/backup or remote
|
its run is active. Audita does not provide a separate archival/backup or remote
|
||||||
artifact storage facility.
|
artifact storage facility.
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
**Last updated:** 2026-09-24
|
**Last updated:** 2026-09-24
|
||||||
|
|
||||||
**Status:** Final target selected; production implementation pending. The boundary
|
**Status:** Production implementation complete. The selected configuration and
|
||||||
and selected overlays are verified. The [implementation plan](implementation.md)
|
overlay model is implemented; [implementation evidence](implementation.md)
|
||||||
owns execution stages; no production migration or release has begun.
|
records verification. No release has been published.
|
||||||
|
|
||||||
## Purpose and Direction
|
## Purpose and Direction
|
||||||
|
|
||||||
@@ -20,15 +20,14 @@ guide instead of legacy loaders, aliases, dual operating modes, or an ongoing
|
|||||||
compatibility layer. Retain existing syntax only when it independently suits the
|
compatibility layer. Retain existing syntax only when it independently suits the
|
||||||
new model, not because compatibility requires it.
|
new model, not because compatibility requires it.
|
||||||
|
|
||||||
The initial review and prototype used ConfigKit v0.3.1. The prototype now pins
|
The initial review and prototype used ConfigKit v0.3.1, then verified v0.4.0
|
||||||
v0.4.0 and verifies its selected-overlay path; original v0.3.1 findings remain
|
selected overlays. Those findings remain historical; the prototype was removed
|
||||||
historical. The installed
|
after production integration. The application depends on a versioned module,
|
||||||
application must depend on a versioned module, not a sibling checkout or local
|
without a sibling checkout or local module replacement.
|
||||||
module replacement.
|
|
||||||
|
|
||||||
The shared boundary/prototype unit is complete. Its [selected contract, inventory,
|
The shared boundary/prototype unit is complete. Its [selected contract, inventory,
|
||||||
and evidence](library-boundary-findings.md) define the detailed target alongside
|
and evidence](library-boundary-findings.md) define the detailed target alongside
|
||||||
this roadmap. Production configuration migration has not begun.
|
this roadmap. Production configuration migration is complete.
|
||||||
|
|
||||||
## Target End State
|
## Target End State
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
**Last updated:** 2026-09-24
|
**Last updated:** 2026-09-24
|
||||||
|
|
||||||
**Status:** Ready for implementation. All stages below are pending. This replaces
|
**Status:** Implemented. All twelve stages are complete. This replaced
|
||||||
the completed testing-overlay prototype plan; its results remain in the
|
the completed testing-overlay prototype plan; its results remain in the
|
||||||
[boundary findings](library-boundary-findings.md#selected-overlay-extension-2026-09-24).
|
[boundary findings](library-boundary-findings.md#selected-overlay-extension-2026-09-24).
|
||||||
|
|
||||||
@@ -583,7 +583,21 @@ belongs to Stage 12.
|
|||||||
|
|
||||||
## Stage 12: Verify the Combined Application and Close the Refactor
|
## Stage 12: Verify the Combined Application and Close the Refactor
|
||||||
|
|
||||||
**Status:** Pending. **Depends on:** Stages 1–11.
|
**Status:** Complete. Controlled HTTP subprocess tests passed for base and testing
|
||||||
|
overlay selection, explicit validation-profile and domain overrides, both outbound
|
||||||
|
models, accepted repair, domain rejection without semantic retry, warning-only
|
||||||
|
repair exhaustion, empty and repeated module pipelines, and safe partial failure
|
||||||
|
diagnostics. `go test ./...`, `go build -o ./bin/audita ./cmd/audita`, focused
|
||||||
|
race tests for runtime/runner/subprocess code, and both Linux release builds
|
||||||
|
passed. The full suite also passed under Go 1.25.5 with offline module access.
|
||||||
|
Maintained examples and local documentation links validated; `git diff --check`
|
||||||
|
passed. No native macOS or live provider call was run. Release preparation remains
|
||||||
|
separate: propose Audita v2.0.0 with [one migration guide](../migrations/v2.md),
|
||||||
|
the actual pinned production dependency/license inventory, and LGPL
|
||||||
|
notice/source/rebuild-distribution review before publication. No release was
|
||||||
|
published here.
|
||||||
|
|
||||||
|
**Depends on:** Stages 1–11.
|
||||||
**Owns:** final integration tests, final defect fixes within this scope, and status/evidence.
|
**Owns:** final integration tests, final defect fixes within this scope, and status/evidence.
|
||||||
|
|
||||||
1. Complete representative production subprocess workflows against controlled HTTP:
|
1. Complete representative production subprocess workflows against controlled HTTP:
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
**Last updated:** 2026-09-24
|
**Last updated:** 2026-09-24
|
||||||
|
|
||||||
**Status:** Final target selected; production implementation pending. The shared
|
**Status:** Production implementation complete. ConfigKit v0.4.0 and PromptKit
|
||||||
boundary and offline prototype, including ConfigKit v0.4.0 overlays, are verified.
|
v0.11.0 are adopted; [implementation evidence](implementation.md) records the
|
||||||
[Implementation stages](implementation.md) are owned by the implementation plan.
|
completed checks. Release compliance and publication remain separate work.
|
||||||
This roadmap defines the end state and user intent; it authorizes no publication.
|
|
||||||
|
|
||||||
## Goal and Ownership
|
## Goal and Ownership
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user