Add output schema registry and public contract docs

This commit is contained in:
2026-05-13 12:59:10 +00:00
parent 9a77a0cd0b
commit 1bc5936681
21 changed files with 791 additions and 24 deletions

View File

@@ -57,6 +57,7 @@ func TestRunProcessHelpListsExpectedFlags(t *testing.T) {
"--config",
"--glossary",
"--output",
"--output-schema",
"--report-json",
"--modules",
"--llm-api-key",
@@ -1158,6 +1159,16 @@ func TestRunProcessReportJSONSuccessIncludesNormalizationSummary(t *testing.T) {
if report.Status != "success" {
t.Fatalf("expected success status, got %q", report.Status)
}
if report.ReportMetadata.ReportSchemaName != reporting.DefaultProcessReportSchemaName ||
report.ReportMetadata.ReportSchemaVersion != reporting.DefaultProcessReportSchemaVersion {
t.Fatalf("unexpected report schema metadata: %+v", report.ReportMetadata)
}
if report.ReportMetadata.OutputSchema != "bare-segments" {
t.Fatalf("expected bare-segments output schema metadata, got %q", report.ReportMetadata.OutputSchema)
}
if report.ReportMetadata.ConfigVersion != nil {
t.Fatalf("expected nil config version without config file, got %v", *report.ReportMetadata.ConfigVersion)
}
if report.Operation != "process" {
t.Fatalf("expected operation process, got %q", report.Operation)
}
@@ -1291,12 +1302,65 @@ func TestRunProcessReportJSONAndRunDirReportShareDiagnosticsMetadata(t *testing.
if externalReport.Diagnostics == nil || runDirReport.Diagnostics == nil {
t.Fatalf("expected diagnostics metadata in both reports")
}
if externalReport.ReportMetadata != runDirReport.ReportMetadata {
t.Fatalf("expected same report metadata in --report-json and run-dir report\nexternal=%+v\nrun-dir=%+v",
externalReport.ReportMetadata, runDirReport.ReportMetadata)
}
if *externalReport.Diagnostics != *runDirReport.Diagnostics {
t.Fatalf("expected same diagnostics metadata in --report-json and run-dir report\nexternal=%+v\nrun-dir=%+v",
*externalReport.Diagnostics, *runDirReport.Diagnostics)
}
}
func TestRunProcessReportJSONIncludesConfigVersionWhenConfigFileUsed(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
workDir := t.TempDir()
reportPath := filepath.Join(t.TempDir(), "report.json")
cfgPath := writeFile(t, "config.yml", "version: 1\noutput:\n schema: audita-v1\n")
exitCode := Run([]string{
"process",
fixturePath("tiny_transcript.json"),
"--glossary",
fixturePath("tiny_glossary.yaml"),
"--config",
cfgPath,
"--report-json",
reportPath,
"--work-dir",
workDir,
"--work-dir-retention",
"always",
}, &stdout, &stderr)
if exitCode != 0 {
t.Fatalf("expected exit code 0, got %d with stderr %q", exitCode, stderr.String())
}
report := readProcessReport(t, reportPath)
if report.ReportMetadata.ConfigVersion == nil || *report.ReportMetadata.ConfigVersion != 1 {
t.Fatalf("expected config version 1 in report metadata, got %+v", report.ReportMetadata)
}
if report.ReportMetadata.OutputSchema != "audita-v1" {
t.Fatalf("expected output schema from config in report metadata, got %q", report.ReportMetadata.OutputSchema)
}
runDirReport := readProcessReport(t, filepath.Join(onlyRunDir(t, workDir), "report.json"))
if runDirReport.ReportMetadata.ReportSchemaName != report.ReportMetadata.ReportSchemaName ||
runDirReport.ReportMetadata.ReportSchemaVersion != report.ReportMetadata.ReportSchemaVersion ||
runDirReport.ReportMetadata.OutputSchema != report.ReportMetadata.OutputSchema {
t.Fatalf("expected same report metadata in run-dir report, got external=%+v run-dir=%+v",
report.ReportMetadata, runDirReport.ReportMetadata)
}
if runDirReport.ReportMetadata.ConfigVersion == nil ||
report.ReportMetadata.ConfigVersion == nil ||
*runDirReport.ReportMetadata.ConfigVersion != *report.ReportMetadata.ConfigVersion {
t.Fatalf("expected same config version in run-dir report metadata, got external=%+v run-dir=%+v",
report.ReportMetadata, runDirReport.ReportMetadata)
}
}
func TestRunProcessWritesNormalizationDiagnosticsArtifacts(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
@@ -3859,6 +3923,148 @@ func TestRunProcessReportJSONNotPrintedToStdout(t *testing.T) {
}
}
func TestRunProcessDefaultOutputMatchesBareSegmentsSchema(t *testing.T) {
var stdoutDefault, stderrDefault bytes.Buffer
var stdoutBare, stderrBare bytes.Buffer
transcriptPath := fixturePath("tiny_transcript.json")
glossaryPath := fixturePath("tiny_glossary.yaml")
exitDefault := Run([]string{"process", transcriptPath, "--glossary", glossaryPath}, &stdoutDefault, &stderrDefault)
if exitDefault != 0 {
t.Fatalf("default run failed: %d stderr=%q", exitDefault, stderrDefault.String())
}
exitBare := Run([]string{"process", transcriptPath, "--glossary", glossaryPath, "--output-schema", "bare-segments"}, &stdoutBare, &stderrBare)
if exitBare != 0 {
t.Fatalf("bare-segments run failed: %d stderr=%q", exitBare, stderrBare.String())
}
if stdoutDefault.String() != stdoutBare.String() {
t.Fatalf("expected default output to match bare-segments output")
}
}
func TestRunProcessOutputSchemaAuditaV1ToStdout(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
exitCode := Run([]string{
"process",
fixturePath("tiny_transcript.json"),
"--glossary", fixturePath("tiny_glossary.yaml"),
"--output-schema", "audita-v1",
}, &stdout, &stderr)
if exitCode != 0 {
t.Fatalf("expected success, got %d stderr=%q", exitCode, stderr.String())
}
var out struct {
Schema string `json:"schema"`
Version string `json:"version"`
Segments []schema.Segment `json:"segments"`
}
if err := json.Unmarshal(stdout.Bytes(), &out); err != nil {
t.Fatalf("expected audita-v1 JSON object output: %v", err)
}
if out.Schema != "audita-v1" || out.Version != "v1" {
t.Fatalf("unexpected schema metadata: schema=%q version=%q", out.Schema, out.Version)
}
if len(out.Segments) == 0 {
t.Fatalf("expected non-empty segments in audita-v1 output")
}
}
func TestRunProcessOutputSchemaAuditaV1ToFile(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
outputPath := filepath.Join(t.TempDir(), "out.json")
exitCode := Run([]string{
"process",
fixturePath("tiny_transcript.json"),
"--glossary", fixturePath("tiny_glossary.yaml"),
"--output-schema", "audita-v1",
"--output", outputPath,
}, &stdout, &stderr)
if exitCode != 0 {
t.Fatalf("expected success, got %d stderr=%q", exitCode, stderr.String())
}
if stdout.Len() != 0 {
t.Fatalf("expected empty stdout with --output, got %q", stdout.String())
}
var out map[string]any
if err := json.Unmarshal(readFile(t, outputPath), &out); err != nil {
t.Fatalf("expected valid audita-v1 JSON file: %v", err)
}
if out["schema"] != "audita-v1" {
t.Fatalf("expected audita-v1 schema in file output, got %#v", out["schema"])
}
}
func TestRunProcessOutputSchemaFromConfig(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
cfgPath := writeFile(t, "config.yml", "version: 1\noutput:\n schema: audita-v1\n")
exitCode := Run([]string{
"process",
fixturePath("tiny_transcript.json"),
"--glossary", fixturePath("tiny_glossary.yaml"),
"--config", cfgPath,
}, &stdout, &stderr)
if exitCode != 0 {
t.Fatalf("expected success, got %d stderr=%q", exitCode, stderr.String())
}
var out map[string]any
if err := json.Unmarshal(stdout.Bytes(), &out); err != nil {
t.Fatalf("expected audita-v1 object from config output schema: %v", err)
}
if out["schema"] != "audita-v1" {
t.Fatalf("expected audita-v1 schema from config output, got %#v", out["schema"])
}
}
func TestRunProcessCLIOutputSchemaOverridesConfig(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
cfgPath := writeFile(t, "config.yml", "version: 1\noutput:\n schema: audita-v1\n")
exitCode := Run([]string{
"process",
fixturePath("tiny_transcript.json"),
"--glossary", fixturePath("tiny_glossary.yaml"),
"--config", cfgPath,
"--output-schema", "bare-segments",
}, &stdout, &stderr)
if exitCode != 0 {
t.Fatalf("expected success, got %d stderr=%q", exitCode, stderr.String())
}
if strings.HasPrefix(strings.TrimSpace(stdout.String()), "{") {
t.Fatalf("expected bare-segments array output from CLI override, got object")
}
}
func TestRunProcessUnknownOutputSchemaFailsClearly(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
exitCode := Run([]string{
"process",
fixturePath("tiny_transcript.json"),
"--glossary", fixturePath("tiny_glossary.yaml"),
"--output-schema", "seriatim-intermediate",
}, &stdout, &stderr)
if exitCode == 0 {
t.Fatalf("expected failure for unknown output schema")
}
if stdout.Len() != 0 {
t.Fatalf("expected empty stdout on failure, got %q", stdout.String())
}
if !strings.Contains(stderr.String(), "unsupported output schema") {
t.Fatalf("expected unsupported output schema error, got %q", stderr.String())
}
}
func fixturePath(name string) string {
return filepath.Join("testdata", name)
}