diff --git a/AGENTS.md b/AGENTS.md index 73f6c1f4..fd0100cf 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -344,7 +344,7 @@ proves natural-language understanding. Semantic selection is an explicit opt-in live-model check. Run the smoke set (one positive and one negative scenario per product) with -`DWS_AGENT_SELECTION_LIVE=1 ARK_API_KEY=... ARK_BASE_URL=... ARK_MODEL=... go test ./internal/app -run TestManualAgentSelectionArkLive -count=1`. +`DWS_AGENT_SELECTION_LIVE=1 ARK_API_KEY=... ARK_BASE_URL=... ARK_MODEL=... go test ./internal/app -run TestAgentSelectionArkLive -count=1`. Add `DWS_AGENT_SELECTION_FULL=1` to evaluate every committed tool scenario, or set `DWS_AGENT_SELECTION_CASES` to comma-separated fixture case IDs. Normal CI never calls a model; its blockers remain the reproducible fixture, binding, diff --git a/Makefile b/Makefile index 7cab8634..82cf7310 100644 --- a/Makefile +++ b/Makefile @@ -134,7 +134,7 @@ mock-mcp-smoke: $(GO) test -v -count=1 -run '^(TestHTTPClientEndToEnd|TestStdioClientEndToEnd)$$' ./internal/transport test-schema-agent-examples: - DWS_AGENT_EXAMPLES_DRY_RUN=1 $(GO) test -v -count=1 ./internal/app -run '^TestManualAgentExamplesDryRun$$' + DWS_AGENT_EXAMPLES_DRY_RUN=1 $(GO) test -v -count=1 ./internal/app -run '^TestAgentExamplesDryRun$$' # generate-schema refreshes param_aliases_generated.go and verifies that # ResolveSchemaBuild assembly is deterministic. Catalog is runtime-assembled diff --git a/internal/app/schema_agent_examples_dry_run_test.go b/internal/app/schema_agent_examples_dry_run_test.go index 394a8249..dec8f1c2 100644 --- a/internal/app/schema_agent_examples_dry_run_test.go +++ b/internal/app/schema_agent_examples_dry_run_test.go @@ -34,35 +34,35 @@ import ( ) var ( - manualAgentExamplePlaceholderPattern = regexp.MustCompile(`<([^>]+)>`) - manualAgentExampleDryRunJSONPattern = regexp.MustCompile(`(?i)"dry_run"\s*:\s*true`) - manualAgentExampleDryRunPlanPattern = regexp.MustCompile(`(?i)"preview_kind"\s*:\s*"plan"`) - // manualAgentExampleDryRunInvocationPattern recognizes the executor + agentExamplePlaceholderPattern = regexp.MustCompile(`<([^>]+)>`) + agentExampleDryRunJSONPattern = regexp.MustCompile(`(?i)"dry_run"\s*:\s*true`) + agentExampleDryRunPlanPattern = regexp.MustCompile(`(?i)"preview_kind"\s*:\s*"plan"`) + // agentExampleDryRunInvocationPattern recognizes the executor // envelope (and the dev connect preview, which mirrors its shape): the // top-level contract is an invocation that merely embeds the would-be // request inside response, so it must classify as invocation, not request. - manualAgentExampleDryRunInvocationPattern = regexp.MustCompile( + agentExampleDryRunInvocationPattern = regexp.MustCompile( `"kind"\s*:\s*"(?:(?:helper|compat|workflow)_invocation|connect_preview)"`) ) -// TestManualAgentExamplesContract is the always-on gate. It validates every +// TestAgentExamplesContract is the always-on gate. It validates every // example, including contract_only entries, against the live bound Cobra path, // flags, required arguments, constraints, and final typed safety. -func TestManualAgentExamplesContract(t *testing.T) { - plan := manualAgentExampleExecutionPlan(t) +func TestAgentExamplesContract(t *testing.T) { + plan := agentExampleExecutionPlan(t) if plan.Total == 0 { t.Fatal("no reviewed Agent examples were contract validated") } t.Logf("Agent example contract: total=%d contract=%d dry_run=%d contract_only=%d", plan.Total, plan.Contract, plan.DryRun, plan.ContractOnly) } -// TestManualAgentExamplesDryRun first validates every reviewed example against +// TestAgentExamplesDryRun first validates every reviewed example against // its real BoundCommand, Cobra required arguments, and final typed constraints. // It then executes only the deterministic, explicitly declared dry_run subset // without injecting --yes. Global flag inheritance is not treated as capability // evidence. Runtime failures never create implicit skips. No shell is involved // and HOME is isolated. -func TestManualAgentExamplesDryRun(t *testing.T) { +func TestAgentExamplesDryRun(t *testing.T) { if os.Getenv("DWS_AGENT_EXAMPLES_DRY_RUN") != "1" { t.Skip("set DWS_AGENT_EXAMPLES_DRY_RUN=1 to execute the explicitly reviewed Agent dry-run subset") } @@ -81,45 +81,45 @@ func TestManualAgentExamplesDryRun(t *testing.T) { t.Setenv("HTTPS_PROXY", "http://127.0.0.1:1") t.Setenv("NO_PROXY", "") - plan := manualAgentExampleExecutionPlan(t) + plan := agentExampleExecutionPlan(t) if plan.Total == 0 { t.Fatal("no reviewed Agent examples were contract validated") } t.Chdir(sandboxRoot) - files := newManualAgentExampleFiles(t, sandboxRoot) + files := newAgentExampleFiles(t, sandboxRoot) selected := 0 executed := 0 for _, execution := range plan.Examples { - if !manualAgentExampleShouldExerciseDryRun(execution) { + if !agentExampleShouldExerciseDryRun(execution) { continue } selected++ execution := execution t.Run(fmt.Sprintf("%s/%d", strings.ReplaceAll(execution.CanonicalPath, ".", "/"), execution.Index), func(t *testing.T) { - argv, err := cli.ParseManualAgentExampleArgv(execution.Example) + argv, err := cli.ParseAgentExampleArgv(execution.Example) if err != nil { t.Fatalf("parse example %q: %v", execution.Example, err) } - args := materializeManualAgentExampleArgv(argv[1:], files) - if manualAgentExampleHasFlag(args, "yes") { + args := materializeAgentExampleArgv(argv[1:], files) + if agentExampleHasFlag(args, "yes") { t.Fatalf("dry-run gate must not inject or accept --yes\nsource: %s\nargv: %q", execution.Example, args) } - if !manualAgentExampleHasFlag(args, "dry-run") { + if !agentExampleHasFlag(args, "dry-run") { args = append([]string{"--dry-run"}, args...) } - capture, err := executeManualAgentExampleCapture(t, args) + capture, err := executeAgentExampleCapture(t, args) if capture.ToolCallAttempts != 0 { t.Fatalf("eligible dry-run attempted %d ToolCaller invocation(s)\nsource: %s\nargv: %q\noutput:\n%s", capture.ToolCallAttempts, execution.Example, args, capture.Output) } - if capture.StdinBytesRead != 0 || manualAgentExamplePromptObserved(capture.Output) { + if capture.StdinBytesRead != 0 || agentExamplePromptObserved(capture.Output) { t.Fatalf("eligible dry-run entered an interactive confirmation path (stdin bytes read: %d)\nsource: %s\nargv: %q\noutput:\n%s", capture.StdinBytesRead, execution.Example, args, capture.Output) } if err != nil { t.Fatalf("dry-run example failed: %v\nsource: %s\nargv: %q\noutput:\n%s", err, execution.Example, args, capture.Output) } - previewKind, observed := manualAgentExampleDryRunEvidence(capture) + previewKind, observed := agentExampleDryRunEvidence(capture) if !observed { t.Fatalf("example returned without audited dry-run evidence (caller dry-run checks: %d)\nsource: %s\nargv: %q\noutput:\n%s", capture.DryRunChecks, execution.Example, args, capture.Output) } @@ -140,18 +140,18 @@ func TestManualAgentExamplesDryRun(t *testing.T) { } sort.Strings(reasonCodes) for _, reasonCode := range reasonCodes { - t.Logf("Agent examples contract_only[%s]=%d", reasonCode, plan.ContractOnlyByReason[cli.ManualAgentExampleReasonCode(reasonCode)]) + t.Logf("Agent examples contract_only[%s]=%d", reasonCode, plan.ContractOnlyByReason[cli.AgentExampleReasonCode(reasonCode)]) } } -// manualAgentExampleShouldExerciseDryRun is the single selection boundary for +// agentExampleShouldExerciseDryRun is the single selection boundary for // the runtime gate. Capability comes only from the final typed ToolSpec; the // example disposition may narrow that set but can never invent support. -func manualAgentExampleShouldExerciseDryRun(execution cli.ManualAgentExampleExecution) bool { - return execution.DryRun != nil && execution.Mode == cli.ManualAgentExampleModeDryRun +func agentExampleShouldExerciseDryRun(execution cli.AgentExampleExecution) bool { + return execution.DryRun != nil && execution.Mode == cli.AgentExampleModeDryRun } -func manualAgentExampleExecutionPlan(t testing.TB) cli.ManualAgentExampleExecutionPlan { +func agentExampleExecutionPlan(t testing.TB) cli.AgentExampleExecutionPlan { t.Helper() contractRoot := NewRootCommand() effective, err := cli.BuildEffectiveCommandRegistry(contractRoot) @@ -171,39 +171,39 @@ func manualAgentExampleExecutionPlan(t testing.TB) cli.ManualAgentExampleExecuti } plan, err := cli.BuildAgentExampleExecutionPlan(bound, registry) if err != nil { - t.Fatalf("BuildManualAgentExampleExecutionPlan() error = %v", err) + t.Fatalf("BuildAgentExampleExecutionPlan() error = %v", err) } return plan } -type manualAgentExampleCapture struct { +type agentExampleCapture struct { Output string DryRunChecks int64 ToolCallAttempts int64 StdinBytesRead int64 } -type manualAgentExampleFailClosedCaller struct { +type agentExampleFailClosedCaller struct { dryRunChecks atomic.Int64 toolCallAttempts atomic.Int64 } -func (c *manualAgentExampleFailClosedCaller) CallTool(_ context.Context, productID, toolName string, _ map[string]any) (*edition.ToolResult, error) { +func (c *agentExampleFailClosedCaller) CallTool(_ context.Context, productID, toolName string, _ map[string]any) (*edition.ToolResult, error) { c.toolCallAttempts.Add(1) return nil, fmt.Errorf("real ToolCaller invocation blocked during Agent example dry-run: %s/%s", productID, toolName) } -func (c *manualAgentExampleFailClosedCaller) Format() string { return "json" } +func (c *agentExampleFailClosedCaller) Format() string { return "json" } -func (c *manualAgentExampleFailClosedCaller) DryRun() bool { +func (c *agentExampleFailClosedCaller) DryRun() bool { c.dryRunChecks.Add(1) return true } -func (c *manualAgentExampleFailClosedCaller) Fields() string { return "" } -func (c *manualAgentExampleFailClosedCaller) JQ() string { return "" } +func (c *agentExampleFailClosedCaller) Fields() string { return "" } +func (c *agentExampleFailClosedCaller) JQ() string { return "" } -func executeManualAgentExampleCapture(t testing.TB, args []string) (manualAgentExampleCapture, error) { +func executeAgentExampleCapture(t testing.TB, args []string) (agentExampleCapture, error) { t.Helper() oldArgs := os.Args os.Args = append([]string{"dws"}, args...) @@ -239,7 +239,7 @@ func executeManualAgentExampleCapture(t testing.TB, args []string) (manualAgentE root := NewRootCommand() originalCaller := helpers.GetCaller() - auditCaller := &manualAgentExampleFailClosedCaller{} + auditCaller := &agentExampleFailClosedCaller{} helpers.InitDeps(auditCaller) defer helpers.InitDeps(originalCaller) var output bytes.Buffer @@ -261,7 +261,7 @@ func executeManualAgentExampleCapture(t testing.TB, args []string) (manualAgentE if err != nil { t.Fatalf("inspect guarded stdin: %v", err) } - return manualAgentExampleCapture{ + return agentExampleCapture{ Output: output.String() + string(captured), DryRunChecks: auditCaller.dryRunChecks.Load(), ToolCallAttempts: auditCaller.toolCallAttempts.Load(), @@ -269,7 +269,7 @@ func executeManualAgentExampleCapture(t testing.TB, args []string) (manualAgentE }, execErr } -type manualAgentExampleFiles struct { +type agentExampleFiles struct { root string markdown string json string @@ -278,7 +278,7 @@ type manualAgentExampleFiles struct { image string } -func newManualAgentExampleFiles(t testing.TB, root string) manualAgentExampleFiles { +func newAgentExampleFiles(t testing.TB, root string) agentExampleFiles { t.Helper() markdown := filepath.Join(root, "content.md") jsonFile := filepath.Join(root, "report.json") @@ -296,13 +296,13 @@ func newManualAgentExampleFiles(t testing.TB, root string) manualAgentExampleFil t.Fatalf("write dry-run fixture %s: %v", path, err) } } - return manualAgentExampleFiles{root: root, markdown: markdown, json: jsonFile, batch: batch, binary: binary, image: image} + return agentExampleFiles{root: root, markdown: markdown, json: jsonFile, batch: batch, binary: binary, image: image} } -func materializeManualAgentExampleArgv(argv []string, files manualAgentExampleFiles) []string { +func materializeAgentExampleArgv(argv []string, files agentExampleFiles) []string { result := append([]string(nil), argv...) for index := range result { - result[index] = manualAgentExamplePlaceholderPattern.ReplaceAllStringFunc(result[index], func(match string) string { + result[index] = agentExamplePlaceholderPattern.ReplaceAllStringFunc(result[index], func(match string) string { name := strings.TrimSuffix(strings.TrimPrefix(match, "<"), ">") switch strings.ToLower(name) { case "basetime", "remindertimestamp", "reminder-time-stamp": @@ -323,7 +323,7 @@ func materializeManualAgentExampleArgv(argv []string, files manualAgentExampleFi } for index := 0; index < len(result); index++ { - name, inline, ok := manualAgentExampleLongFlag(result[index]) + name, inline, ok := agentExampleLongFlag(result[index]) if !ok { continue } @@ -368,7 +368,7 @@ func materializeManualAgentExampleArgv(argv []string, files manualAgentExampleFi return result } -func manualAgentExampleLongFlag(argument string) (name, inline string, ok bool) { +func agentExampleLongFlag(argument string) (name, inline string, ok bool) { if !strings.HasPrefix(argument, "--") { return "", "", false } @@ -376,7 +376,7 @@ func manualAgentExampleLongFlag(argument string) (name, inline string, ok bool) return name, inline, name != "" } -func manualAgentExampleHasFlag(argv []string, target string) bool { +func agentExampleHasFlag(argv []string, target string) bool { for _, argument := range argv { if argument == "--"+target || strings.HasPrefix(argument, "--"+target+"=") { return true @@ -385,20 +385,20 @@ func manualAgentExampleHasFlag(argv []string, target string) bool { return false } -func manualAgentExampleDryRunObserved(capture manualAgentExampleCapture) bool { - _, ok := manualAgentExampleDryRunEvidence(capture) +func agentExampleDryRunObserved(capture agentExampleCapture) bool { + _, ok := agentExampleDryRunEvidence(capture) return ok } -func manualAgentExampleDryRunEvidence(capture manualAgentExampleCapture) (string, bool) { +func agentExampleDryRunEvidence(capture agentExampleCapture) (string, bool) { normalized := strings.ToLower(capture.Output) - if manualAgentExampleDryRunJSONPattern.MatchString(capture.Output) && manualAgentExampleDryRunPlanPattern.MatchString(capture.Output) { + if agentExampleDryRunJSONPattern.MatchString(capture.Output) && agentExampleDryRunPlanPattern.MatchString(capture.Output) { return contract.DryRunPreviewPlan, true } - if manualAgentExampleDryRunJSONPattern.MatchString(capture.Output) && manualAgentExampleDryRunInvocationPattern.MatchString(capture.Output) { + if agentExampleDryRunJSONPattern.MatchString(capture.Output) && agentExampleDryRunInvocationPattern.MatchString(capture.Output) { return contract.DryRunPreviewInvocation, true } - if manualAgentExampleDryRunJSONPattern.MatchString(capture.Output) { + if agentExampleDryRunJSONPattern.MatchString(capture.Output) { return contract.DryRunPreviewRequest, true } if strings.Contains(normalized, "[dry-run]") { @@ -410,11 +410,11 @@ func manualAgentExampleDryRunEvidence(capture manualAgentExampleCapture) (string return "", false } -func TestManualAgentExampleDryRunEvidenceAcceptsSharedAndCommandPlans(t *testing.T) { - if !manualAgentExampleDryRunObserved(manualAgentExampleCapture{Output: "[DRY-RUN] Preview only, not executed:\nTool: calendar_list"}) { +func TestAgentExampleDryRunEvidenceAcceptsSharedAndCommandPlans(t *testing.T) { + if !agentExampleDryRunObserved(agentExampleCapture{Output: "[DRY-RUN] Preview only, not executed:\nTool: calendar_list"}) { t.Fatal("dry-run output with a Tool and nil Arguments was not recognized") } - if manualAgentExampleDryRunObserved(manualAgentExampleCapture{Output: "Tool: calendar_list"}) { + if agentExampleDryRunObserved(agentExampleCapture{Output: "Tool: calendar_list"}) { t.Fatal("a Tool line without dry-run evidence must not be accepted") } for _, falseEvidence := range []string{ @@ -422,28 +422,28 @@ func TestManualAgentExampleDryRunEvidenceAcceptsSharedAndCommandPlans(t *testing "Run again with --dry-run to preview the operation", `{"dry_run":false,"executed":true}`, } { - if manualAgentExampleDryRunObserved(manualAgentExampleCapture{Output: falseEvidence}) { + if agentExampleDryRunObserved(agentExampleCapture{Output: falseEvidence}) { t.Errorf("non-evidence text was mistaken for a successful dry-run: %q", falseEvidence) } } operationSummary := "操作: 下载钉盘文件\n文件ID: test" - if manualAgentExampleDryRunObserved(manualAgentExampleCapture{Output: operationSummary}) { + if agentExampleDryRunObserved(agentExampleCapture{Output: operationSummary}) { t.Fatal("a human-only operation summary without an audited dry-run check must not be accepted") } - if !manualAgentExampleDryRunObserved(manualAgentExampleCapture{Output: operationSummary, DryRunChecks: 1}) { + if !agentExampleDryRunObserved(agentExampleCapture{Output: operationSummary, DryRunChecks: 1}) { t.Fatal("a command plan guarded by the injected caller's dry-run check was not recognized") } } -func TestCrossPlatformCoverageManualAgentExampleDryRunEvidenceClassifiesStructuredPlan(t *testing.T) { - kind, observed := manualAgentExampleDryRunEvidence(manualAgentExampleCapture{ +func TestCrossPlatformCoverageAgentExampleDryRunEvidenceClassifiesStructuredPlan(t *testing.T) { + kind, observed := agentExampleDryRunEvidence(agentExampleCapture{ Output: `{"dry_run":true,"executed":false,"preview_kind":"plan"}`, DryRunChecks: 1, }) if !observed || kind != contract.DryRunPreviewPlan { t.Fatalf("structured plan classified as kind=%q observed=%v", kind, observed) } - if manualAgentExampleDryRunObserved(manualAgentExampleCapture{ + if agentExampleDryRunObserved(agentExampleCapture{ Output: `{"dry_run":false,"executed":false,"preview_kind":"plan"}`, DryRunChecks: 1, }) { @@ -451,7 +451,7 @@ func TestCrossPlatformCoverageManualAgentExampleDryRunEvidenceClassifiesStructur } } -func TestManualAgentExampleDryRunEvidenceClassifiesExecutorEnvelopeAsInvocation(t *testing.T) { +func TestAgentExampleDryRunEvidenceClassifiesExecutorEnvelopeAsInvocation(t *testing.T) { // Executor dry-run envelope: invocation at top level, the would-be request // nested inside response — must classify as invocation, never request. envelope := `{ @@ -460,29 +460,29 @@ func TestManualAgentExampleDryRunEvidenceClassifiesExecutorEnvelopeAsInvocation( "response": {"dry_run": true, "request": {"jsonrpc": "2.0", "method": "tools/call"}, "note": "execution skipped by --dry-run"} }` - kind, observed := manualAgentExampleDryRunEvidence(manualAgentExampleCapture{Output: envelope}) + kind, observed := agentExampleDryRunEvidence(agentExampleCapture{Output: envelope}) if !observed || kind != contract.DryRunPreviewInvocation { t.Fatalf("executor envelope classified as kind=%q observed=%v, want invocation", kind, observed) } for _, invKind := range []string{"compat_invocation", "workflow_invocation", "connect_preview"} { out := strings.Replace(envelope, "helper_invocation", invKind, 1) - if kind, ok := manualAgentExampleDryRunEvidence(manualAgentExampleCapture{Output: out}); !ok || kind != contract.DryRunPreviewInvocation { + if kind, ok := agentExampleDryRunEvidence(agentExampleCapture{Output: out}); !ok || kind != contract.DryRunPreviewInvocation { t.Fatalf("kind %q envelope classified as %q/%v, want invocation", invKind, kind, ok) } } // A bare MCP dry-run document has no invocation kind and stays request. mcpDoc := `{"dry_run": true, "executed": false, "tool": "get_dev_app", "arguments": {}}` - if kind, ok := manualAgentExampleDryRunEvidence(manualAgentExampleCapture{Output: mcpDoc}); !ok || kind != contract.DryRunPreviewRequest { + if kind, ok := agentExampleDryRunEvidence(agentExampleCapture{Output: mcpDoc}); !ok || kind != contract.DryRunPreviewRequest { t.Fatalf("bare MCP dry-run classified as %q/%v, want request", kind, ok) } // Plan still wins over an invocation-shaped payload. planDoc := `{"dry_run": true, "preview_kind": "plan", "kind": "helper_invocation"}` - if kind, ok := manualAgentExampleDryRunEvidence(manualAgentExampleCapture{Output: planDoc}); !ok || kind != contract.DryRunPreviewPlan { + if kind, ok := agentExampleDryRunEvidence(agentExampleCapture{Output: planDoc}); !ok || kind != contract.DryRunPreviewPlan { t.Fatalf("plan precedence broken: %q/%v", kind, ok) } } -func manualAgentExamplePromptObserved(output string) bool { +func agentExamplePromptObserved(output string) bool { normalized := strings.ToLower(output) for _, marker := range []string{ "confirm ", @@ -503,7 +503,7 @@ func manualAgentExamplePromptObserved(output string) bool { return false } -func TestManualAgentExamplePromptObservedRejectsInteractiveConfirmation(t *testing.T) { +func TestAgentExamplePromptObservedRejectsInteractiveConfirmation(t *testing.T) { for _, prompt := range []string{ "Confirm deletion? (yes/no):", "Confirm action? (yes/no):", @@ -514,11 +514,11 @@ func TestManualAgentExamplePromptObservedRejectsInteractiveConfirmation(t *testi "Are you sure you want to continue?", "Operation cancelled", } { - if !manualAgentExamplePromptObserved(prompt) { + if !agentExamplePromptObserved(prompt) { t.Errorf("interactive confirmation output was not detected: %q", prompt) } } - if manualAgentExamplePromptObserved(`{"dry_run":true,"confirmation":"user_required"}`) { + if agentExamplePromptObserved(`{"dry_run":true,"confirmation":"user_required"}`) { t.Fatal("typed safety metadata was mistaken for an interactive prompt") } } @@ -532,26 +532,26 @@ func TestAitableAdvpermDisableDryRunSkipsConfirmationAndToolCall(t *testing.T) { "aitable", "advperm", "disable", "--base-id", "BASE_ID", } - if manualAgentExampleHasFlag(args, "yes") { + if agentExampleHasFlag(args, "yes") { t.Fatal("regression test must not bypass confirmation with --yes") } - capture, err := executeManualAgentExampleCapture(t, args) + capture, err := executeAgentExampleCapture(t, args) if err != nil { t.Fatalf("advperm disable fail-closed dry-run failed: %v\noutput:\n%s", err, capture.Output) } - if capture.StdinBytesRead != 0 || manualAgentExamplePromptObserved(capture.Output) { + if capture.StdinBytesRead != 0 || agentExamplePromptObserved(capture.Output) { t.Fatalf("advperm disable dry-run entered confirmation (stdin bytes read: %d)\noutput:\n%s", capture.StdinBytesRead, capture.Output) } if capture.ToolCallAttempts != 0 { t.Fatalf("advperm disable dry-run attempted %d real ToolCaller invocation(s)\noutput:\n%s", capture.ToolCallAttempts, capture.Output) } - if !manualAgentExampleDryRunObserved(capture) { + if !agentExampleDryRunObserved(capture) { t.Fatalf("advperm disable returned no audited dry-run evidence (caller dry-run checks: %d)\noutput:\n%s", capture.DryRunChecks, capture.Output) } } -func TestManualAgentExampleFailClosedCallerRecordsToolCalls(t *testing.T) { - caller := &manualAgentExampleFailClosedCaller{} +func TestAgentExampleFailClosedCallerRecordsToolCalls(t *testing.T) { + caller := &agentExampleFailClosedCaller{} if !caller.DryRun() { t.Fatal("fail-closed caller must advertise dry-run mode") } @@ -566,7 +566,7 @@ func TestManualAgentExampleFailClosedCallerRecordsToolCalls(t *testing.T) { } } -func TestManualAgentExampleChatGroupMuteMemberUsesCommandDryRunPreview(t *testing.T) { +func TestAgentExampleChatGroupMuteMemberUsesCommandDryRunPreview(t *testing.T) { sandboxRoot := t.TempDir() configDir := filepath.Join(sandboxRoot, "config") if err := os.MkdirAll(configDir, 0o700); err != nil { @@ -575,7 +575,7 @@ func TestManualAgentExampleChatGroupMuteMemberUsesCommandDryRunPreview(t *testin setTestHome(t, sandboxRoot) t.Setenv("DWS_CONFIG_DIR", configDir) - capture, err := executeManualAgentExampleCapture(t, []string{ + capture, err := executeAgentExampleCapture(t, []string{ "--dry-run", "chat", "group-mute-member", "--group", "test_openConversationId", @@ -591,10 +591,10 @@ func TestManualAgentExampleChatGroupMuteMemberUsesCommandDryRunPreview(t *testin if capture.DryRunChecks == 0 { t.Fatalf("group-mute-member did not enter its audited command dry-run path\noutput:\n%s", capture.Output) } - if capture.StdinBytesRead != 0 || manualAgentExamplePromptObserved(capture.Output) { + if capture.StdinBytesRead != 0 || agentExamplePromptObserved(capture.Output) { t.Fatalf("group-mute-member dry-run entered an interactive prompt (stdin bytes read: %d)\noutput:\n%s", capture.StdinBytesRead, capture.Output) } - if !manualAgentExampleDryRunObserved(capture) { + if !agentExampleDryRunObserved(capture) { t.Fatalf("group-mute-member returned no audited dry-run evidence\noutput:\n%s", capture.Output) } for _, expected := range []string{`"uids"`, `"userId1"`, `"userId2"`} { diff --git a/internal/app/schema_agent_selection_contract_test.go b/internal/app/schema_agent_selection_contract_test.go index 905134e6..1b625fed 100644 --- a/internal/app/schema_agent_selection_contract_test.go +++ b/internal/app/schema_agent_selection_contract_test.go @@ -19,7 +19,7 @@ import ( "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/cli" ) -func TestManualAgentSelectionScenariosCoverEveryExecutableSchemaTool(t *testing.T) { +func TestAgentSelectionScenariosCoverEveryExecutableSchemaTool(t *testing.T) { root := NewRootCommand() effective, err := cli.BuildEffectiveCommandRegistry(root) if err != nil { diff --git a/internal/app/schema_agent_selection_live_test.go b/internal/app/schema_agent_selection_live_test.go index 5e3dd443..eb605e3a 100644 --- a/internal/app/schema_agent_selection_live_test.go +++ b/internal/app/schema_agent_selection_live_test.go @@ -31,42 +31,42 @@ import ( "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/cli" ) -const manualAgentSelectionLiveBatchSize = 12 +const agentSelectionLiveBatchSize = 12 -type manualAgentSelectionLiveCandidate struct { +type agentSelectionLiveCandidate struct { CanonicalPath string `json:"canonical_path"` AgentSummary string `json:"agent_summary"` UseWhen []string `json:"use_when"` AvoidWhen []string `json:"avoid_when"` } -type manualAgentSelectionLiveInput struct { - Cases []manualAgentSelectionLiveCase `json:"cases"` - Candidates []manualAgentSelectionLiveCandidate `json:"candidates"` +type agentSelectionLiveInput struct { + Cases []agentSelectionLiveCase `json:"cases"` + Candidates []agentSelectionLiveCandidate `json:"candidates"` } -// manualAgentSelectionLiveCase is deliberately answer-free. Expected and +// agentSelectionLiveCase is deliberately answer-free. Expected and // forbidden canonicals stay only in the local assertion fixture and are never // sent to the model being evaluated. -type manualAgentSelectionLiveCase struct { +type agentSelectionLiveCase struct { ID string `json:"id"` Scenario string `json:"scenario"` } -type manualAgentSelectionLiveResult struct { +type agentSelectionLiveResult struct { ID string `json:"id"` CanonicalPath string `json:"canonical_path"` } -type manualAgentSelectionLiveResponse struct { - Results []manualAgentSelectionLiveResult `json:"results"` +type agentSelectionLiveResponse struct { + Results []agentSelectionLiveResult `json:"results"` } -// TestManualAgentSelectionArkLive is intentionally opt-in. Deterministic CI +// TestAgentSelectionArkLive is intentionally opt-in. Deterministic CI // validates all fixture and Cobra facts without network access; this test asks // a real model to interpret the reviewed natural-language scenarios. Set // DWS_AGENT_SELECTION_FULL=1 to evaluate every positive and negative case. -func TestManualAgentSelectionArkLive(t *testing.T) { +func TestAgentSelectionArkLive(t *testing.T) { if os.Getenv("DWS_AGENT_SELECTION_LIVE") != "1" { t.Skip("set DWS_AGENT_SELECTION_LIVE=1 and ARK_API_KEY/ARK_BASE_URL/ARK_MODEL to run live Agent command-selection evaluation") } @@ -82,37 +82,37 @@ func TestManualAgentSelectionArkLive(t *testing.T) { t.Fatalf("%s is required when DWS_AGENT_SELECTION_LIVE=1", name) } } - if err := validateManualAgentSelectionLiveBaseURL(baseURL, os.Getenv("DWS_AGENT_SELECTION_ALLOWED_BASE_URLS")); err != nil { + if err := validateAgentSelectionLiveBaseURL(baseURL, os.Getenv("DWS_AGENT_SELECTION_ALLOWED_BASE_URLS")); err != nil { t.Fatal(err) } - fixture, selectionSet := manualAgentSelectionLiveFixture(t) - cases := selectManualAgentSelectionLiveCases(t, fixture.Cases) - for _, batch := range batchManualAgentSelectionLiveCases(cases, manualAgentSelectionLiveBatchSize) { + fixture, selectionSet := agentSelectionLiveFixture(t) + cases := selectAgentSelectionLiveCases(t, fixture.Cases) + for _, batch := range batchAgentSelectionLiveCases(cases, agentSelectionLiveBatchSize) { productID := batch[0].ProductID - t.Run(productID+"/"+sanitizeManualAgentSelectionLiveTestID(batch[0].ID), func(t *testing.T) { - input := buildManualAgentSelectionLiveInput(batch, selectionSet) - results := callManualAgentSelectionLiveModel(t, baseURL, apiKey, model, input) - assertManualAgentSelectionLiveResults(t, batch, results) + t.Run(productID+"/"+sanitizeAgentSelectionLiveTestID(batch[0].ID), func(t *testing.T) { + input := buildAgentSelectionLiveInput(batch, selectionSet) + results := callAgentSelectionLiveModel(t, baseURL, apiKey, model, input) + assertAgentSelectionLiveResults(t, batch, results) }) } } -func buildManualAgentSelectionLiveInput(batch []cli.AgentSelectionCase, selectionSet cli.ManualAgentSelectionSet) manualAgentSelectionLiveInput { - input := manualAgentSelectionLiveInput{Cases: make([]manualAgentSelectionLiveCase, 0, len(batch))} +func buildAgentSelectionLiveInput(batch []cli.AgentSelectionCase, selectionSet cli.FixtureAgentSelectionSet) agentSelectionLiveInput { + input := agentSelectionLiveInput{Cases: make([]agentSelectionLiveCase, 0, len(batch))} if len(batch) == 0 { return input } for _, selectionCase := range batch { - input.Cases = append(input.Cases, manualAgentSelectionLiveCase{ + input.Cases = append(input.Cases, agentSelectionLiveCase{ ID: selectionCase.ID, Scenario: selectionCase.Scenario, }) } - input.Candidates = make([]manualAgentSelectionLiveCandidate, 0, len(batch[0].CandidateCanonicals)) + input.Candidates = make([]agentSelectionLiveCandidate, 0, len(batch[0].CandidateCanonicals)) for _, canonical := range batch[0].CandidateCanonicals { tool := selectionSet.Tools[canonical] - input.Candidates = append(input.Candidates, manualAgentSelectionLiveCandidate{ + input.Candidates = append(input.Candidates, agentSelectionLiveCandidate{ CanonicalPath: canonical, AgentSummary: tool.AgentSummary, UseWhen: tool.UseWhen, @@ -122,7 +122,7 @@ func buildManualAgentSelectionLiveInput(batch []cli.AgentSelectionCase, selectio return input } -func manualAgentSelectionLiveFixture(t testing.TB) (cli.AgentSelectionFixture, cli.ManualAgentSelectionSet) { +func agentSelectionLiveFixture(t testing.TB) (cli.AgentSelectionFixture, cli.FixtureAgentSelectionSet) { t.Helper() root := NewRootCommand() effective, err := cli.BuildEffectiveCommandRegistry(root) @@ -137,10 +137,10 @@ func manualAgentSelectionLiveFixture(t testing.TB) (cli.AgentSelectionFixture, c if err != nil { t.Fatalf("BuildAgentSelectionEvalFixture() error = %v", err) } - return fixture, cli.ManualAgentSelectionSet{} + return fixture, cli.FixtureAgentSelectionSet{} } -func selectManualAgentSelectionLiveCases(t testing.TB, cases []cli.AgentSelectionCase) []cli.AgentSelectionCase { +func selectAgentSelectionLiveCases(t testing.TB, cases []cli.AgentSelectionCase) []cli.AgentSelectionCase { t.Helper() if raw := strings.TrimSpace(os.Getenv("DWS_AGENT_SELECTION_CASES")); raw != "" { selected := map[string]bool{} @@ -187,7 +187,7 @@ func selectManualAgentSelectionLiveCases(t testing.TB, cases []cli.AgentSelectio return result } -func batchManualAgentSelectionLiveCases(cases []cli.AgentSelectionCase, batchSize int) [][]cli.AgentSelectionCase { +func batchAgentSelectionLiveCases(cases []cli.AgentSelectionCase, batchSize int) [][]cli.AgentSelectionCase { if batchSize <= 0 { batchSize = 1 } @@ -214,9 +214,9 @@ func batchManualAgentSelectionLiveCases(cases []cli.AgentSelectionCase, batchSiz return result } -func callManualAgentSelectionLiveModel(t testing.TB, baseURL, apiKey, model string, input manualAgentSelectionLiveInput) []manualAgentSelectionLiveResult { +func callAgentSelectionLiveModel(t testing.TB, baseURL, apiKey, model string, input agentSelectionLiveInput) []agentSelectionLiveResult { t.Helper() - body, err := marshalManualAgentSelectionLiveRequest(baseURL, model, input) + body, err := marshalAgentSelectionLiveRequest(baseURL, model, input) if err != nil { t.Fatalf("marshal live selection request: %v", err) } @@ -256,7 +256,7 @@ func callManualAgentSelectionLiveModel(t testing.TB, baseURL, apiKey, model stri if len(envelope.Choices) == 0 || strings.TrimSpace(envelope.Choices[0].Message.Content) == "" { t.Fatal("live selection response has no model content") } - var selection manualAgentSelectionLiveResponse + var selection agentSelectionLiveResponse decoder := json.NewDecoder(strings.NewReader(envelope.Choices[0].Message.Content)) decoder.DisallowUnknownFields() if err := decoder.Decode(&selection); err != nil { @@ -265,7 +265,7 @@ func callManualAgentSelectionLiveModel(t testing.TB, baseURL, apiKey, model stri return selection.Results } -func marshalManualAgentSelectionLiveRequest(baseURL, model string, input manualAgentSelectionLiveInput) ([]byte, error) { +func marshalAgentSelectionLiveRequest(baseURL, model string, input agentSelectionLiveInput) ([]byte, error) { inputJSON, err := json.Marshal(input) if err != nil { return nil, fmt.Errorf("marshal live selection input: %w", err) @@ -290,9 +290,9 @@ func marshalManualAgentSelectionLiveRequest(baseURL, model string, input manualA return json.Marshal(requestBody) } -func assertManualAgentSelectionLiveResults(t testing.TB, cases []cli.AgentSelectionCase, results []manualAgentSelectionLiveResult) { +func assertAgentSelectionLiveResults(t testing.TB, cases []cli.AgentSelectionCase, results []agentSelectionLiveResult) { t.Helper() - byID := make(map[string]manualAgentSelectionLiveResult, len(results)) + byID := make(map[string]agentSelectionLiveResult, len(results)) for _, result := range results { if _, exists := byID[result.ID]; exists { t.Fatalf("live selection returned duplicate case ID %q", result.ID) @@ -311,7 +311,7 @@ func assertManualAgentSelectionLiveResults(t testing.TB, cases []cli.AgentSelect t.Errorf("live selection returned empty canonical for %q", selectionCase.ID) continue } - if selected != "none" && !containsManualAgentSelectionCanonical(selectionCase.CandidateCanonicals, selected) { + if selected != "none" && !containsAgentSelectionCanonical(selectionCase.CandidateCanonicals, selected) { t.Errorf("live selection returned non-candidate %q for %q", selected, selectionCase.ID) continue } @@ -332,13 +332,13 @@ func assertManualAgentSelectionLiveResults(t testing.TB, cases []cli.AgentSelect } } -func validateManualAgentSelectionLiveBaseURL(raw, extraAllowed string) error { +func validateAgentSelectionLiveBaseURL(raw, extraAllowed string) error { parsed, err := url.Parse(raw) if err != nil || parsed.Scheme == "" || parsed.Host == "" || parsed.RawQuery != "" || parsed.Fragment != "" || parsed.User != nil { return fmt.Errorf("ARK_BASE_URL must be an absolute HTTP(S) API base without query or fragment") } if parsed.Scheme == "http" { - if !manualAgentSelectionLoopbackHost(parsed.Hostname()) { + if !agentSelectionLiveLoopbackHost(parsed.Hostname()) { return fmt.Errorf("ARK_BASE_URL may use plaintext HTTP only for a loopback test endpoint") } return nil @@ -363,7 +363,7 @@ func validateManualAgentSelectionLiveBaseURL(raw, extraAllowed string) error { return nil } -func manualAgentSelectionLoopbackHost(host string) bool { +func agentSelectionLiveLoopbackHost(host string) bool { if strings.EqualFold(strings.TrimSpace(host), "localhost") { return true } @@ -371,7 +371,7 @@ func manualAgentSelectionLoopbackHost(host string) bool { return ip != nil && ip.IsLoopback() } -func containsManualAgentSelectionCanonical(values []string, target string) bool { +func containsAgentSelectionCanonical(values []string, target string) bool { for _, value := range values { if value == target { return true @@ -380,36 +380,36 @@ func containsManualAgentSelectionCanonical(values []string, target string) bool return false } -func sanitizeManualAgentSelectionLiveTestID(value string) string { +func sanitizeAgentSelectionLiveTestID(value string) string { value = strings.ReplaceAll(value, ".", "_") value = strings.ReplaceAll(value, "/", "_") return value } -func TestManualAgentSelectionLiveResultContract(t *testing.T) { +func TestAgentSelectionLiveResultContract(t *testing.T) { cases := []cli.AgentSelectionCase{ {ID: "sample.search/use_when/0", Scenario: "find an item", ExpectedCanonical: "sample.search", CandidateCanonicals: []string{"sample.create", "sample.search"}}, {ID: "sample.search/avoid_when/0", Scenario: "create an item", ForbiddenCanonical: "sample.search", CandidateCanonicals: []string{"sample.create", "sample.search"}}, } t.Run("accepts exact positive and negative choices", func(t *testing.T) { - assertManualAgentSelectionLiveResults(t, cases, []manualAgentSelectionLiveResult{ + assertAgentSelectionLiveResults(t, cases, []agentSelectionLiveResult{ {ID: cases[0].ID, CanonicalPath: "sample.search"}, {ID: cases[1].ID, CanonicalPath: "sample.create"}, }) }) } -func TestManualAgentSelectionLiveInputDoesNotLeakAssertionsOrRepeatCandidates(t *testing.T) { +func TestAgentSelectionLiveInputDoesNotLeakAssertionsOrRepeatCandidates(t *testing.T) { batch := []cli.AgentSelectionCase{ {ID: "sample.search/use_when/0", Scenario: "find an item", ExpectedCanonical: "sample.search", CandidateCanonicals: []string{"sample.create", "sample.search"}}, {ID: "sample.search/avoid_when/0", Scenario: "create an item", ForbiddenCanonical: "sample.search", CandidateCanonicals: []string{"sample.create", "sample.search"}}, } - selectionSet := cli.ManualAgentSelectionSet{Tools: map[string]cli.ManualAgentToolSelection{ + selectionSet := cli.FixtureAgentSelectionSet{Tools: map[string]cli.AgentToolSelection{ "sample.create": {AgentSummary: "Create an item", UseWhen: []string{"create"}, AvoidWhen: []string{"find"}}, "sample.search": {AgentSummary: "Search items", UseWhen: []string{"find"}, AvoidWhen: []string{"create"}}, }} - input := buildManualAgentSelectionLiveInput(batch, selectionSet) - data, err := marshalManualAgentSelectionLiveRequest("https://ark.cn-beijing.volces.com/api/plan/v3", "fixed-model", input) + input := buildAgentSelectionLiveInput(batch, selectionSet) + data, err := marshalAgentSelectionLiveRequest("https://ark.cn-beijing.volces.com/api/plan/v3", "fixed-model", input) if err != nil { t.Fatal(err) } @@ -426,7 +426,7 @@ func TestManualAgentSelectionLiveInputDoesNotLeakAssertionsOrRepeatCandidates(t } } -func TestValidateManualAgentSelectionLiveBaseURL(t *testing.T) { +func TestValidateAgentSelectionLiveBaseURL(t *testing.T) { tests := []struct { name string baseURL string @@ -446,7 +446,7 @@ func TestValidateManualAgentSelectionLiveBaseURL(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := validateManualAgentSelectionLiveBaseURL(test.baseURL, test.extraAllowed) + err := validateAgentSelectionLiveBaseURL(test.baseURL, test.extraAllowed) if test.wantErr == "" { if err != nil { t.Fatalf("validate base URL: %v", err) diff --git a/internal/app/schema_contract_test.go b/internal/app/schema_contract_test.go index 03fd49e4..0ede18f9 100644 --- a/internal/app/schema_contract_test.go +++ b/internal/app/schema_contract_test.go @@ -81,7 +81,7 @@ func TestDeliverySchemaContractMapsToExecutableTree(t *testing.T) { for _, tool := range product.Tools { canonical := strings.TrimSpace(tool.CanonicalPath) if canonical == "" { - t.Fatal("embedded schema --all contains an empty canonical path") + t.Fatal("delivery schema --all contains an empty canonical path") } if actual[canonical] { duplicates = append(duplicates, canonical) @@ -91,7 +91,7 @@ func TestDeliverySchemaContractMapsToExecutableTree(t *testing.T) { } if len(duplicates) > 0 { sort.Strings(duplicates) - t.Fatalf("embedded schema --all contains duplicate canonicals: %v", duplicates) + t.Fatalf("delivery schema --all contains duplicate canonicals: %v", duplicates) } var missing, extra []string diff --git a/internal/app/schema_help_flag_completeness_test.go b/internal/app/schema_help_flag_completeness_test.go index 1f41abbf..58119144 100644 --- a/internal/app/schema_help_flag_completeness_test.go +++ b/internal/app/schema_help_flag_completeness_test.go @@ -77,16 +77,16 @@ func deliverySchemaAllToolsForHelpFlagTest(t testing.TB, root *cobra.Command) ma for _, tool := range product.Tools { canonical := strings.TrimSpace(schemaContractString(tool["canonical_path"])) if canonical == "" { - t.Fatal("embedded schema --all contains an empty canonical path") + t.Fatal("delivery schema --all contains an empty canonical path") } if _, exists := tools[canonical]; exists { - t.Fatalf("embedded schema --all contains duplicate canonical %q", canonical) + t.Fatalf("delivery schema --all contains duplicate canonical %q", canonical) } tools[canonical] = tool } } if len(tools) == 0 { - t.Fatal("embedded schema --all contains no tools") + t.Fatal("delivery schema --all contains no tools") } return tools } diff --git a/internal/app/schema_interface_disposition_contract_test.go b/internal/app/schema_interface_disposition_contract_test.go index 98e526e0..c92a8d18 100644 --- a/internal/app/schema_interface_disposition_contract_test.go +++ b/internal/app/schema_interface_disposition_contract_test.go @@ -182,7 +182,7 @@ func TestReviewedInterfaceDispositionSourceOwnsRuntimeSurface(t *testing.T) { } sort.Strings(canonicals) if len(canonicals) == 0 { - t.Fatal("embedded schema --all contains no tools") + t.Fatal("delivery schema --all contains no tools") } for _, canonical := range canonicals { tool := tools[canonical] diff --git a/internal/app/schema_shortcut_contract_test.go b/internal/app/schema_shortcut_contract_test.go index 43ea2327..8a90fff0 100644 --- a/internal/app/schema_shortcut_contract_test.go +++ b/internal/app/schema_shortcut_contract_test.go @@ -40,7 +40,7 @@ func TestDeliverySchemaCoversOrExactlyExcludesEveryPublicShortcutContract(t *tes } } if deliveredShortcuts != schemaPublishedShortcutCount { - t.Fatalf("embedded schema --all shortcut tools = %d, want %d", deliveredShortcuts, schemaPublishedShortcutCount) + t.Fatalf("delivery schema --all shortcut tools = %d, want %d", deliveredShortcuts, schemaPublishedShortcutCount) } exclusions, err := cli.EmbeddedRuntimeSchemaExclusions() @@ -64,15 +64,15 @@ func TestDeliverySchemaCoversOrExactlyExcludesEveryPublicShortcutContract(t *tes if tool == nil { cliPath := declared.Service + " " + declared.Command if !excludedPaths[cliPath] { - t.Fatalf("embedded schema --all is missing %s (%s) without an exact reviewed exclusion", canonical, cliPath) + t.Fatalf("delivery schema --all is missing %s (%s) without an exact reviewed exclusion", canonical, cliPath) } excludedShortcuts++ return } - assertEmbeddedShortcutIdentityAndSelection(t, tool, declared, canonical) - assertEmbeddedShortcutSafetyAndInterface(t, tool, declared, canonical) - assertEmbeddedShortcutParameters(t, tool, declared, canonical) - assertEmbeddedShortcutConstraints(t, tool, declared, canonical) + assertDeliveryShortcutIdentityAndSelection(t, tool, declared, canonical) + assertDeliveryShortcutSafetyAndInterface(t, tool, declared, canonical) + assertDeliveryShortcutParameters(t, tool, declared, canonical) + assertDeliveryShortcutConstraints(t, tool, declared, canonical) }) } if got, want := excludedShortcuts, publicShortcutCount-schemaPublishedShortcutCount; got != want { @@ -143,7 +143,7 @@ func shortcutSchemaCanonical(declared shortcut.Shortcut) string { return declared.Service + ".shortcut_" + name } -func assertEmbeddedShortcutIdentityAndSelection( +func assertDeliveryShortcutIdentityAndSelection( t testing.TB, tool map[string]any, declared shortcut.Shortcut, @@ -179,7 +179,7 @@ func assertEmbeddedShortcutIdentityAndSelection( } } -func assertEmbeddedShortcutSafetyAndInterface( +func assertDeliveryShortcutSafetyAndInterface( t testing.TB, tool map[string]any, declared shortcut.Shortcut, @@ -214,7 +214,7 @@ func assertEmbeddedShortcutSafetyAndInterface( } } -func assertEmbeddedShortcutParameters( +func assertDeliveryShortcutParameters( t testing.TB, tool map[string]any, declared shortcut.Shortcut, @@ -315,7 +315,7 @@ func shortcutSchemaRequired(declared shortcut.Shortcut, flagName string) bool { return false } -func assertEmbeddedShortcutConstraints( +func assertDeliveryShortcutConstraints( t testing.TB, tool map[string]any, declared shortcut.Shortcut, diff --git a/internal/app/schema_todo_list_attachment_contract_test.go b/internal/app/schema_todo_list_attachment_contract_test.go index 1acfa0bd..ef22261c 100644 --- a/internal/app/schema_todo_list_attachment_contract_test.go +++ b/internal/app/schema_todo_list_attachment_contract_test.go @@ -26,12 +26,12 @@ func TestTodoListAttachmentDeliveredSchemaMatchesExecutableHelp(t *testing.T) { root.SetErr(&stderr) root.SetArgs([]string{"schema", cliPath, "--format", "json"}) if err := root.Execute(); err != nil { - t.Fatalf("execute embedded schema leaf: %v; stderr=%s", err, stderr.String()) + t.Fatalf("execute delivery schema leaf: %v; stderr=%s", err, stderr.String()) } var tool map[string]any if err := json.Unmarshal(stdout.Bytes(), &tool); err != nil { - t.Fatalf("decode embedded schema leaf: %v", err) + t.Fatalf("decode delivery schema leaf: %v", err) } if got := schemaContractString(tool["canonical_path"]); got != canonicalPath { t.Fatalf("canonical_path = %q, want %q", got, canonicalPath) diff --git a/internal/cli/runtime_schema.go b/internal/cli/runtime_schema.go index c8f71762..c129318b 100644 --- a/internal/cli/runtime_schema.go +++ b/internal/cli/runtime_schema.go @@ -288,7 +288,7 @@ func collectRuntimeSchemaEntriesFromBound(bound BoundCommandRegistry) ([]runtime return entries, nil } -func embeddedMCPMetadataForEntryFrom(entry runtimeSchemaEntry, agentMetadata embeddedAgentMetadata, mcpMetadata embeddedMCPMetadata) (embeddedMCPToolMetadata, bool) { +func embeddedMCPMetadataForEntryFrom(entry runtimeSchemaEntry, agentMetadata agentMetadata, mcpMetadata embeddedMCPMetadata) (embeddedMCPToolMetadata, bool) { // Production authority: ContractFinal Interface.Ref remaps CLI canonical // names onto pinned MCP tool keys (e.g. reply_personal_message → // chat.send_personal_message). Agent-metadata inject is CI-dump only. diff --git a/internal/cli/runtime_schema_coverage_more_test.go b/internal/cli/runtime_schema_coverage_more_test.go index 18ddecc2..4b48022c 100644 --- a/internal/cli/runtime_schema_coverage_more_test.go +++ b/internal/cli/runtime_schema_coverage_more_test.go @@ -87,7 +87,7 @@ func TestCrossPlatformCoverageCollectRuntimeSchemaEntriesErrorsAndOrdering(t *te } func TestCrossPlatformCoverageRuntimeSchemaMetadataLookupEdges(t *testing.T) { - if _, ok := embeddedMCPMetadataForEntryFrom(runtimeSchemaEntry{}, embeddedAgentMetadata{}, embeddedMCPMetadata{Tools: map[string]embeddedMCPToolMetadata{}}); ok { + if _, ok := embeddedMCPMetadataForEntryFrom(runtimeSchemaEntry{}, agentMetadata{}, embeddedMCPMetadata{Tools: map[string]embeddedMCPToolMetadata{}}); ok { t.Fatal("empty lookup unexpectedly matched") } @@ -107,7 +107,7 @@ func TestCrossPlatformCoverageRuntimeSchemaMetadataLookupEdges(t *testing.T) { }, }, }} - got, ok := embeddedMCPMetadataForEntryFrom(runtimeSchemaEntry{Command: leaf, ProductID: "chat", ToolName: "reply_personal_message"}, embeddedAgentMetadata{}, mcp) + got, ok := embeddedMCPMetadataForEntryFrom(runtimeSchemaEntry{Command: leaf, ProductID: "chat", ToolName: "reply_personal_message"}, agentMetadata{}, mcp) if !ok || got.Parameters["clawType"].Type != "string" { t.Fatalf("ContractFinal Interface.Ref MCP remap = %#v ok=%v", got, ok) } diff --git a/internal/cli/schema_agent_examples.go b/internal/cli/schema_agent_examples.go index 568d3678..a77a7ef2 100644 --- a/internal/cli/schema_agent_examples.go +++ b/internal/cli/schema_agent_examples.go @@ -30,80 +30,76 @@ import ( // remains a precise reviewed exception for such a capability whose runtime // preconditions cannot be exercised safely and deterministically in the // isolated test process. -type AgentExampleMode = ManualAgentExampleMode - -// ManualAgentExampleMode is retained as the historical name for AgentExampleMode -// so dry-run tests and policy scripts keep stable identifiers. -type ManualAgentExampleMode string +type AgentExampleMode string const ( - ManualAgentExampleModeContract ManualAgentExampleMode = "contract" - ManualAgentExampleModeDryRun ManualAgentExampleMode = "dry_run" - ManualAgentExampleModeContractOnly ManualAgentExampleMode = "contract_only" + AgentExampleModeContract AgentExampleMode = "contract" + AgentExampleModeDryRun AgentExampleMode = "dry_run" + AgentExampleModeContractOnly AgentExampleMode = "contract_only" ) -// ManualAgentExampleReasonCode is a closed taxonomy for reviewed contract-only +// AgentExampleReasonCode is a closed taxonomy for reviewed contract-only // exceptions to an explicit dry-run capability. -type ManualAgentExampleReasonCode string +type AgentExampleReasonCode string const ( - ManualAgentExampleReasonLocalState ManualAgentExampleReasonCode = "local_state" - ManualAgentExampleReasonStatefulPreflight ManualAgentExampleReasonCode = "stateful_preflight" + AgentExampleReasonLocalState AgentExampleReasonCode = "local_state" + AgentExampleReasonStatefulPreflight AgentExampleReasonCode = "stateful_preflight" ) -// ManualAgentExampleDisposition narrows one exact example with an explicit +// AgentExampleDisposition narrows one exact example with an explicit // typed dry-run capability to contract-only. Index is a pointer so a missing // field cannot silently select example zero. // -// Dispositions are no longer authored via HintFiles. They remain available as -// an in-test / future ContractFinal extension surface; production ContractFinal -// Selection currently does not declare them, so the delivery plan treats every -// example as default-typed (contract or dry_run from ToolSpec.DryRun). -type ManualAgentExampleDisposition struct { - Index *int `json:"index"` - Mode ManualAgentExampleMode `json:"mode"` - ReasonCode ManualAgentExampleReasonCode `json:"reason_code"` - Reason string `json:"reason"` - Reviewed bool `json:"reviewed"` +// Dispositions are authored as an in-test / future ContractFinal extension +// surface; production ContractFinal Selection currently does not declare them, +// so the delivery plan treats every example as default-typed (contract or +// dry_run from ToolSpec.DryRun). +type AgentExampleDisposition struct { + Index *int `json:"index"` + Mode AgentExampleMode `json:"mode"` + ReasonCode AgentExampleReasonCode `json:"reason_code"` + Reason string `json:"reason"` + Reviewed bool `json:"reviewed"` } -// ManualAgentExampleExecution is one resolved example and its effective test mode. -type ManualAgentExampleExecution struct { +// AgentExampleExecution is one resolved example and its effective test mode. +type AgentExampleExecution struct { CanonicalPath string Index int Example string - Mode ManualAgentExampleMode + Mode AgentExampleMode DryRun *contract.DryRunSpec - ReasonCode ManualAgentExampleReasonCode + ReasonCode AgentExampleReasonCode Reason string - Source ManualAgentExampleDispositionSource + Source AgentExampleDispositionSource } -// ManualAgentExampleDispositionSource distinguishes the normal typed-contract +// AgentExampleDispositionSource distinguishes the normal typed-contract // classification from narrow reviewed exceptions. -type ManualAgentExampleDispositionSource string +type AgentExampleDispositionSource string const ( - ManualAgentExampleDispositionDefault ManualAgentExampleDispositionSource = "default" - ManualAgentExampleDispositionReviewedManual ManualAgentExampleDispositionSource = "reviewed_manual" + AgentExampleDispositionDefault AgentExampleDispositionSource = "default" + AgentExampleDispositionReviewed AgentExampleDispositionSource = "reviewed_manual" ) -// ManualAgentExampleExecutionPlan is a stable, typed report used by the +// AgentExampleExecutionPlan is a stable, typed report used by the // exhaustive real-Cobra dry-run test. -type ManualAgentExampleExecutionPlan struct { - Examples []ManualAgentExampleExecution +type AgentExampleExecutionPlan struct { + Examples []AgentExampleExecution Total int Contract int DryRun int ContractOnly int ReviewedContractOnly int - ContractOnlyByReason map[ManualAgentExampleReasonCode]int + ContractOnlyByReason map[AgentExampleReasonCode]int } // ValidateAgentExampleDelivery is the final generation gate. It validates every // bound tool's ContractFinal Selection.Examples against the assembled typed // SchemaRegistry. -func ValidateAgentExampleDelivery(bound BoundCommandRegistry, registry SchemaRegistry) (ManualAgentExampleExecutionPlan, error) { +func ValidateAgentExampleDelivery(bound BoundCommandRegistry, registry SchemaRegistry) (AgentExampleExecutionPlan, error) { return BuildAgentExampleExecutionPlan(bound, registry) } @@ -115,16 +111,16 @@ var agentExampleSelectionFn = contractFinalToolSelection // BuildAgentExampleExecutionPlan validates every ContractFinal example against // its real BoundCommand/Cobra contract. Runtime dry-run execution is opt-in and // comes only from the final typed ToolSpec. -func BuildAgentExampleExecutionPlan(bound BoundCommandRegistry, registry SchemaRegistry) (ManualAgentExampleExecutionPlan, error) { +func BuildAgentExampleExecutionPlan(bound BoundCommandRegistry, registry SchemaRegistry) (AgentExampleExecutionPlan, error) { tools := make(map[string]ToolSpec, len(bound.Commands)) for _, product := range registry.Products { for _, tool := range product.Tools { canonical := strings.TrimSpace(tool.Identity.CanonicalPath) if canonical == "" { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("typed SchemaRegistry contains a tool with empty canonical path") + return AgentExampleExecutionPlan{}, fmt.Errorf("typed SchemaRegistry contains a tool with empty canonical path") } if _, duplicate := tools[canonical]; duplicate { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("typed SchemaRegistry contains duplicate tool %q", canonical) + return AgentExampleExecutionPlan{}, fmt.Errorf("typed SchemaRegistry contains duplicate tool %q", canonical) } tools[canonical] = tool } @@ -132,31 +128,25 @@ func BuildAgentExampleExecutionPlan(bound BoundCommandRegistry, registry SchemaR return buildAgentExampleExecutionPlan(bound, tools) } -// BuildManualAgentExampleExecutionPlan is a compatibility wrapper that ignores -// residual ManualAgentSelectionSet input and builds the plan from ContractFinal only. -func BuildManualAgentExampleExecutionPlan(bound BoundCommandRegistry, registry SchemaRegistry, _ ManualAgentSelectionSet) (ManualAgentExampleExecutionPlan, error) { - return BuildAgentExampleExecutionPlan(bound, registry) +// FixtureAgentSelectionSet is a transitional Agent selection fixture type +// retained only so live-selection call sites can project candidate tables. +// Production paths must keep it empty; example planning reads ContractFinal. +type FixtureAgentSelectionSet struct { + Revisions map[string]FixtureAgentSelectionRevision `json:"revisions,omitempty"` + Products map[string]FixtureAgentProductSelection `json:"products,omitempty"` + Tools map[string]AgentToolSelection `json:"tools,omitempty"` } -// ManualAgentSelectionSet is a transitional Agent selection fixture type -// retained only so live-selection / example-plan call sites compile while they -// migrate fully onto ContractFinal. Production paths must keep it empty. -type ManualAgentSelectionSet struct { - Revisions map[string]ManualAgentSelectionRevision `json:"revisions,omitempty"` - Products map[string]ManualAgentProductSelection `json:"products,omitempty"` - Tools map[string]ManualAgentToolSelection `json:"tools,omitempty"` -} - -// ManualAgentSelectionRevision is retained for transitional fixtures only. -type ManualAgentSelectionRevision struct { +// FixtureAgentSelectionRevision is retained for transitional fixtures only. +type FixtureAgentSelectionRevision struct { GeneratedBy string `json:"generated_by"` Model string `json:"model,omitempty"` PromptVersion string `json:"prompt_version,omitempty"` Reason string `json:"reason"` } -// ManualAgentProductSelection is retained for transitional fixtures only. -type ManualAgentProductSelection struct { +// FixtureAgentProductSelection is retained for transitional fixtures only. +type FixtureAgentProductSelection struct { AgentSummary string `json:"agent_summary"` UseWhen []string `json:"use_when"` AvoidWhen []string `json:"avoid_when"` @@ -166,28 +156,30 @@ type ManualAgentProductSelection struct { Evidence []string `json:"evidence"` } -// ManualAgentToolSelection is retained for transitional fixtures only. -type ManualAgentToolSelection struct { - AgentSummary string `json:"agent_summary"` - UseWhen []string `json:"use_when"` - AvoidWhen []string `json:"avoid_when"` - Examples []string `json:"examples"` - ExampleDispositions []ManualAgentExampleDisposition `json:"example_dispositions,omitempty"` - Reviewed bool `json:"reviewed"` - Revision string `json:"revision"` - Reason string `json:"reason"` - Evidence []string `json:"evidence"` +// AgentToolSelection is the tool-level selection projection used by example +// planning and live-selection fixtures. Production authority remains +// ContractFinal Selection on the owning leaf. +type AgentToolSelection struct { + AgentSummary string `json:"agent_summary"` + UseWhen []string `json:"use_when"` + AvoidWhen []string `json:"avoid_when"` + Examples []string `json:"examples"` + ExampleDispositions []AgentExampleDisposition `json:"example_dispositions,omitempty"` + Reviewed bool `json:"reviewed"` + Revision string `json:"revision"` + Reason string `json:"reason"` + Evidence []string `json:"evidence"` } -func buildAgentExampleExecutionPlan(bound BoundCommandRegistry, typedTools map[string]ToolSpec) (ManualAgentExampleExecutionPlan, error) { - plan := ManualAgentExampleExecutionPlan{ - ContractOnlyByReason: map[ManualAgentExampleReasonCode]int{}, +func buildAgentExampleExecutionPlan(bound BoundCommandRegistry, typedTools map[string]ToolSpec) (AgentExampleExecutionPlan, error) { + plan := AgentExampleExecutionPlan{ + ContractOnlyByReason: map[AgentExampleReasonCode]int{}, } canonicalPaths := make([]string, 0, len(bound.Commands)) for _, command := range bound.Commands { canonical := strings.TrimSpace(command.CanonicalPath) if !contractfinal.HasRuntimeContractFinal(command.PrimaryCommand) { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("bound tool %q has no ContractFinal declaration; Schema examples require leaf Schema.Selection", canonical) + return AgentExampleExecutionPlan{}, fmt.Errorf("bound tool %q has no ContractFinal declaration; Schema examples require leaf Schema.Selection", canonical) } canonicalPaths = append(canonicalPaths, canonical) } @@ -195,7 +187,7 @@ func buildAgentExampleExecutionPlan(bound BoundCommandRegistry, typedTools map[s for _, canonical := range canonicalPaths { spec, ok := bound.ByCanonical[canonical] if !ok { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("example plan references unknown canonical tool %q", canonical) + return AgentExampleExecutionPlan{}, fmt.Errorf("example plan references unknown canonical tool %q", canonical) } selection := agentExampleSelectionFn(spec.PrimaryCommand) var typedTool ToolSpec @@ -203,19 +195,19 @@ func buildAgentExampleExecutionPlan(bound BoundCommandRegistry, typedTools map[s var found bool typedTool, found = typedTools[canonical] if !found { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("example tool %q is missing from final typed SchemaRegistry", canonical) + return AgentExampleExecutionPlan{}, fmt.Errorf("example tool %q is missing from final typed SchemaRegistry", canonical) } } if len(selection.Examples) == 0 { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("ContractFinal tool %s requires non-empty Selection.Examples", canonical) + return AgentExampleExecutionPlan{}, fmt.Errorf("ContractFinal tool %s requires non-empty Selection.Examples", canonical) } if len(selection.Examples) > 2 { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("ContractFinal tool %s has %d examples; maximum is 2", canonical, len(selection.Examples)) + return AgentExampleExecutionPlan{}, fmt.Errorf("ContractFinal tool %s has %d examples; maximum is 2", canonical, len(selection.Examples)) } if err := validateAgentExampleDispositions(canonical, selection.Examples, selection.ExampleDispositions); err != nil { - return ManualAgentExampleExecutionPlan{}, err + return AgentExampleExecutionPlan{}, err } - dispositions := make(map[int]ManualAgentExampleDisposition, len(selection.ExampleDispositions)) + dispositions := make(map[int]AgentExampleDisposition, len(selection.ExampleDispositions)) for _, disposition := range selection.ExampleDispositions { dispositions[*disposition.Index] = disposition } @@ -232,29 +224,29 @@ func buildAgentExampleExecutionPlan(bound BoundCommandRegistry, typedTools map[s for index, example := range selection.Examples { argv, err := tokenizeAgentExample(example) if err != nil { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("tool %s example has invalid argv syntax: %w", canonical, err) + return AgentExampleExecutionPlan{}, fmt.Errorf("tool %s example has invalid argv syntax: %w", canonical, err) } if len(argv) < 2 || argv[0] != "dws" { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("tool %s example must start with dws: %q", canonical, example) + return AgentExampleExecutionPlan{}, fmt.Errorf("tool %s example must start with dws: %q", canonical, example) } for _, argument := range argv[1:] { if argument == "--yes" || strings.HasPrefix(argument, "--yes=") { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("tool %s example must not bypass confirmation with --yes", canonical) + return AgentExampleExecutionPlan{}, fmt.Errorf("tool %s example must not bypass confirmation with --yes", canonical) } if argument == "--help" || strings.HasPrefix(argument, "--help=") || argument == "-h" || strings.HasPrefix(argument, "-h=") { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("tool %s example must demonstrate execution, not only --help", canonical) + return AgentExampleExecutionPlan{}, fmt.Errorf("tool %s example must demonstrate execution, not only --help", canonical) } } remainder, matched, ok := matchAgentExamplePath(argv, paths) if !ok { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("tool %s example does not use its reviewed primary/alias path: %q", canonical, example) + return AgentExampleExecutionPlan{}, fmt.Errorf("tool %s example does not use its reviewed primary/alias path: %q", canonical, example) } if matched.Command == nil { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("tool %s reviewed path %q has no bound Cobra command", canonical, matched.Path) + return AgentExampleExecutionPlan{}, fmt.Errorf("tool %s reviewed path %q has no bound Cobra command", canonical, matched.Path) } constraints, err := strictCompatibilityConstraints(matched.Command, canonical) if err != nil { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("tool %s example for %q has invalid executable constraints: %w", canonical, matched.Path, err) + return AgentExampleExecutionPlan{}, fmt.Errorf("tool %s example for %q has invalid executable constraints: %w", canonical, matched.Path, err) } if typedTools != nil { constraints.MutuallyExclusive = append(constraints.MutuallyExclusive, typedTool.Constraints.MutuallyExclusive...) @@ -264,36 +256,36 @@ func buildAgentExampleExecutionPlan(bound BoundCommandRegistry, typedTools map[s } positionals, err := strictCompatibilityPositionals(matched.Command) if err != nil { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("tool %s example for %q has invalid executable positionals: %w", canonical, matched.Path, err) + return AgentExampleExecutionPlan{}, fmt.Errorf("tool %s example for %q has invalid executable positionals: %w", canonical, matched.Path, err) } if typedTools != nil { positionals = mergeAgentExamplePositionals(positionals, typedTool.Positionals) } if err := validateAgentExampleCobraContract(matched.Command, remainder, constraints, positionals); err != nil { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("tool %s example for %q: %w", canonical, matched.Path, err) + return AgentExampleExecutionPlan{}, fmt.Errorf("tool %s example for %q: %w", canonical, matched.Path, err) } - execution := ManualAgentExampleExecution{ + execution := AgentExampleExecution{ CanonicalPath: canonical, Index: index, Example: example, - Mode: ManualAgentExampleModeContract, - Source: ManualAgentExampleDispositionDefault, + Mode: AgentExampleModeContract, + Source: AgentExampleDispositionDefault, } if typedTool.DryRun != nil { dryRun := *typedTool.DryRun execution.DryRun = &dryRun - execution.Mode = ManualAgentExampleModeDryRun + execution.Mode = AgentExampleModeDryRun } disposition, hasDisposition := dispositions[index] if hasDisposition { if typedTools != nil && execution.DryRun == nil { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("tool %s example disposition index %d narrows no explicit dry_run capability", canonical, index) + return AgentExampleExecutionPlan{}, fmt.Errorf("tool %s example disposition index %d narrows no explicit dry_run capability", canonical, index) } execution.Mode = disposition.Mode execution.ReasonCode = disposition.ReasonCode execution.Reason = strings.TrimSpace(disposition.Reason) - execution.Source = ManualAgentExampleDispositionReviewedManual + execution.Source = AgentExampleDispositionReviewed plan.ContractOnly++ plan.ReviewedContractOnly++ plan.ContractOnlyByReason[disposition.ReasonCode]++ @@ -315,7 +307,7 @@ func buildAgentExampleExecutionPlan(bound BoundCommandRegistry, typedTools map[s } } if !found { - return ManualAgentExampleExecutionPlan{}, fmt.Errorf("final typed SchemaRegistry tool %q is missing from BoundCommandRegistry", canonical) + return AgentExampleExecutionPlan{}, fmt.Errorf("final typed SchemaRegistry tool %q is missing from BoundCommandRegistry", canonical) } } return plan, nil @@ -353,7 +345,7 @@ func matchAgentExamplePath(argv []string, paths []agentExamplePath) ([]string, a return nil, agentExamplePath{}, false } -func validateAgentExampleDispositions(canonical string, examples []string, dispositions []ManualAgentExampleDisposition) error { +func validateAgentExampleDispositions(canonical string, examples []string, dispositions []AgentExampleDisposition) error { seen := make(map[int]bool, len(dispositions)) for _, disposition := range dispositions { if disposition.Index == nil { @@ -370,8 +362,8 @@ func validateAgentExampleDispositions(canonical string, examples []string, dispo if !disposition.Reviewed { return fmt.Errorf("tool %s example disposition index %d must be reviewed", canonical, index) } - if disposition.Mode != ManualAgentExampleModeContractOnly { - return fmt.Errorf("tool %s example disposition index %d has invalid mode %q; only %q may narrow an explicit dry_run capability", canonical, index, disposition.Mode, ManualAgentExampleModeContractOnly) + if disposition.Mode != AgentExampleModeContractOnly { + return fmt.Errorf("tool %s example disposition index %d has invalid mode %q; only %q may narrow an explicit dry_run capability", canonical, index, disposition.Mode, AgentExampleModeContractOnly) } if !validAgentExampleReasonCode(disposition.ReasonCode) { return fmt.Errorf("tool %s example disposition index %d has invalid reason_code %q", canonical, index, disposition.ReasonCode) @@ -383,9 +375,9 @@ func validateAgentExampleDispositions(canonical string, examples []string, dispo return nil } -func validAgentExampleReasonCode(code ManualAgentExampleReasonCode) bool { +func validAgentExampleReasonCode(code AgentExampleReasonCode) bool { switch code { - case ManualAgentExampleReasonLocalState, ManualAgentExampleReasonStatefulPreflight: + case AgentExampleReasonLocalState, AgentExampleReasonStatefulPreflight: return true default: return false @@ -474,9 +466,9 @@ func tokenizeAgentExample(input string) ([]string, error) { return argv, nil } -// ParseManualAgentExampleArgv exposes the shell-free argv parser used by +// ParseAgentExampleArgv exposes the shell-free argv parser used by // example validation and dry-run tests. -func ParseManualAgentExampleArgv(input string) ([]string, error) { +func ParseAgentExampleArgv(input string) ([]string, error) { return tokenizeAgentExample(input) } diff --git a/internal/cli/schema_agent_metadata.go b/internal/cli/schema_agent_metadata.go index c35dffc6..fdcd712a 100644 --- a/internal/cli/schema_agent_metadata.go +++ b/internal/cli/schema_agent_metadata.go @@ -16,7 +16,6 @@ package cli import ( "encoding/json" "fmt" - "io/fs" "strings" "sync" "sync/atomic" @@ -30,19 +29,19 @@ import ( // InstallBuildTimeAgentMetadataJSON is a CI/local dump helper for // cmd_schema_catalog only; it is not a production source. -const embeddedAgentMetadataSource = "embedded-skill-metadata" +const agentMetadataSource = "embedded-skill-metadata" -type embeddedAgentMetadata struct { +type agentMetadata struct { Version int `json:"version"` SourceHash string `json:"source_hash"` SurfaceHash string `json:"surface_hash,omitempty"` - Coverage embeddedAgentMetadataCoverage `json:"coverage"` + Coverage agentMetadataCoverage `json:"coverage"` Products map[string]agentProductMetadata `json:"products"` Domains []string `json:"domains"` Tools map[string]agentToolMetadata `json:"tools"` } -type embeddedAgentMetadataCoverage struct { +type agentMetadataCoverage struct { SurfaceProducts int `json:"surface_products,omitempty"` ProductsWithMetadata int `json:"products_with_metadata"` SurfaceTools int `json:"surface_tools,omitempty"` @@ -88,21 +87,16 @@ type agentToolMetadata struct { FieldProvenance map[string]contract.FieldProvenance `json:"field_provenance,omitempty"` } -type embeddedAgentMetadataDomain struct { - ProductID string `json:"product_id"` - Tools map[string]agentToolMetadata `json:"tools"` -} - -var runtimeEmbeddedAgentMetadataLazy struct { +var runtimeAgentMetadataLazy struct { once sync.Once - metadata embeddedAgentMetadata + metadata agentMetadata } -var runtimeEmbeddedAgentMetadataLazyLoadCount atomic.Uint64 +var runtimeAgentMetadataLazyLoadCount atomic.Uint64 var ( buildTimeAgentMetadataMu sync.Mutex - buildTimeAgentMetadataOverride *embeddedAgentMetadata + buildTimeAgentMetadataOverride *agentMetadata ) // InstallBuildTimeAgentMetadataJSON installs generator-produced Agent metadata @@ -111,7 +105,7 @@ var ( // The dump helper injects an in-memory snapshot so schema_agent_metadata/ is // neither committed nor embedded. func InstallBuildTimeAgentMetadataJSON(data []byte) error { - var metadata embeddedAgentMetadata + var metadata agentMetadata if err := json.Unmarshal(data, &metadata); err != nil { return fmt.Errorf("decode build-time Agent metadata: %w", err) } @@ -139,55 +133,22 @@ func ClearBuildTimeAgentMetadata() { // CI dump helper installed one; otherwise an empty snapshot. Shipped // binaries no longer embed schema_agent_metadata/*.json; production Agent // facts come from ContractFinal / ProductDecl. -func runtimeAgentMetadata() embeddedAgentMetadata { +func runtimeAgentMetadata() agentMetadata { buildTimeAgentMetadataMu.Lock() override := buildTimeAgentMetadataOverride buildTimeAgentMetadataMu.Unlock() if override != nil { return *override } - runtimeEmbeddedAgentMetadataLazy.once.Do(func() { - runtimeEmbeddedAgentMetadataLazyLoadCount.Add(1) - runtimeEmbeddedAgentMetadataLazy.metadata = emptyEmbeddedAgentMetadata() + runtimeAgentMetadataLazy.once.Do(func() { + runtimeAgentMetadataLazyLoadCount.Add(1) + runtimeAgentMetadataLazy.metadata = emptyAgentMetadata() }) - return runtimeEmbeddedAgentMetadataLazy.metadata + return runtimeAgentMetadataLazy.metadata } -// loadEmbeddedAgentMetadataFrom remains a test-only seam for MapFS fixtures that -// exercise the retired split-domain JSON shape. Production no longer embeds or -// loads schema_agent_metadata/*.json. -func loadEmbeddedAgentMetadataFrom(source fs.FS) embeddedAgentMetadata { - var metadata embeddedAgentMetadata - index, err := fs.ReadFile(source, "schema_agent_metadata/index.json") - if err != nil || json.Unmarshal(index, &metadata) != nil { - return emptyEmbeddedAgentMetadata() - } - metadata.Tools = map[string]agentToolMetadata{} - for _, domain := range metadata.Domains { - domain = strings.TrimSpace(domain) - if domain == "" || strings.Contains(domain, "/") || strings.Contains(domain, "\\") { - return emptyEmbeddedAgentMetadata() - } - data, err := fs.ReadFile(source, "schema_agent_metadata/"+domain+".json") - if err != nil { - return emptyEmbeddedAgentMetadata() - } - var fragment embeddedAgentMetadataDomain - if err := json.Unmarshal(data, &fragment); err != nil || strings.TrimSpace(fragment.ProductID) != domain { - return emptyEmbeddedAgentMetadata() - } - for path, tool := range fragment.Tools { - metadata.Tools[path] = tool - } - } - if metadata.Products == nil { - metadata.Products = map[string]agentProductMetadata{} - } - return metadata -} - -func emptyEmbeddedAgentMetadata() embeddedAgentMetadata { - return embeddedAgentMetadata{ +func emptyAgentMetadata() agentMetadata { + return agentMetadata{ Products: map[string]agentProductMetadata{}, Tools: map[string]agentToolMetadata{}, } @@ -197,7 +158,7 @@ func emptyEmbeddedAgentMetadata() embeddedAgentMetadata { // metadata to runtime contract assembly. Path resolution happens once; all // consumers receive the same resolved safety, interface, selection and // provenance values without performing downstream map merges. -func agentToolContractForPathsFromMetadata(source embeddedAgentMetadata, paths ...string) (contract.SafetySpec, contract.InterfaceSpec, contract.SelectionSpec, map[string]contract.FieldProvenance, bool) { +func agentToolContractForPathsFromMetadata(source agentMetadata, paths ...string) (contract.SafetySpec, contract.InterfaceSpec, contract.SelectionSpec, map[string]contract.FieldProvenance, bool) { metadata, ok := lookupAgentToolMetadataFrom(source, paths...) if !ok { return contract.SafetySpec{}, contract.InterfaceSpec{}, contract.SelectionSpec{}, nil, false @@ -266,12 +227,12 @@ func projectAgentInterfaceRefProvenance(provenance contract.FieldProvenance, ref // agentProductSelectionForIDsFromMetadata exposes generated product routing // through the same typed contract.SelectionSpec used by ToolSpec. -func agentProductSelectionForIDsFromMetadata(source embeddedAgentMetadata, ids ...string) (contract.SelectionSpec, bool) { +func agentProductSelectionForIDsFromMetadata(source agentMetadata, ids ...string) (contract.SelectionSpec, bool) { selection, _, ok := agentProductContractForIDsFromMetadata(source, ids...) return selection, ok } -func agentProductContractForIDsFromMetadata(source embeddedAgentMetadata, ids ...string) (contract.SelectionSpec, map[string]contract.FieldProvenance, bool) { +func agentProductContractForIDsFromMetadata(source agentMetadata, ids ...string) (contract.SelectionSpec, map[string]contract.FieldProvenance, bool) { for _, id := range ids { metadata, ok := source.Products[strings.TrimSpace(id)] if !ok { @@ -283,7 +244,7 @@ func agentProductContractForIDsFromMetadata(source embeddedAgentMetadata, ids .. UseWhen: cloneOptionalStrings(metadata.UseWhen), AvoidWhen: cloneOptionalStrings(metadata.AvoidWhen), SourceRefs: cloneOptionalStrings(metadata.SourceRefs), - MetadataSource: embeddedAgentMetadataSource, + MetadataSource: agentMetadataSource, }.Normalized() return selection, cloneFieldProvenance(metadata.FieldProvenance), true } @@ -307,7 +268,7 @@ func agentToolSelection(metadata agentToolMetadata) contract.SelectionSpec { Examples: cloneOptionalStrings(metadata.Examples), Reviewed: reviewed, SourceRefs: cloneOptionalStrings(metadata.SourceRefs), - MetadataSource: embeddedAgentMetadataSource, + MetadataSource: agentMetadataSource, }.Normalized() } @@ -341,7 +302,7 @@ func cloneFieldCandidates(source []contract.FieldCandidateProvenance) []contract return out } -func lookupAgentToolMetadataFrom(source embeddedAgentMetadata, paths ...string) (agentToolMetadata, bool) { +func lookupAgentToolMetadataFrom(source agentMetadata, paths ...string) (agentToolMetadata, bool) { seen := map[string]bool{} for _, path := range paths { for _, candidate := range []string{ @@ -360,9 +321,9 @@ func lookupAgentToolMetadataFrom(source embeddedAgentMetadata, paths ...string) return agentToolMetadata{}, false } -func agentMetadataSummaryFrom(metadata embeddedAgentMetadata) map[string]any { +func agentMetadataSummaryFrom(metadata agentMetadata) map[string]any { summary := map[string]any{ - "source": embeddedAgentMetadataSource, + "source": agentMetadataSource, "version": metadata.Version, "source_hash": strings.TrimSpace(metadata.SourceHash), "products_with_metadata": len(metadata.Products), @@ -411,7 +372,7 @@ func agentMetadataSummaryFromProducts(products []ProductSpec) map[string]any { } } summary := map[string]any{ - "source": embeddedAgentMetadataSource, + "source": agentMetadataSource, "version": 1, "source_hash": "", "products_with_metadata": productsWith, diff --git a/internal/cli/schema_agent_metadata_fixture_test.go b/internal/cli/schema_agent_metadata_fixture_test.go new file mode 100644 index 00000000..497e99f6 --- /dev/null +++ b/internal/cli/schema_agent_metadata_fixture_test.go @@ -0,0 +1,60 @@ +// Copyright 2026 Alibaba Group +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cli + +import ( + "encoding/json" + "io/fs" + "strings" +) + +// agentMetadataDomain is the retired split-domain JSON fragment shape. Tests +// keep a MapFS loader for regression coverage; production never embeds or loads +// schema_agent_metadata/*.json. +type agentMetadataDomain struct { + ProductID string `json:"product_id"` + Tools map[string]agentToolMetadata `json:"tools"` +} + +// loadAgentMetadataFixtureFrom is a test-only seam for MapFS fixtures that +// exercise the retired split-domain JSON shape. +func loadAgentMetadataFixtureFrom(source fs.FS) agentMetadata { + var metadata agentMetadata + index, err := fs.ReadFile(source, "schema_agent_metadata/index.json") + if err != nil || json.Unmarshal(index, &metadata) != nil { + return emptyAgentMetadata() + } + metadata.Tools = map[string]agentToolMetadata{} + for _, domain := range metadata.Domains { + domain = strings.TrimSpace(domain) + if domain == "" || strings.Contains(domain, "/") || strings.Contains(domain, "\\") { + return emptyAgentMetadata() + } + data, err := fs.ReadFile(source, "schema_agent_metadata/"+domain+".json") + if err != nil { + return emptyAgentMetadata() + } + var fragment agentMetadataDomain + if err := json.Unmarshal(data, &fragment); err != nil || strings.TrimSpace(fragment.ProductID) != domain { + return emptyAgentMetadata() + } + for path, tool := range fragment.Tools { + metadata.Tools[path] = tool + } + } + if metadata.Products == nil { + metadata.Products = map[string]agentProductMetadata{} + } + return metadata +} diff --git a/internal/cli/schema_agent_metadata_test.go b/internal/cli/schema_agent_metadata_test.go index e1d242d8..f796bae8 100644 --- a/internal/cli/schema_agent_metadata_test.go +++ b/internal/cli/schema_agent_metadata_test.go @@ -23,13 +23,13 @@ import ( "github.com/spf13/cobra" ) -func TestEmbeddedAgentMetadataLoadsSplitDomains(t *testing.T) { +func TestAgentMetadataFixtureLoadsSplitDomains(t *testing.T) { // Production no longer embeds or ships schema_agent_metadata/*.json. // Runtime Agent metadata must stay empty; selection completeness now lives // in schema_catalog (see TestDeliverySchemaCatalogSelectionCompleteness). metadata := runtimeAgentMetadata() if len(metadata.Tools) != 0 || len(metadata.Products) != 0 || len(metadata.Domains) != 0 { - t.Fatalf("retired embedded Agent metadata must be empty: %#v", metadata) + t.Fatalf("retired Agent metadata snapshot must be empty: %#v", metadata) } // Temporary MapFS fixture only — exercises the retired split-domain loader // seam without depending on a committed schema_agent_metadata/ directory. @@ -37,7 +37,7 @@ func TestEmbeddedAgentMetadataLoadsSplitDomains(t *testing.T) { "schema_agent_metadata/index.json": {Data: []byte(`{"domains":["sample"],"coverage":{"tools_with_metadata":1}}`)}, "schema_agent_metadata/sample.json": {Data: []byte(`{"product_id":"sample","tools":{"sample.get":{"agent_summary":"S","use_when":["u"],"avoid_when":["a"],"examples":["dws sample get"],"interface_mode":"local","availability":"available"}}}`)}, } - loaded := loadEmbeddedAgentMetadataFrom(fixture) + loaded := loadAgentMetadataFixtureFrom(fixture) if len(loaded.Tools) != 1 || loaded.Tools["sample.get"].AgentSummary != "S" { t.Fatalf("fixture loader = %#v", loaded) } @@ -49,7 +49,7 @@ func TestEmbeddedAgentMetadataLoadsSplitDomains(t *testing.T) { // and examples that never bypass confirmation with --yes. func TestDeliverySchemaCatalogSelectionCompleteness(t *testing.T) { if !deliverySchemaCatalogAvailable() { - t.Fatalf("embedded schema Catalog is unavailable: %v", deliverySchemaCatalogError()) + t.Fatalf("delivery schema Catalog is unavailable: %v", deliverySchemaCatalogError()) } loaded := mustDeliverySchemaCatalogMaps(t) products := map[string]struct{}{} @@ -130,7 +130,7 @@ func TestAgentMetadataTypedAccessorRoundTripsProvenance(t *testing.T) { } } }` - var fragment embeddedAgentMetadataDomain + var fragment agentMetadataDomain if err := json.Unmarshal([]byte(encoded), &fragment); err != nil { t.Fatalf("decode generated Agent metadata: %v", err) } @@ -138,12 +138,12 @@ func TestAgentMetadataTypedAccessorRoundTripsProvenance(t *testing.T) { if err != nil { t.Fatalf("encode generated Agent metadata: %v", err) } - var decoded embeddedAgentMetadataDomain + var decoded agentMetadataDomain if err := json.Unmarshal(roundTrip, &decoded); err != nil { t.Fatalf("round-trip generated Agent metadata: %v", err) } - metadataFixture := embeddedAgentMetadata{ + metadataFixture := agentMetadata{ Products: map[string]agentProductMetadata{}, Tools: decoded.Tools, } @@ -158,7 +158,7 @@ func TestAgentMetadataTypedAccessorRoundTripsProvenance(t *testing.T) { if interfaceSpec.Ref == nil || interfaceSpec.Ref.ProductID != "calendar" || interfaceSpec.Ref.RPCName != "update_attendee" || interfaceSpec.Mode != "mcp" || interfaceSpec.Availability != "available" || interfaceSpec.Reason != "reviewed RPC mapping" { t.Fatalf("interface = %#v", interfaceSpec) } - if selection.AgentSummary != "Update one attendee" || selection.MetadataSource != embeddedAgentMetadataSource || selection.Reviewed == nil || !*selection.Reviewed || len(selection.Examples) != 1 { + if selection.AgentSummary != "Update one attendee" || selection.MetadataSource != agentMetadataSource || selection.Reviewed == nil || !*selection.Reviewed || len(selection.Examples) != 1 { t.Fatalf("selection = %#v", selection) } risk := provenance["risk"] @@ -207,7 +207,7 @@ func TestCrossPlatformCoverageAgentMetadataInterfaceProvenance(t *testing.T) { } mode := resolvedFieldProvenance("local", "reviewed.json", "", "reviewed_explicit", "highest_precedence", "reviewed local wrapper") - metadataFixture := embeddedAgentMetadata{ + metadataFixture := agentMetadata{ Products: map[string]agentProductMetadata{}, Tools: map[string]agentToolMetadata{ "calendar event get": { @@ -300,7 +300,7 @@ func TestCrossPlatformCoverageAgentMetadataInterfaceConflict(t *testing.T) { func TestCrossPlatformCoverageAgentProductSelectionAccessor(t *testing.T) { provenance := resolvedFieldProvenance("Document operations", "manual", "manual.json", "reviewed_manual", "highest_precedence", "reviewed") - metadataFixture := embeddedAgentMetadata{ + metadataFixture := agentMetadata{ Products: map[string]agentProductMetadata{ "doc": { AgentSummary: "Document operations", @@ -315,7 +315,7 @@ func TestCrossPlatformCoverageAgentProductSelectionAccessor(t *testing.T) { } selection, ok := agentProductSelectionForIDsFromMetadata(metadataFixture, "missing", " doc ") - if !ok || selection.AgentSummary != "Document operations" || selection.AgentSummarySource != "reviewed-doc-routing" || selection.MetadataSource != embeddedAgentMetadataSource { + if !ok || selection.AgentSummary != "Document operations" || selection.AgentSummarySource != "reviewed-doc-routing" || selection.MetadataSource != agentMetadataSource { t.Fatalf("product selection = %#v, ok=%v", selection, ok) } if len(selection.UseWhen) != 1 || len(selection.SourceRefs) != 2 || selection.SourceRefs[0] != "a.md" { @@ -338,8 +338,8 @@ func TestCrossPlatformCoverageAgentProductSelectionAccessor(t *testing.T) { } -func TestRuntimeSchemaIncludesEmbeddedAgentMetadata(t *testing.T) { - agentFixture := embeddedAgentMetadata{ +func TestRuntimeSchemaIncludesAgentMetadata(t *testing.T) { + agentFixture := agentMetadata{ Version: 1, SourceHash: "sha256:test", Products: map[string]agentProductMetadata{ @@ -371,7 +371,7 @@ func TestRuntimeSchemaIncludesEmbeddedAgentMetadata(t *testing.T) { if err != nil { t.Fatalf("runtimeSchemaPayloadForTest(leaf): %v", err) } - if leaf["effect"] != "write" || leaf["agent_metadata_source"] != embeddedAgentMetadataSource { + if leaf["effect"] != "write" || leaf["agent_metadata_source"] != agentMetadataSource { t.Fatalf("leaf Agent metadata = %#v", leaf) } if leaf["interface_mode"] != "local" || leaf["availability"] != "available" || leaf["interface_reason"] != "test local implementation" { @@ -388,7 +388,7 @@ func TestRuntimeSchemaIncludesEmbeddedAgentMetadata(t *testing.T) { summary, _ := catalog["agent_metadata"].(map[string]any) // Catalog-level Agent summary is derived from assembled products/tools // (ContractFinal / ProductDecl), not from the inject fixture source_hash. - if summary["source"] != embeddedAgentMetadataSource { + if summary["source"] != agentMetadataSource { t.Fatalf("catalog Agent metadata summary = %#v", summary) } if summary["tools_with_metadata"] == nil || summary["products_with_metadata"] == nil { @@ -431,7 +431,7 @@ func TestRuntimeSchemaIncludesEmbeddedAgentMetadata(t *testing.T) { func TestRuntimeSchemaAllPayloadContainsFullLeafParameters(t *testing.T) { // Synthetic fixture has no ContractFinal/ProductDecl; exercise the // test-isolated legacy assembly path (production fails closed). - registry, err := schemaRegistryForTestWithMetadata(buildRuntimeSchemaTestRoot(), emptyEmbeddedAgentMetadata(), embeddedMCPMetadata{}) + registry, err := schemaRegistryForTestWithMetadata(buildRuntimeSchemaTestRoot(), emptyAgentMetadata(), embeddedMCPMetadata{}) if err != nil { t.Fatal(err) } @@ -471,7 +471,7 @@ func TestRuntimeSchemaReportsEmbeddedInterfaceMetadata(t *testing.T) { "doc.create_document": {Description: "创建文档"}, }, } - agentFixture := emptyEmbeddedAgentMetadata() + agentFixture := emptyAgentMetadata() catalog, err := runtimeSchemaPayloadForTestWithMetadata(buildRuntimeSchemaTestRoot(), nil, agentFixture, mcpFixture) if err != nil { @@ -517,7 +517,7 @@ func schemaTestInt(value any) int { } func TestRuntimeSchemaUsesVersionedInterfaceRef(t *testing.T) { - agentFixture := embeddedAgentMetadata{ + agentFixture := agentMetadata{ Tools: map[string]agentToolMetadata{ "doc create": { InterfaceRef: &embeddedMCPInterfaceRef{ProductID: "documents", RPCName: "create_doc_v2"}, @@ -554,7 +554,7 @@ func TestRuntimeSchemaUsesVersionedInterfaceRef(t *testing.T) { func TestMCPRequiredParticipatesInSourcePrecedence(t *testing.T) { required := true - agentFixture := emptyEmbeddedAgentMetadata() + agentFixture := emptyAgentMetadata() mcpFixture := embeddedMCPMetadata{ Tools: map[string]embeddedMCPToolMetadata{ "sample.list_items": { @@ -585,7 +585,7 @@ func TestMCPRequiredParticipatesInSourcePrecedence(t *testing.T) { } func TestMCPDefaultDoesNotOverrideCLIDefault(t *testing.T) { - agentFixture := emptyEmbeddedAgentMetadata() + agentFixture := emptyAgentMetadata() mcpFixture := embeddedMCPMetadata{ Tools: map[string]embeddedMCPToolMetadata{ "sample.list_items": { diff --git a/internal/cli/schema_agent_selection.go b/internal/cli/schema_agent_selection.go index 6c45a7a3..33736bf7 100644 --- a/internal/cli/schema_agent_selection.go +++ b/internal/cli/schema_agent_selection.go @@ -167,8 +167,8 @@ func ValidateAgentSelectionContract(bound BoundCommandRegistry) (AgentSelectionR // contractFinalToolSelection synthesizes selection assertions of a declared // tool from its ContractFinal overlay. -func contractFinalToolSelection(command *cobra.Command) ManualAgentToolSelection { - out := ManualAgentToolSelection{Reviewed: true, Revision: "contract", Reason: "Contract final declaration (corecmd.ContractDecl)"} +func contractFinalToolSelection(command *cobra.Command) AgentToolSelection { + out := AgentToolSelection{Reviewed: true, Revision: "contract", Reason: "Contract final declaration (corecmd.ContractDecl)"} payload, ok := contractfinal.RuntimeContractFinal(command) if !ok || payload.Selection == nil { return out diff --git a/internal/cli/schema_catalog_structure_test.go b/internal/cli/schema_catalog_structure_test.go index a0d1c702..94528d71 100644 --- a/internal/cli/schema_catalog_structure_test.go +++ b/internal/cli/schema_catalog_structure_test.go @@ -31,10 +31,10 @@ func TestDeliverySchemaCatalogStructure(t *testing.T) { loaded := mustDeliverySchemaCatalogMaps(t) data, err := json.Marshal(loaded.Snapshot) if err != nil { - t.Fatalf("marshal embedded catalog snapshot: %v", err) + t.Fatalf("marshal delivery catalog snapshot: %v", err) } if err := ValidateCatalogStructure(data); err != nil { - t.Fatalf("embedded schema catalog violates the unified command structure: %v", err) + t.Fatalf("delivery schema catalog violates the unified command structure: %v", err) } } diff --git a/internal/cli/schema_cross_platform_coverage_final_test.go b/internal/cli/schema_cross_platform_coverage_final_test.go index 4e058c80..b7b92483 100644 --- a/internal/cli/schema_cross_platform_coverage_final_test.go +++ b/internal/cli/schema_cross_platform_coverage_final_test.go @@ -221,7 +221,7 @@ func TestCrossPlatformCoverageFinalChangedStatementGaps(t *testing.T) { t.Run("validateSchemaRegistryAgentMetadata missing summary", func(t *testing.T) { prev := finalSchemaAgentMetadata - finalSchemaAgentMetadata = func() embeddedAgentMetadata { return embeddedAgentMetadata{} } + finalSchemaAgentMetadata = func() agentMetadata { return agentMetadata{} } t.Cleanup(func() { finalSchemaAgentMetadata = prev }) registry := SchemaRegistry{Products: []ProductSpec{{ ID: "sample", diff --git a/internal/cli/schema_cross_platform_coverage_remaining_test.go b/internal/cli/schema_cross_platform_coverage_remaining_test.go index 16978d2b..c791a819 100644 --- a/internal/cli/schema_cross_platform_coverage_remaining_test.go +++ b/internal/cli/schema_cross_platform_coverage_remaining_test.go @@ -22,11 +22,11 @@ func TestCrossPlatformCoverageAgentExampleRemainingBranches(t *testing.T) { t.Run("disposition validation and map build", func(t *testing.T) { bound, registry := crossPlatformAgentExampleFixture(t, nil) t.Cleanup(restoreSelection) - agentExampleSelectionFn = func(cmd *cobra.Command) ManualAgentToolSelection { + agentExampleSelectionFn = func(cmd *cobra.Command) AgentToolSelection { selection := contractFinalToolSelection(cmd) - selection.ExampleDispositions = []ManualAgentExampleDisposition{{ - Index: idx(0), Mode: ManualAgentExampleModeDryRun, Reviewed: true, - Reason: "r", ReasonCode: ManualAgentExampleReasonLocalState, + selection.ExampleDispositions = []AgentExampleDisposition{{ + Index: idx(0), Mode: AgentExampleModeDryRun, Reviewed: true, + Reason: "r", ReasonCode: AgentExampleReasonLocalState, }} return selection } @@ -120,11 +120,11 @@ func TestCrossPlatformCoverageAgentExampleRemainingBranches(t *testing.T) { payload.DryRun = &contract.DryRunSpec{PreviewKind: "plan"} }) t.Cleanup(restoreSelection) - agentExampleSelectionFn = func(cmd *cobra.Command) ManualAgentToolSelection { + agentExampleSelectionFn = func(cmd *cobra.Command) AgentToolSelection { selection := contractFinalToolSelection(cmd) - selection.ExampleDispositions = []ManualAgentExampleDisposition{{ - Index: idx(0), Mode: ManualAgentExampleModeContractOnly, Reviewed: true, - Reason: "cannot dry-run safely", ReasonCode: ManualAgentExampleReasonStatefulPreflight, + selection.ExampleDispositions = []AgentExampleDisposition{{ + Index: idx(0), Mode: AgentExampleModeContractOnly, Reviewed: true, + Reason: "cannot dry-run safely", ReasonCode: AgentExampleReasonStatefulPreflight, }} return selection } @@ -132,10 +132,10 @@ func TestCrossPlatformCoverageAgentExampleRemainingBranches(t *testing.T) { if err != nil { t.Fatalf("plan error = %v", err) } - if plan.ContractOnly != 1 || plan.ReviewedContractOnly != 1 || plan.ContractOnlyByReason[ManualAgentExampleReasonStatefulPreflight] != 1 { + if plan.ContractOnly != 1 || plan.ReviewedContractOnly != 1 || plan.ContractOnlyByReason[AgentExampleReasonStatefulPreflight] != 1 { t.Fatalf("plan = %#v", plan) } - if len(plan.Examples) != 1 || plan.Examples[0].Mode != ManualAgentExampleModeContractOnly { + if len(plan.Examples) != 1 || plan.Examples[0].Mode != AgentExampleModeContractOnly { t.Fatalf("execution = %#v", plan.Examples) } }) @@ -143,11 +143,11 @@ func TestCrossPlatformCoverageAgentExampleRemainingBranches(t *testing.T) { t.Run("disposition without dry_run capability fails", func(t *testing.T) { bound, registry := crossPlatformAgentExampleFixture(t, nil) t.Cleanup(restoreSelection) - agentExampleSelectionFn = func(cmd *cobra.Command) ManualAgentToolSelection { + agentExampleSelectionFn = func(cmd *cobra.Command) AgentToolSelection { selection := contractFinalToolSelection(cmd) - selection.ExampleDispositions = []ManualAgentExampleDisposition{{ - Index: idx(0), Mode: ManualAgentExampleModeContractOnly, Reviewed: true, - Reason: "no dry run", ReasonCode: ManualAgentExampleReasonLocalState, + selection.ExampleDispositions = []AgentExampleDisposition{{ + Index: idx(0), Mode: AgentExampleModeContractOnly, Reviewed: true, + Reason: "no dry run", ReasonCode: AgentExampleReasonLocalState, }} return selection } @@ -699,7 +699,7 @@ func TestCrossPlatformCoverageRuntimeSchemaNormalizeGroups(t *testing.T) { func TestCrossPlatformCoverageSchemaRuntimeRegistryRemainingBranches(t *testing.T) { t.Run("legacy product selection and ContractFinal param decl failure", func(t *testing.T) { entry := runtimeSchemaEntry{ProductID: "legacy", ToolName: "run", Command: &cobra.Command{Use: "run"}} - agent := embeddedAgentMetadata{Products: map[string]agentProductMetadata{ + agent := agentMetadata{Products: map[string]agentProductMetadata{ "legacy": {AgentSummary: "legacy product"}, }} if _, _, err := assembleProductSelection(entry, runtimeSchemaMetadataSources{Agent: agent}, true); err != nil { @@ -946,11 +946,11 @@ func TestCrossPlatformCoverageAgentExamplePlanAndTokenizerRemaining(t *testing.T payload.DryRun = &contract.DryRunSpec{PreviewKind: "plan"} }) t.Cleanup(func() { agentExampleSelectionFn = contractFinalToolSelection }) - agentExampleSelectionFn = func(cmd *cobra.Command) ManualAgentToolSelection { + agentExampleSelectionFn = func(cmd *cobra.Command) AgentToolSelection { selection := contractFinalToolSelection(cmd) - selection.ExampleDispositions = []ManualAgentExampleDisposition{{ - Index: idx(0), Mode: ManualAgentExampleModeContractOnly, Reviewed: true, - Reason: "stateful", ReasonCode: ManualAgentExampleReasonStatefulPreflight, + selection.ExampleDispositions = []AgentExampleDisposition{{ + Index: idx(0), Mode: AgentExampleModeContractOnly, Reviewed: true, + Reason: "stateful", ReasonCode: AgentExampleReasonStatefulPreflight, }} return selection } diff --git a/internal/cli/schema_cross_platform_coverage_test.go b/internal/cli/schema_cross_platform_coverage_test.go index 1cde323f..f0fb5419 100644 --- a/internal/cli/schema_cross_platform_coverage_test.go +++ b/internal/cli/schema_cross_platform_coverage_test.go @@ -160,10 +160,10 @@ func TestCrossPlatformCoverageAgentExampleExecutionPlanErrors(t *testing.T) { } }) - t.Run("BuildManualAgentExampleExecutionPlan wrapper", func(t *testing.T) { + t.Run("BuildAgentExampleExecutionPlan", func(t *testing.T) { bound, registry := crossPlatformAgentExampleFixture(t, nil) - if _, err := BuildManualAgentExampleExecutionPlan(bound, registry, ManualAgentSelectionSet{}); err != nil { - t.Fatalf("BuildManualAgentExampleExecutionPlan() error = %v", err) + if _, err := BuildAgentExampleExecutionPlan(bound, registry); err != nil { + t.Fatalf("BuildAgentExampleExecutionPlan() error = %v", err) } }) @@ -171,19 +171,19 @@ func TestCrossPlatformCoverageAgentExampleExecutionPlanErrors(t *testing.T) { examples := []string{"dws sample run --name x", "dws sample run --name y"} cases := []struct { name string - disp []ManualAgentExampleDisposition + disp []AgentExampleDisposition want string }{ - {"nil index", []ManualAgentExampleDisposition{{Mode: ManualAgentExampleModeContractOnly, Reviewed: true, Reason: "r", ReasonCode: ManualAgentExampleReasonLocalState}}, "requires index"}, - {"out of range", []ManualAgentExampleDisposition{{Index: idx(9), Mode: ManualAgentExampleModeContractOnly, Reviewed: true, Reason: "r", ReasonCode: ManualAgentExampleReasonLocalState}}, "out of range"}, - {"duplicate index", []ManualAgentExampleDisposition{ - {Index: idx(0), Mode: ManualAgentExampleModeContractOnly, Reviewed: true, Reason: "r", ReasonCode: ManualAgentExampleReasonLocalState}, - {Index: idx(0), Mode: ManualAgentExampleModeContractOnly, Reviewed: true, Reason: "r2", ReasonCode: ManualAgentExampleReasonLocalState}, + {"nil index", []AgentExampleDisposition{{Mode: AgentExampleModeContractOnly, Reviewed: true, Reason: "r", ReasonCode: AgentExampleReasonLocalState}}, "requires index"}, + {"out of range", []AgentExampleDisposition{{Index: idx(9), Mode: AgentExampleModeContractOnly, Reviewed: true, Reason: "r", ReasonCode: AgentExampleReasonLocalState}}, "out of range"}, + {"duplicate index", []AgentExampleDisposition{ + {Index: idx(0), Mode: AgentExampleModeContractOnly, Reviewed: true, Reason: "r", ReasonCode: AgentExampleReasonLocalState}, + {Index: idx(0), Mode: AgentExampleModeContractOnly, Reviewed: true, Reason: "r2", ReasonCode: AgentExampleReasonLocalState}, }, "duplicate example disposition"}, - {"not reviewed", []ManualAgentExampleDisposition{{Index: idx(0), Mode: ManualAgentExampleModeContractOnly, Reviewed: false, Reason: "r", ReasonCode: ManualAgentExampleReasonLocalState}}, "must be reviewed"}, - {"invalid mode", []ManualAgentExampleDisposition{{Index: idx(0), Mode: ManualAgentExampleModeDryRun, Reviewed: true, Reason: "r", ReasonCode: ManualAgentExampleReasonLocalState}}, "invalid mode"}, - {"invalid reason_code", []ManualAgentExampleDisposition{{Index: idx(0), Mode: ManualAgentExampleModeContractOnly, Reviewed: true, Reason: "r", ReasonCode: "bogus"}}, "invalid reason_code"}, - {"empty reason", []ManualAgentExampleDisposition{{Index: idx(0), Mode: ManualAgentExampleModeContractOnly, Reviewed: true, Reason: " ", ReasonCode: ManualAgentExampleReasonLocalState}}, "non-empty reason"}, + {"not reviewed", []AgentExampleDisposition{{Index: idx(0), Mode: AgentExampleModeContractOnly, Reviewed: false, Reason: "r", ReasonCode: AgentExampleReasonLocalState}}, "must be reviewed"}, + {"invalid mode", []AgentExampleDisposition{{Index: idx(0), Mode: AgentExampleModeDryRun, Reviewed: true, Reason: "r", ReasonCode: AgentExampleReasonLocalState}}, "invalid mode"}, + {"invalid reason_code", []AgentExampleDisposition{{Index: idx(0), Mode: AgentExampleModeContractOnly, Reviewed: true, Reason: "r", ReasonCode: "bogus"}}, "invalid reason_code"}, + {"empty reason", []AgentExampleDisposition{{Index: idx(0), Mode: AgentExampleModeContractOnly, Reviewed: true, Reason: " ", ReasonCode: AgentExampleReasonLocalState}}, "non-empty reason"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { @@ -193,15 +193,15 @@ func TestCrossPlatformCoverageAgentExampleExecutionPlanErrors(t *testing.T) { } }) } - if !validAgentExampleReasonCode(ManualAgentExampleReasonLocalState) || validAgentExampleReasonCode("nope") { + if !validAgentExampleReasonCode(AgentExampleReasonLocalState) || validAgentExampleReasonCode("nope") { t.Fatal("validAgentExampleReasonCode mismatch") } }) - t.Run("tokenizeAgentExample and ParseManualAgentExampleArgv", func(t *testing.T) { - argv, err := ParseManualAgentExampleArgv(`dws sample run --name "a b"`) + t.Run("tokenizeAgentExample and ParseAgentExampleArgv", func(t *testing.T) { + argv, err := ParseAgentExampleArgv(`dws sample run --name "a b"`) if err != nil || len(argv) != 5 || argv[4] != "a b" { - t.Fatalf("ParseManualAgentExampleArgv() = %#v, %v", argv, err) + t.Fatalf("ParseAgentExampleArgv() = %#v, %v", argv, err) } placeholder, err := tokenizeAgentExample(`dws sample run --file `) if err != nil || placeholder[len(placeholder)-1] != "" { @@ -494,7 +494,7 @@ func TestCrossPlatformCoverageSchemaRuntimeRegistryLegacyAndPayload(t *testing.T for _, command := range bound.Commands { contractfinal.ClearRuntimeContractFinalForTest(command.PrimaryCommand) } - agent := embeddedAgentMetadata{ + agent := agentMetadata{ Version: 1, Products: map[string]agentProductMetadata{"doc": {AgentSummary: "docs", UseWhen: []string{"read docs"}}}, Tools: map[string]agentToolMetadata{ @@ -585,11 +585,11 @@ func TestCrossPlatformCoverageSchemaAgentMetadataInstallAndLoad(t *testing.T) { "schema_agent_metadata/index.json": {Data: []byte(`{"domains":["sample"],"coverage":{"tools_with_metadata":1}}`)}, "schema_agent_metadata/sample.json": {Data: []byte(`{"product_id":"sample","tools":{"sample.get":{"agent_summary":"S","use_when":["u"],"avoid_when":["a"],"examples":["dws sample get"],"interface_mode":"local","availability":"available"}}}`)}, } - loaded := loadEmbeddedAgentMetadataFrom(fixture) + loaded := loadAgentMetadataFixtureFrom(fixture) if len(loaded.Tools) != 1 { t.Fatalf("loaded = %#v", loaded) } - if loadEmbeddedAgentMetadataFrom(fstest.MapFS{"schema_agent_metadata/index.json": {Data: []byte(`{"domains":["bad/name"]}`)}}).Tools == nil { + if loadAgentMetadataFixtureFrom(fstest.MapFS{"schema_agent_metadata/index.json": {Data: []byte(`{"domains":["bad/name"]}`)}}).Tools == nil { t.Fatal("invalid domain must return empty metadata") } @@ -692,7 +692,7 @@ func TestCrossPlatformCoverageSchemaCanonicalPathAndParamAliases(t *testing.T) { func TestCrossPlatformCoverageDeliverySchemaCatalogDelivery(t *testing.T) { if !deliverySchemaCatalogAvailable() { - t.Fatalf("embedded catalog unavailable: %v", deliverySchemaCatalogError()) + t.Fatalf("delivery catalog unavailable: %v", deliverySchemaCatalogError()) } loaded := deliverySchemaCatalog() if loaded.Registry.Source != SchemaSourceRuntimeAssembled { @@ -808,7 +808,7 @@ func TestCrossPlatformCoverageRuntimeSchemaPayloadGroupAndProduct(t *testing.T) for _, command := range bound.Commands { contractfinal.ClearRuntimeContractFinalForTest(command.PrimaryCommand) } - agent := embeddedAgentMetadata{ + agent := agentMetadata{ Tools: map[string]agentToolMetadata{ "doc create": {Effect: "write", InterfaceMode: "local", Availability: "available", InterfaceReason: "test", AgentSummary: "create"}, }, diff --git a/internal/cli/schema_hint_emptiness_contract_test.go b/internal/cli/schema_hint_emptiness_contract_test.go index 06836c09..cf5f3694 100644 --- a/internal/cli/schema_hint_emptiness_contract_test.go +++ b/internal/cli/schema_hint_emptiness_contract_test.go @@ -62,7 +62,7 @@ func TestSchemaHintsDirectoryRetired(t *testing.T) { // retained candidate after RegisterSchemaHints → contract.ParamDecl migration. func TestDeliveryCatalogHasNoToolSchemaHintProvenance(t *testing.T) { if !deliverySchemaCatalogAvailable() { - t.Fatal("embedded schema catalog unavailable") + t.Fatal("delivery schema Catalog unavailable") } loaded := deliverySchemaCatalog() hits := make([]string, 0) diff --git a/internal/cli/schema_lazy_metadata.go b/internal/cli/schema_lazy_metadata.go index dab04254..0d4f6735 100644 --- a/internal/cli/schema_lazy_metadata.go +++ b/internal/cli/schema_lazy_metadata.go @@ -20,7 +20,7 @@ func RuntimeSchemaMetadataLoadCounts() SchemaMetadataLoadCounts { return SchemaMetadataLoadCounts{ Catalog: runtimeDeliverySchemaCatalogLazyCount.Load(), MetaIndex: runtimeDeliverySchemaMetaIndexLazyCount.Load(), - AgentMetadata: runtimeEmbeddedAgentMetadataLazyLoadCount.Load(), + AgentMetadata: runtimeAgentMetadataLazyLoadCount.Load(), MCPMetadata: runtimeEmbeddedMCPMetadataLazyLoadCount.Load(), ParameterBinding: runtimeSchemaParameterBindingsLazyLoadCount.Load(), } diff --git a/internal/cli/schema_lazy_metadata_test.go b/internal/cli/schema_lazy_metadata_test.go index 9d769f05..e833cfe9 100644 --- a/internal/cli/schema_lazy_metadata_test.go +++ b/internal/cli/schema_lazy_metadata_test.go @@ -22,7 +22,7 @@ func TestRuntimeSchemaMetadataLoadsOnlyOnDemand(t *testing.T) { // Package-cli TestMain may assemble Catalog via cmd_schema_catalog dump // decode; that must not force Agent / parameter-binding loads. MCP may // already be touched by assembly-related validation — record baseline. - agentBefore := runtimeEmbeddedAgentMetadataLazyLoadCount.Load() + agentBefore := runtimeAgentMetadataLazyLoadCount.Load() mcpBefore := runtimeEmbeddedMCPMetadataLazyLoadCount.Load() paramBefore := runtimeSchemaParameterBindingsLazyLoadCount.Load() if agentBefore != 0 { @@ -44,7 +44,7 @@ func TestRuntimeSchemaMetadataLoadsOnlyOnDemand(t *testing.T) { } wait.Wait() - if got := runtimeEmbeddedAgentMetadataLazyLoadCount.Load(); got != 1 { + if got := runtimeAgentMetadataLazyLoadCount.Load(); got != 1 { t.Fatalf("Agent metadata lazy load count = %d, want 1", got) } if got := runtimeEmbeddedMCPMetadataLazyLoadCount.Load(); got != mcpBefore+1 && got != 1 { diff --git a/internal/cli/schema_parameter_mapping_completeness_test.go b/internal/cli/schema_parameter_mapping_completeness_test.go index be6c4add..d490d0ad 100644 --- a/internal/cli/schema_parameter_mapping_completeness_test.go +++ b/internal/cli/schema_parameter_mapping_completeness_test.go @@ -28,7 +28,7 @@ type schemaParameterMappingFlagAudit struct { func TestDeliveryCatalogMCPParameterMappingsAreComplete(t *testing.T) { loaded := mustDeliverySchemaCatalogMaps(t) if !deliverySchemaCatalogAvailable() { - t.Fatalf("embedded schema Catalog is unavailable: %v", deliverySchemaCatalogError()) + t.Fatalf("delivery schema Catalog is unavailable: %v", deliverySchemaCatalogError()) } bindings, err := runtimeSchemaParameterBindingData() if err != nil { @@ -47,7 +47,7 @@ func TestDeliveryCatalogMCPParameterMappingsAreComplete(t *testing.T) { func TestDeliveryCatalogDoesNotProjectHardRequiredFlagsAsOptional(t *testing.T) { loaded := mustDeliverySchemaCatalogMaps(t) if !deliverySchemaCatalogAvailable() { - t.Fatalf("embedded schema Catalog is unavailable: %v", deliverySchemaCatalogError()) + t.Fatalf("delivery schema Catalog is unavailable: %v", deliverySchemaCatalogError()) } var problems []string for canonical, tool := range loaded.Snapshot.Tools { @@ -78,7 +78,7 @@ func TestDeliveryCatalogLocalInterfacesAreExactAndReviewed(t *testing.T) { } loaded := mustDeliverySchemaCatalogMaps(t) if !deliverySchemaCatalogAvailable() { - t.Fatalf("embedded schema Catalog is unavailable: %v", deliverySchemaCatalogError()) + t.Fatalf("delivery schema Catalog is unavailable: %v", deliverySchemaCatalogError()) } gotLocal := make(map[string]bool) for canonical, tool := range loaded.Snapshot.Tools { diff --git a/internal/cli/schema_registry_test_helpers_test.go b/internal/cli/schema_registry_test_helpers_test.go index 57a83752..32128547 100644 --- a/internal/cli/schema_registry_test_helpers_test.go +++ b/internal/cli/schema_registry_test_helpers_test.go @@ -68,7 +68,7 @@ func schemaRegistryForTest(root *cobra.Command) (SchemaRegistry, error) { return AssembleSchemaRegistryFromBound(bound) } -func schemaRegistryForTestWithMetadata(root *cobra.Command, agent embeddedAgentMetadata, mcp embeddedMCPMetadata) (SchemaRegistry, error) { +func schemaRegistryForTestWithMetadata(root *cobra.Command, agent agentMetadata, mcp embeddedMCPMetadata) (SchemaRegistry, error) { bound, err := boundTestCommandRegistry(root) if err != nil { return SchemaRegistry{}, err @@ -93,7 +93,7 @@ func runtimeSchemaPayloadForTest(root *cobra.Command, args []string) (map[string return runtimeSchemaPayloadFromRegistry(registry, args) } -func runtimeSchemaPayloadForTestWithMetadata(root *cobra.Command, args []string, agent embeddedAgentMetadata, mcp embeddedMCPMetadata) (map[string]any, error) { +func runtimeSchemaPayloadForTestWithMetadata(root *cobra.Command, args []string, agent agentMetadata, mcp embeddedMCPMetadata) (map[string]any, error) { registry, err := schemaRegistryForTestWithMetadata(root, agent, mcp) if err != nil { return nil, err diff --git a/internal/cli/schema_runtime_registry.go b/internal/cli/schema_runtime_registry.go index bdaa779d..974734d6 100644 --- a/internal/cli/schema_runtime_registry.go +++ b/internal/cli/schema_runtime_registry.go @@ -16,7 +16,7 @@ import ( ) type runtimeSchemaMetadataSources struct { - Agent embeddedAgentMetadata + Agent agentMetadata MCP embeddedMCPMetadata } diff --git a/internal/cli/schema_runtime_registry_contract_test.go b/internal/cli/schema_runtime_registry_contract_test.go index 162f2920..f0434bf4 100644 --- a/internal/cli/schema_runtime_registry_contract_test.go +++ b/internal/cli/schema_runtime_registry_contract_test.go @@ -166,7 +166,7 @@ func TestAssembleSchemaRegistryAllowingLegacyIsolatesOverlayPath(t *testing.T) { for _, command := range bound.Commands { contractfinal.ClearRuntimeContractFinalForTest(command.PrimaryCommand) } - agent := embeddedAgentMetadata{ + agent := agentMetadata{ Version: 1, Products: map[string]agentProductMetadata{ "doc": {AgentSummary: "docs", UseWhen: []string{"read docs"}}, diff --git a/internal/cli/schema_source_root_coverage_test.go b/internal/cli/schema_source_root_coverage_test.go index de2a55b9..4f235220 100644 --- a/internal/cli/schema_source_root_coverage_test.go +++ b/internal/cli/schema_source_root_coverage_test.go @@ -137,7 +137,7 @@ func TestCrossPlatformCoverageMCPMetadataInterfaceRefEdges(t *testing.T) { if _, ok := mcpMetadataForInterfaceRef(embeddedMCPMetadata{Tools: map[string]embeddedMCPToolMetadata{}}, "chat", "missing"); ok { t.Fatal("missing MCP tool must miss") } - agent := embeddedAgentMetadata{Tools: map[string]agentToolMetadata{ + agent := agentMetadata{Tools: map[string]agentToolMetadata{ "chat reply": {InterfaceRef: &embeddedMCPInterfaceRef{ProductID: "chat", RPCName: "send_personal_message"}}, }} mcp := embeddedMCPMetadata{Tools: map[string]embeddedMCPToolMetadata{ diff --git a/scripts/policy/check-schema-command-registry.sh b/scripts/policy/check-schema-command-registry.sh index 89ea5174..1c9c9e59 100755 --- a/scripts/policy/check-schema-command-registry.sh +++ b/scripts/policy/check-schema-command-registry.sh @@ -70,7 +70,7 @@ fi # exactly two production locations: its declaration and the assignment inside # that accessor. Any third reference is an eager initializer or an accessor # bypass and fails this static check. -# Agent metadata embed/loader is retired; production must not reopen it. +# Agent metadata JSON embed/loader is retired; production must not reopen it. if policy_search_production_go 'go:embed schema_agent_metadata' internal/cli; then printf '%s\n' 'schema_agent_metadata must not be re-embedded' >&2 exit 1 @@ -79,6 +79,10 @@ if policy_search_production_go 'loadEmbeddedAgentMetadata\(' internal/cli; then printf '%s\n' 'retired loadEmbeddedAgentMetadata must not remain in production code' >&2 exit 1 fi +if policy_search_production_go 'loadAgentMetadataFixtureFrom\(' internal/cli; then + printf '%s\n' 'Agent metadata fixture loader must stay test-only' >&2 + exit 1 +fi check_schema_loader_references() { loader="$1" allowed="$2"