Compare commits

...
Author SHA1 Message Date
m f63c4bb40c feat: connect creator research to truth runtime
CI / test (push) Successful in 1m9s
CI / test (pull_request) Successful in 1m8s
2026-08-23 16:27:00 +03:00
m 22f839df99 Merge pull request 'feat: expose controlled provider discovery status' (#205) from codex/dev-000228-controlled-discovery into main
CI / test (push) Successful in 1m9s
feat: expose controlled provider discovery status
2026-08-23 12:57:48 +00:00
m c41634a065 feat: expose controlled provider discovery status
CI / test (push) Successful in 1m5s
CI / test (pull_request) Successful in 1m2s
2026-08-23 15:54:30 +03:00
m 2609f31e59 Merge pull request 'feat: expose bounded local agent executor' (#204) from codex/dev-000227-local-executor into main
CI / test (push) Successful in 1m10s
feat: expose bounded local agent executor
2026-08-23 12:48:40 +00:00
m 7aa41b3be2 feat: expose bounded local agent executor
CI / test (push) Successful in 1m8s
CI / test (pull_request) Successful in 1m6s
2026-08-23 15:45:00 +03:00
m 1f6ca363ee docs: record authenticated UI acceptance evidence
CI / test (push) Successful in 1m14s
Merge DEV-000226 authenticated UI acceptance evidence
2026-08-23 12:31:16 +00:00
17 changed files with 338 additions and 31 deletions
+8 -8
View File
@@ -7,26 +7,26 @@ import (
"git.cin.su/m/Assistant/contracts/work"
)
// localFallbackExecutor keeps the durable work path alive when no external
// executor is reachable. It never claims that an external action happened.
// The work owner records the WAITING callback and can retry after a bridge is
// localExecutor provides the bounded local execution capability. It never
// claims that an unsupported or external action happened. The work owner
// records the WAITING callback and can retry after a suitable executor is
// configured or a human chooses the next step.
type localFallbackExecutor struct {
type localExecutor struct {
now func() time.Time
}
func newLocalFallbackExecutor() localFallbackExecutor {
return localFallbackExecutor{now: time.Now}
func newLocalExecutor() localExecutor {
return localExecutor{now: time.Now}
}
func (e localFallbackExecutor) Execute(_ context.Context, request work.AgentExecutionRequest) (work.AgentExecutionResult, error) {
func (e localExecutor) Execute(_ context.Context, request work.AgentExecutionRequest) (work.AgentExecutionResult, error) {
now := time.Now()
if e.now != nil {
now = e.now()
}
return work.AgentExecutionResult{
State: work.AgentExecutionWaiting,
Summary: "Внешний Agent Execution Bridge недоступен; локальный fallback сохранил durable работу и ожидает исполнителя.",
Summary: "Локальный исполнитель не поддерживает эту операцию; durable работа сохранена и ожидает подходящего исполнителя.",
ObservedAtUnixMillis: now.UnixMilli(),
}, nil
}
+3 -3
View File
@@ -8,9 +8,9 @@ import (
"git.cin.su/m/Assistant/contracts/work"
)
func TestLocalFallbackNeverClaimsExternalExecution(t *testing.T) {
func TestLocalExecutorNeverClaimsUnsupportedExecution(t *testing.T) {
when := time.UnixMilli(1_700_000_000_000)
executor := localFallbackExecutor{now: func() time.Time { return when }}
executor := localExecutor{now: func() time.Time { return when }}
result, err := executor.Execute(context.Background(), work.AgentExecutionRequest{Intent: work.AgentDispatchIntent{DispatchID: "dispatch-1"}})
if err != nil {
t.Fatal(err)
@@ -19,6 +19,6 @@ func TestLocalFallbackNeverClaimsExternalExecution(t *testing.T) {
t.Fatalf("unexpected fallback result: %+v", result)
}
if result.OutcomeRef != "" || result.Summary == "" {
t.Fatalf("fallback must not claim an outcome: %+v", result)
t.Fatalf("local executor must not claim an outcome: %+v", result)
}
}
+3 -2
View File
@@ -49,8 +49,9 @@ func main() {
os.Exit(1)
}
} else {
// The local evaluator keeps task-qualification work alive, but it is not
// an external Agent Execution Bridge and must never be reported as one.
// The local executor keeps supported task-qualification work alive, but
// it is not an external Agent Execution Bridge and must never be reported
// as one. Unsupported work remains durably WAITING.
localFallback = true
executor = newTaskEvaluationExecutor(envOr("COGNITIVE_WORKER_URL", "http://cognitive-worker:8083"), envOr("WORK_GRAPH_RUNTIME_URL", "http://work-graph-runtime:8088"), envOr("TASK_VERIFIER_URL", "http://task-verifier:8091"), &http.Client{Timeout: *leaseTTL})
fmt.Fprintln(os.Stderr, "protected agent execution bridge URL is not configured; task evaluations use the local durable evaluator, other work remains in fallback")
+12 -8
View File
@@ -6,12 +6,14 @@ import (
)
type workerStatusResponse struct {
Runtime string `json:"runtime"`
ExecutorConfigured bool `json:"executor_configured"`
Mode string `json:"mode"`
Ready bool `json:"ready"`
Reason string `json:"reason"`
LocalFallback bool `json:"local_fallback"`
Runtime string `json:"runtime"`
ExecutorConfigured bool `json:"executor_configured"`
Mode string `json:"mode"`
Ready bool `json:"ready"`
Reason string `json:"reason"`
LocalFallback bool `json:"local_fallback"`
LocalExecutor bool `json:"local_executor"`
Capabilities []string `json:"capabilities,omitempty"`
}
func workerStatusHandler(executorConfigured bool, localFallback ...bool) http.Handler {
@@ -23,10 +25,12 @@ func workerStatusHandler(executorConfigured bool, localFallback ...bool) http.Ha
Ready: false,
Reason: "protected agent execution bridge URL is not configured",
LocalFallback: local,
LocalExecutor: local,
}
if local {
status.Mode = "local-fallback"
status.Reason = "external bridge unavailable; durable work is retained without external mutation"
status.Mode = "local-executor"
status.Reason = "bounded local task-evaluation executor is active; unsupported work remains durably waiting"
status.Capabilities = []string{"task-evaluation"}
}
if executorConfigured {
status.Mode = "execution"
+6 -3
View File
@@ -38,16 +38,19 @@ func TestWorkerStatusReportsRecoveryOnlyWithoutExecutor(t *testing.T) {
}
}
func TestWorkerStatusReportsLocalFallback(t *testing.T) {
func TestWorkerStatusReportsLocalExecutor(t *testing.T) {
response := httptest.NewRecorder()
workerStatusHandler(false, true).ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/status", nil))
var value workerStatusResponse
if err := json.NewDecoder(response.Body).Decode(&value); err != nil {
t.Fatal(err)
}
if response.Code != http.StatusOK || value.Ready || value.Mode != "local-fallback" || !value.LocalFallback {
if response.Code != http.StatusOK || value.Ready || value.Mode != "local-executor" || !value.LocalFallback || !value.LocalExecutor {
t.Fatalf("unexpected status: code=%d value=%+v", response.Code, value)
}
if len(value.Capabilities) != 1 || value.Capabilities[0] != "task-evaluation" {
t.Fatalf("unexpected local capabilities: %+v", value.Capabilities)
}
}
func TestWorkerStatusDoesNotCallLocalFallbackAnExternalExecutor(t *testing.T) {
@@ -57,7 +60,7 @@ func TestWorkerStatusDoesNotCallLocalFallbackAnExternalExecutor(t *testing.T) {
if err := json.NewDecoder(response.Body).Decode(&value); err != nil {
t.Fatal(err)
}
if value.ExecutorConfigured || value.Ready || !value.LocalFallback || value.Mode != "local-fallback" {
if value.ExecutorConfigured || value.Ready || !value.LocalFallback || !value.LocalExecutor || value.Mode != "local-executor" {
t.Fatalf("local fallback was presented as external execution: %+v", value)
}
}
+2 -2
View File
@@ -20,14 +20,14 @@ type taskEvaluationExecutor struct {
callbackURL string
verifierURL string
client *http.Client
fallback localFallbackExecutor
fallback localExecutor
}
func newTaskEvaluationExecutor(cognitiveURL, callbackURL, verifierURL string, client *http.Client) taskEvaluationExecutor {
if client == nil {
client = http.DefaultClient
}
return taskEvaluationExecutor{cognitiveURL: strings.TrimRight(cognitiveURL, "/"), callbackURL: strings.TrimRight(callbackURL, "/"), verifierURL: strings.TrimRight(verifierURL, "/"), client: client, fallback: newLocalFallbackExecutor()}
return taskEvaluationExecutor{cognitiveURL: strings.TrimRight(cognitiveURL, "/"), callbackURL: strings.TrimRight(callbackURL, "/"), verifierURL: strings.TrimRight(verifierURL, "/"), client: client, fallback: newLocalExecutor()}
}
func (e taskEvaluationExecutor) Execute(ctx context.Context, request work.AgentExecutionRequest) (work.AgentExecutionResult, error) {
+44
View File
@@ -3,6 +3,7 @@ package main
import (
"encoding/json"
"net/http"
"sort"
"time"
"git.cin.su/m/Assistant/contracts/capability"
@@ -17,6 +18,10 @@ type discoveryService struct {
}
func (s discoveryService) handler(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet && r.URL.Path == "/v1/provider-discovery/status" {
s.statusHandler(w, r)
return
}
registration, ok := s.providers[r.PathValue("provider")]
if !ok || registration.Discovery == nil {
http.Error(w, "provider discovery not found", http.StatusNotFound)
@@ -35,3 +40,42 @@ func (s discoveryService) handler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(result)
}
type discoveryStatus struct {
Provider string `json:"provider"`
ProviderKind capability.ProviderKind `json:"provider_kind"`
Health capability.HealthState `json:"health"`
FailureClass capability.CognitiveFailureType `json:"failure_class,omitempty"`
ObservedAtUnixMillis int64 `json:"observed_at_unix_millis"`
Models []discoveredModelStatus `json:"models"`
}
type discoveredModelStatus struct {
ProviderModelID capability.ProviderModelID `json:"provider_model_id"`
Fingerprint capability.ModelFingerprint `json:"fingerprint,omitempty"`
Capabilities []capability.ModelCapability `json:"capabilities,omitempty"`
}
func (s discoveryService) statusHandler(w http.ResponseWriter, r *http.Request) {
providers := make([]string, 0, len(s.providers))
for name := range s.providers {
providers = append(providers, name)
}
sort.Strings(providers)
result := make([]discoveryStatus, 0, len(providers))
for _, name := range providers {
registration := s.providers[name]
status := discoveryStatus{Provider: name, ProviderKind: registration.Kind, Health: capability.HealthUnknown, ObservedAtUnixMillis: s.now().UnixMilli(), Models: []discoveredModelStatus{}}
if registration.Discovery != nil {
models, probe := registration.Discovery.Discover(r.Context())
status.Health = probe.Health
status.FailureClass = capability.CognitiveFailureType(probe.Failure)
for _, model := range models {
status.Models = append(status.Models, discoveredModelStatus{ProviderModelID: model.ProviderModelID, Fingerprint: model.Fingerprint, Capabilities: model.Capabilities})
}
}
result = append(result, status)
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(result)
}
+52
View File
@@ -0,0 +1,52 @@
package main
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"git.cin.su/m/Assistant/adapters/models"
"git.cin.su/m/Assistant/contracts/capability"
"git.cin.su/m/Assistant/contracts/cognitive"
"git.cin.su/m/Assistant/contracts/identity"
)
type discoveryTestProvider struct{}
func (discoveryTestProvider) Probe(context.Context) models.ProviderProbe {
return models.ProviderProbe{Health: capability.HealthAvailable}
}
func (discoveryTestProvider) Discover(context.Context) ([]models.DiscoveredModel, models.ProviderProbe) {
return []models.DiscoveredModel{{ProviderModelID: "local-model", Fingerprint: "fingerprint-1", Capabilities: []capability.ModelCapability{capability.CapabilityAdvisory}}}, models.ProviderProbe{Health: capability.HealthAvailable}
}
func (discoveryTestProvider) Advise(context.Context, cognitive.AdvisoryRequest) (cognitive.AdvisoryResponse, error) {
return cognitive.AdvisoryResponse{}, nil
}
func TestDiscoveryStatusIsReadOnlyAndDoesNotExposeCredentialMetadata(t *testing.T) {
service := discoveryService{
providers: map[string]providerRegistration{"cpu": {ProviderInstanceID: "provider-1", Kind: "openai-compatible-chat-v1", CredentialRef: "credential://must-not-be-returned", Discovery: discoveryTestProvider{}}},
owner: identity.PrincipalID("owner-1"),
now: func() time.Time { return time.UnixMilli(1234) },
}
response := httptest.NewRecorder()
service.handler(response, httptest.NewRequest(http.MethodGet, "/v1/provider-discovery/status", nil))
if response.Code != http.StatusOK {
t.Fatalf("status=%d", response.Code)
}
body := response.Body.String()
var result []discoveryStatus
if err := json.NewDecoder(strings.NewReader(body)).Decode(&result); err != nil {
t.Fatal(err)
}
if len(result) != 1 || result[0].Provider != "cpu" || result[0].Health != capability.HealthAvailable || len(result[0].Models) != 1 || result[0].ObservedAtUnixMillis != 1234 {
t.Fatalf("unexpected discovery status: %+v", result)
}
if strings.Contains(body, "must-not-be-returned") || strings.Contains(body, "credential://") {
t.Fatalf("credential metadata leaked in discovery status: %s", body)
}
}
+1
View File
@@ -169,6 +169,7 @@ func main() {
mux.HandleFunc("POST /v1/task-evaluations/execute", gateway.taskEvaluationHandler)
discovery := discoveryService{resolver: resolver, providers: discoveries, owner: identity.PrincipalID(envOr("COGNITIVE_OWNER_PRINCIPAL_ID", "domovoy-creator-principal")), now: time.Now}
mux.HandleFunc("POST /v1/provider-discovery/{provider}", discovery.handler)
mux.HandleFunc("GET /v1/provider-discovery/status", discovery.statusHandler)
refreshProviderDiscoveries(resolver, discovery)
log.Printf("cognitive-worker listening on %s", addr)
if err := http.ListenAndServe(addr, mux); err != nil {
+23
View File
@@ -116,6 +116,10 @@ func main() {
if err != nil {
log.Fatal(err)
}
researchClient, err := newResearchRuntimeClient(envOr("RESEARCH_RUNTIME_URL", "http://research-runtime:8087"), &http.Client{Timeout: 12 * time.Second})
if err != nil {
log.Fatal(err)
}
learning := learningRecorder{epistemics: epistemicsRepository, capability: capabilityRepository}
mux := http.NewServeMux()
authenticateCreator := func(w http.ResponseWriter, r *http.Request) (identity.CreatorSession, bool) {
@@ -178,6 +182,25 @@ func main() {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(session)
})
mux.HandleFunc("POST /v1/creator/research/web", func(w http.ResponseWriter, r *http.Request) {
if _, ok := authenticateCreator(w, r); !ok {
return
}
var request epistemics.WebResearchRequest
decoder := json.NewDecoder(http.MaxBytesReader(w, r.Body, 128<<10))
decoder.DisallowUnknownFields()
if err := decoder.Decode(&request); err != nil {
http.Error(w, "invalid web research request", http.StatusBadRequest)
return
}
result, err := researchClient.EvaluateWeb(r.Context(), request)
if err != nil {
http.Error(w, "web research unavailable", http.StatusBadGateway)
return
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(result)
})
mux.HandleFunc("POST /v1/creator/development/proposals", func(w http.ResponseWriter, r *http.Request) {
session, ok := authenticateCreator(w, r)
if !ok {
+53
View File
@@ -0,0 +1,53 @@
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"git.cin.su/m/Assistant/contracts/epistemics"
)
type researchRuntimeClient struct {
baseURL string
client *http.Client
}
func newResearchRuntimeClient(rawURL string, client *http.Client) (researchRuntimeClient, error) {
base := strings.TrimRight(strings.TrimSpace(rawURL), "/")
if base == "" {
return researchRuntimeClient{}, fmt.Errorf("research runtime URL is empty")
}
if client == nil {
client = http.DefaultClient
}
return researchRuntimeClient{baseURL: base, client: client}, nil
}
func (c researchRuntimeClient) EvaluateWeb(ctx context.Context, request epistemics.WebResearchRequest) (epistemics.ResearchResult, error) {
payload, err := json.Marshal(request)
if err != nil {
return epistemics.ResearchResult{}, err
}
httpRequest, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL+"/v1/research/web/evaluate", bytes.NewReader(payload))
if err != nil {
return epistemics.ResearchResult{}, err
}
httpRequest.Header.Set("Content-Type", "application/json")
response, err := c.client.Do(httpRequest)
if err != nil {
return epistemics.ResearchResult{}, err
}
defer response.Body.Close()
if response.StatusCode < 200 || response.StatusCode >= 300 {
return epistemics.ResearchResult{}, fmt.Errorf("research runtime status %d", response.StatusCode)
}
var result epistemics.ResearchResult
if err := json.NewDecoder(response.Body).Decode(&result); err != nil {
return epistemics.ResearchResult{}, err
}
return result, nil
}
+33
View File
@@ -0,0 +1,33 @@
package main
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"git.cin.su/m/Assistant/contracts/epistemics"
)
func TestResearchRuntimeClientForwardsBoundedWebRequest(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost || r.URL.Path != "/v1/research/web/evaluate" || r.Header.Get("Content-Type") != "application/json" {
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.Path)
}
var request epistemics.WebResearchRequest
if err := json.NewDecoder(r.Body).Decode(&request); err != nil || request.URL != "https://assistant.cin.su/healthz" {
t.Fatalf("unexpected request body: %#v %v", request, err)
}
_ = json.NewEncoder(w).Encode(epistemics.ResearchResult{PlanID: request.Plan.ID, Findings: []epistemics.ResearchFinding{{PropositionKey: request.PropositionKey, State: epistemics.FindingSupported}}})
}))
defer server.Close()
client, err := newResearchRuntimeClient(server.URL, server.Client())
if err != nil {
t.Fatal(err)
}
result, err := client.EvaluateWeb(context.Background(), epistemics.WebResearchRequest{Plan: epistemics.ResearchPlan{ID: "plan-1"}, PropositionKey: "health", URL: "https://assistant.cin.su/healthz"})
if err != nil || result.PlanID != "plan-1" || len(result.Findings) != 1 || result.Findings[0].State != epistemics.FindingSupported {
t.Fatalf("unexpected result: %#v %v", result, err)
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
{
"task_file": "dev/tasks/DEV-000226-ui-acceptance-evidence.json",
"task_id": "DEV-000226",
"task_file": "dev/tasks/DEV-000229-research-runtime-bridge.json",
"task_id": "DEV-000229",
"task_revision": 1
}
+47
View File
@@ -0,0 +1,47 @@
{
"task_id": "DEV-000227",
"task_revision": 1,
"architecture_revision": "ADR-0018",
"base_repo_revision": "1f6ca363ee241b41a89bff1f1b603f15e9873b00",
"risk_tier": "E",
"intent": "Make the existing bounded local task-evaluation path an explicit local executor capability while preserving truthful durable waiting for unsupported work and keeping the external bridge optional.",
"requirement_ids": ["local executor", "truthful degraded execution", "optional external bridge"],
"allowed_change_scope": {
"modules": ["agent-worker", "operations-status"],
"paths": [
"cmd/agent-worker/local_fallback.go",
"cmd/agent-worker/local_fallback_test.go",
"cmd/agent-worker/task_evaluation_executor.go",
"cmd/agent-worker/status.go",
"cmd/agent-worker/status_test.go",
"cmd/agent-worker/main.go",
"dev/ACTIVE_TASK.json",
"dev/tasks/DEV-000227-local-executor.json",
"docs/PROJECT_STATUS.md"
]
},
"forbidden_change_scope": {
"paths": ["architecture/**", "security/**", "contracts/**", "database/**", "deploy/**", "LLM-local/**"]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": ["work.AgentExecutor", "typed task-evaluation runtime endpoints"],
"may_change": ["agent-worker status projection adds local executor capability metadata"]
},
"semantic_owner": "work agent-worker runtime",
"canonical_state": ["existing durable Work dispatch, lease and callback state"],
"state_transitions": ["unsupported local request -> WAITING", "supported task evaluation -> verified callback"],
"side_effects_and_privileges": ["existing bounded internal task-evaluation calls and Work callback only; no external mutation authority"],
"persistence_and_migrations": ["none"],
"failure_retry_restart": ["unsupported work remains durable WAITING; existing lease recovery remains authoritative"],
"assumptions": ["task-evaluation execution and verification endpoints are already deployed internal capabilities", "external bridge may remain absent"],
"acceptance_scenarios": ["local status names bounded local executor and capability", "unsupported work never claims completion", "task evaluation still executes, verifies and callbacks", "external bridge status remains separate", "no secret or new privilege is introduced"],
"required_tests": ["go test ./cmd/agent-worker/...", "go vet ./cmd/agent-worker/...", "preflight", "check-diff", "check-architecture", "independent", "git diff --check", "CI", "production status smoke"],
"terminal_gap_states": ["BLOCKED_BY_MISSING_CAPABILITY", "BLOCKED_BY_SPEC_GAP"]
}
@@ -0,0 +1,23 @@
{
"task_id": "DEV-000228",
"task_revision": 1,
"architecture_revision": "ADR-0018",
"base_repo_revision": "2609f31e59d3914cdf4adcf23ec618705277d12a",
"risk_tier": "E",
"intent": "Expose a read-only, provider-neutral discovery status view so Domovoy can inspect available optional providers and models before requesting qualification, without exposing credential metadata or activating anything.",
"requirement_ids": ["controlled discovery", "provider qualification visibility", "optional external tools"],
"allowed_change_scope": {"modules": ["cognitive-worker", "operations-status"], "paths": ["cmd/cognitive-worker/discovery.go", "cmd/cognitive-worker/discovery_test.go", "cmd/cognitive-worker/main.go", "dev/ACTIVE_TASK.json", "dev/tasks/DEV-000228-controlled-discovery.json", "docs/PROJECT_STATUS.md"]},
"forbidden_change_scope": {"paths": ["architecture/**", "security/**", "contracts/**", "database/**", "deploy/**", "LLM-local/**"]},
"allowed_architecture_delta": {"new_cross_module_dependencies": 0, "new_canonical_owners": 0, "new_privileges": 0, "new_third_party_dependencies": 0, "new_database_owner_roles": 0},
"contracts": {"consume": ["existing LocalProvider discovery probes", "existing capability model metadata"], "may_change": ["read-only cognitive-worker discovery status projection"]},
"semantic_owner": "cognitive-worker observation projection",
"canonical_state": ["existing Capability discovery registration remains the canonical persisted state"],
"state_transitions": ["provider probe -> observed discovery status", "discovery registration remains DISCOVERED/INACTIVE until qualification and promotion"],
"side_effects_and_privileges": ["read-only provider probe on explicit status request; no activation, mutation or credential disclosure"],
"persistence_and_migrations": ["none"],
"failure_retry_restart": ["unavailable provider is reported with health/failure state; persisted discovery remains available through existing owner"],
"assumptions": ["provider discovery adapters already enforce bounded requests", "qualification remains a separate task-evaluation and promotion step"],
"acceptance_scenarios": ["status lists registered providers deterministically", "model inventory and probe health are visible", "credential references are not returned", "status does not activate or persist a provider", "unknown provider remains absent or unavailable"],
"required_tests": ["go test ./cmd/cognitive-worker/...", "go vet ./cmd/cognitive-worker/...", "preflight", "check-diff", "check-architecture", "independent", "git diff --check", "CI", "production status smoke"],
"terminal_gap_states": ["BLOCKED_BY_MISSING_CAPABILITY", "BLOCKED_BY_SPEC_GAP"]
}
@@ -0,0 +1,23 @@
{
"task_id": "DEV-000229",
"task_revision": 1,
"architecture_revision": "ADR-0018",
"base_repo_revision": "22f839df99d8f6abd95f00cf99d34b4b45ace692",
"risk_tier": "E",
"intent": "Connect authenticated Domovoy/Core requests to the existing bounded Truth/Research web runtime while preserving source freshness, exact citations, conflicts and read-only connector policy.",
"requirement_ids": ["Truth/Research runtime", "authenticated internet research", "source evidence"],
"allowed_change_scope": {"modules": ["core-runtime", "research-runtime-bridge"], "paths": ["cmd/core-runtime/main.go", "cmd/core-runtime/research_client.go", "cmd/core-runtime/research_client_test.go", "dev/ACTIVE_TASK.json", "dev/tasks/DEV-000229-research-runtime-bridge.json", "docs/PROJECT_STATUS.md"]},
"forbidden_change_scope": {"paths": ["architecture/**", "security/**", "contracts/**", "database/**", "deploy/**", "LLM-local/**"]},
"allowed_architecture_delta": {"new_cross_module_dependencies": 0, "new_canonical_owners": 0, "new_privileges": 0, "new_third_party_dependencies": 0, "new_database_owner_roles": 0},
"contracts": {"consume": ["existing epistemics.WebResearchRequest and ResearchResult", "existing authenticated Creator session"], "may_change": ["authenticated Core-to-research runtime adapter route"]},
"semantic_owner": "epistemics research runtime; Core is an authenticated transport boundary",
"canonical_state": ["epistemics runtime remains sole owner of persisted truth bundles, claims, beliefs and citations"],
"state_transitions": ["authenticated request -> bounded web connector -> evaluated persisted finding"],
"side_effects_and_privileges": ["read-only outbound source fetches to preconfigured allowlisted hosts; authenticated user request persists evidence in epistemics owner"],
"persistence_and_migrations": ["none"],
"failure_retry_restart": ["research runtime unavailable returns explicit gateway failure; no claim is emitted by Core"],
"assumptions": ["research runtime allowlist is configured outside code", "web connector retains exact source snapshot and does not invent citations"],
"acceptance_scenarios": ["unauthenticated research request is denied", "authenticated request reaches research runtime", "source evidence and finding are returned without fabricated claims", "research runtime remains bounded by allowlist", "no secret is forwarded or returned"],
"required_tests": ["go test ./cmd/core-runtime/...", "go vet ./cmd/core-runtime/...", "preflight", "check-diff", "check-architecture", "independent", "git diff --check", "CI", "production health and research-runtime readiness smoke"],
"terminal_gap_states": ["BLOCKED_BY_MISSING_CAPABILITY", "BLOCKED_BY_SPEC_GAP"]
}
+3 -3
View File
@@ -16,15 +16,15 @@
- `GOVERNED_SELF_DEVELOPMENT_STATUS = DURABLE_GATE_PERSISTED`; Work-owned revisioned gate storage and optimistic-concurrency persistence are live. No bridge-backed source mutation, promotion or rollback is claimed. Evidence: `docs/evidence/governed-development-gate-persistence-2026-08-23-v1.json`.
- `UI_AUTHENTICATED_ACCEPTANCE = AUTHENTICATED_QUICK_SMOKE_PASS`; browser-driven smoke completed in the active production session: chat response received, admin login accepted, diagnostics 7/7 passed, operations fleet 4/4 READY, and action history loaded. Deep mutation, delegation-specific and long-running acceptance remain intentionally deferred.
- `CURRENT_UI_SESSION_STATUS = NO_CURRENT_AUTHENTICATED_SESSION`; the historical quick-smoke evidence above is retained, but the current acceptance run has no signed-in browser session, so no new authenticated visual result is claimed. Public cabinet shell and unauthenticated protection were checked separately.
- `AGENT_WORKER_STATUS_CORRECTION = LIVE_TRUTHFUL_LOCAL_FALLBACK`; after DEV-000216, absence of the protected bridge is reported as `executor_configured=false`, `mode=local-fallback`, `ready=false`; local task evaluation is not represented as external agent execution. Evidence: `docs/evidence/audit-runtime-status-2026-08-23-v2.json`.
- `AGENT_WORKER_STATUS_CORRECTION = LIVE_TRUTHFUL_LOCAL_EXECUTOR`; absence of the protected bridge is reported as `executor_configured=false`, `mode=local-executor`, `ready=false`, with `task-evaluation` as the only advertised local capability; unsupported work remains durably waiting and is not represented as external agent execution. Evidence: `docs/evidence/audit-runtime-status-2026-08-23-v2.json` (pre-DEV-000227 field shape remains historical).
- `FLEET_READINESS_LIVE = MEDIUM_SELECTED_BY_AVAILABILITY`; the live cognitive worker observed FAST unavailable, MEDIUM available, HEAVY available and LIFEBOAT available; it selected MEDIUM while the configured preference remained FAST. This is routing evidence only, not a quality or promotion claim. Evidence: `docs/evidence/fleet-readiness-live-2026-08-23-v2.json`.
- `UI_AUTHENTICATED_ACCEPTANCE = CURRENT_LIVE_PASS`; current signed-in browser evidence covers root chat session, admin diagnostics 7/7, operations fleet 4/4 READY with FAST selected, truthful local-fallback agent status, action history and learning/reflection sections; the 390x844 console layout remained readable without horizontal overflow. Evidence: `docs/evidence/authenticated-ui-acceptance-2026-08-23-v2.json`.
- `UI_AUTHENTICATED_ACCEPTANCE = CURRENT_LIVE_PASS`; current signed-in browser evidence covers root chat session, admin diagnostics 7/7, operations fleet 4/4 READY with FAST selected, truthful local-executor agent status, action history and learning/reflection sections; the 390x844 console layout remained readable without horizontal overflow. Evidence: `docs/evidence/authenticated-ui-acceptance-2026-08-23-v2.json`.
## Current governance checkpoint
- `COMPLETION_MATRIX = docs/evidence/audit-completion-matrix-2026-08-23-v3.json`; all seven objective areas are mapped to current repository/production proof, with external bridge, GPU promotion/quality and deep-acceptance gaps explicit.
- `ACTIVE_TASK = dev/tasks/DEV-000226-ui-acceptance-evidence.json revision 1`
- `ACTIVE_TASK = dev/tasks/DEV-000229-research-runtime-bridge.json revision 1`; authenticated Core now has a bounded adapter route to the existing Truth/Research runtime. The epistemics owner remains responsible for persistence, freshness, citations and conflicts.
- `LINEAGE_DECISION = docs/GOVERNANCE_LINEAGE_DECISION_2026-08-22.md`; historical packets remain provenance and are not current authority.
- `REGISTRY_STATUS = YAML and JSON semantic mirrors agree`
- `PRODUCTION_DOMAIN = docker.cin.su`; shared docker-test is not used for this project.