diff --git a/pkg/workflow/agentic_engine.go b/pkg/workflow/agentic_engine.go index 38b8900bc31..10ca7bfd2dd 100644 --- a/pkg/workflow/agentic_engine.go +++ b/pkg/workflow/agentic_engine.go @@ -101,6 +101,11 @@ type Engine interface { // IsExperimental returns true if this engine is experimental IsExperimental() bool + // IsUndocumented returns true if this engine is intentionally excluded from + // public reference documentation and schema drift checks. + // Drift detectors must skip engines where IsUndocumented() returns true. + IsUndocumented() bool + // GetGHSkillAgentName returns the gh skill --agent value for this engine. // Returns an empty string when gh skill install does not support the engine. GetGHSkillAgentName() string @@ -314,10 +319,16 @@ type CodingAgentEngine interface { // BaseEngine provides common functionality for agentic engines type BaseEngine struct { - id string - displayName string - description string - experimental bool + id string + displayName string + description string + experimental bool + // undocumented marks the engine as intentionally excluded from public reference + // documentation (engines.md) and schema drift checks. Drift detectors must skip + // engines where IsUndocumented() returns true rather than re-filing reconciliation + // issues. Defaults to false; only set to true when a maintainer has decided the + // engine should not appear in public docs. + undocumented bool ghSkillAgentName string capabilities EngineCapabilities dedicatedLLMGatewayPort int @@ -339,6 +350,10 @@ func (e *BaseEngine) IsExperimental() bool { return e.experimental } +func (e *BaseEngine) IsUndocumented() bool { + return e.undocumented +} + func (e *BaseEngine) GetGHSkillAgentName() string { return e.ghSkillAgentName } @@ -554,6 +569,22 @@ func (r *EngineRegistry) GetSupportedEngines() []string { return engines } +// GetDocumentedEngines returns a sorted list of engine IDs that are documented in the +// public reference (engines.md) and included in schema drift checks. +// Engines marked with undocumented: true are intentionally excluded and must not be +// re-added by automated drift detectors or documentation healers. +func (r *EngineRegistry) GetDocumentedEngines() []string { + agenticEngineLog.Print("Getting list of documented engines") + var ids []string + for id, engine := range r.engines { + if !engine.IsUndocumented() { + ids = append(ids, id) + } + } + sort.Strings(ids) + return ids +} + // IsValidEngine checks if an engine ID is valid func (r *EngineRegistry) IsValidEngine(id string) bool { _, exists := r.engines[id] diff --git a/pkg/workflow/agentic_engine_test.go b/pkg/workflow/agentic_engine_test.go index 0c2f99ad76a..862db751902 100644 --- a/pkg/workflow/agentic_engine_test.go +++ b/pkg/workflow/agentic_engine_test.go @@ -67,6 +67,21 @@ func TestEngineRegistry(t *testing.T) { assert.Equal(t, "copilot", defaultEngine.GetID(), "default engine should be copilot") }) + t.Run("GetDocumentedEngines excludes undocumented engines", func(t *testing.T) { + registry := NewEngineRegistry() + documented := registry.GetDocumentedEngines() + + // antigravity is registered but intentionally undocumented + assert.NotContains(t, documented, "antigravity", + "GetDocumentedEngines must exclude antigravity (undocumented: true)") + + // all other built-in engines must be present + expected := []string{"claude", "codex", "copilot", "crush", "gemini", "opencode", "pi"} + for _, id := range expected { + assert.Contains(t, documented, id, "GetDocumentedEngines should include %q", id) + } + }) + t.Run("GetEngineByPrefix matches engine", func(t *testing.T) { registry := NewEngineRegistry() engine, err := registry.GetEngineByPrefix("codex-experimental") diff --git a/pkg/workflow/antigravity_engine.go b/pkg/workflow/antigravity_engine.go index 6af5458e6b1..5d177012d77 100644 --- a/pkg/workflow/antigravity_engine.go +++ b/pkg/workflow/antigravity_engine.go @@ -19,10 +19,14 @@ type AntigravityEngine struct { func NewAntigravityEngine() *AntigravityEngine { return &AntigravityEngine{ BaseEngine: BaseEngine{ - id: "antigravity", - displayName: "Antigravity CLI", - description: "Antigravity CLI with headless mode and LLM gateway support", - experimental: true, + id: "antigravity", + displayName: "Antigravity CLI", + description: "Antigravity CLI with headless mode and LLM gateway support", + experimental: true, + // undocumented: the maintainer decision (closed-unmerged PR #42294) is that + // the antigravity engine must not appear in engines.md or the schema. + // Set true so drift detectors skip this engine and do not re-file docs issues. + undocumented: true, ghSkillAgentName: "antigravity", capabilities: EngineCapabilities{ ToolsAllowlist: true, diff --git a/pkg/workflow/antigravity_engine_test.go b/pkg/workflow/antigravity_engine_test.go index c364e1d2f1a..668cae38097 100644 --- a/pkg/workflow/antigravity_engine_test.go +++ b/pkg/workflow/antigravity_engine_test.go @@ -18,6 +18,7 @@ func TestAntigravityEngine(t *testing.T) { assert.Equal(t, "Antigravity CLI", engine.GetDisplayName(), "Display name should be 'Antigravity CLI'") assert.NotEmpty(t, engine.GetDescription(), "Description should not be empty") assert.True(t, engine.IsExperimental(), "Antigravity engine should be experimental") + assert.True(t, engine.IsUndocumented(), "Antigravity engine should be marked undocumented") }) t.Run("capabilities", func(t *testing.T) { diff --git a/pkg/workflow/spec_test.go b/pkg/workflow/spec_test.go index fb1e03dfd4a..6b615a85723 100644 --- a/pkg/workflow/spec_test.go +++ b/pkg/workflow/spec_test.go @@ -274,14 +274,15 @@ func TestSpec_Engine_RegistryLookupAndIdentity(t *testing.T) { // TestSpec_Engine_DocumentedEnginesRegistered validates that every AI engine documented // in the workflow package README.md is registered and reports the documented identity. // Spec: the engine architecture lists copilot, claude, codex, gemini, crush, opencode, -// pi, and antigravity engines, each created by a NewEngine constructor. +// and pi engines, each created by a NewEngine constructor. +// Note: antigravity is registered but intentionally excluded from public docs (IsUndocumented() == true). func TestSpec_Engine_DocumentedEnginesRegistered(t *testing.T) { registry := workflow.GetGlobalEngineRegistry() require.NotNil(t, registry, "GetGlobalEngineRegistry() must return a non-nil registry") documentedEngines := []string{ "copilot", "claude", "codex", "gemini", - "crush", "opencode", "pi", "antigravity", + "crush", "opencode", "pi", } for _, id := range documentedEngines { @@ -291,10 +292,30 @@ func TestSpec_Engine_DocumentedEnginesRegistered(t *testing.T) { require.NotNil(t, engine, "documented engine %q must be non-nil", id) assert.Equal(t, id, engine.GetID(), "engine %q must report its documented ID via GetID()", id) + assert.False(t, engine.IsUndocumented(), + "engine %q must not be marked undocumented", id) }) } } +// TestSpec_Engine_AntigravityIsUndocumented validates that the antigravity engine is +// registered but intentionally excluded from public reference documentation and schema +// drift checks (IsUndocumented() == true). This records the maintainer decision from +// closed-unmerged PR #42294 in code so drift detectors do not re-file docs issues. +func TestSpec_Engine_AntigravityIsUndocumented(t *testing.T) { + registry := workflow.GetGlobalEngineRegistry() + require.NotNil(t, registry, "GetGlobalEngineRegistry() must return a non-nil registry") + + engine, err := registry.GetEngine("antigravity") + require.NoError(t, err, "antigravity engine must still be registered for runtime use") + require.NotNil(t, engine, "antigravity engine must be non-nil") + + assert.True(t, engine.IsUndocumented(), + "antigravity must be marked undocumented so drift detectors skip it") + assert.NotContains(t, registry.GetDocumentedEngines(), "antigravity", + "GetDocumentedEngines() must exclude antigravity") +} + // TestSpec_Engine_GlobalRegistrySingleton validates the documented thread-safety contract that // GetGlobalEngineRegistry returns a singleton initialized once at startup. // Spec ("Thread Safety"): "The GetGlobalEngineRegistry() singleton is initialized once at startup