Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90104d2553 | ||
|
|
ca0d002073 | ||
|
|
20db36f52e | ||
|
|
383d4c6e4f | ||
|
|
f3ddb45fe5 | ||
|
|
6061eb5c13 |
@@ -298,12 +298,21 @@ func fallbackEligible(reason cognitive.FinishReason) bool {
|
||||
}
|
||||
|
||||
func (g cognitiveGateway) provider(selected capability.ResolvedCognitiveBinding) advisoryProvider {
|
||||
var byStableID advisoryProvider
|
||||
for _, registration := range g.providers[selected.Provider.Kind] {
|
||||
if registration.EndpointRef == selected.Provider.EndpointRef && registration.CredentialRef == selected.Provider.CredentialRef {
|
||||
return registration.Provider
|
||||
}
|
||||
// Capability revisions can legitimately retain an older credential
|
||||
// reference while the protected runtime has rotated or reloaded the
|
||||
// current credential. ProviderInstanceID is the stable owner identity;
|
||||
// use it after exact metadata matching so stale non-secret metadata does
|
||||
// not force an unnecessary builtin fallback.
|
||||
if byStableID == nil && registration.ProviderInstanceID == selected.Provider.ID && registration.Kind == selected.Provider.Kind {
|
||||
byStableID = registration.Provider
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return byStableID
|
||||
}
|
||||
|
||||
func writeGatewayResponse(w http.ResponseWriter, response cognitive.GatewayAdvisoryResponse) {
|
||||
|
||||
@@ -88,6 +88,19 @@ func TestActiveRegistryBindingReachesProviderAdapter(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProviderUsesStableInstanceWhenCredentialMetadataIsStale(t *testing.T) {
|
||||
provider := &stubAdvisoryProvider{}
|
||||
gateway := cognitiveGateway{providers: map[capability.ProviderKind][]providerRegistration{
|
||||
"provider-kind-1": {{ProviderInstanceID: "provider-1", Kind: "provider-kind-1", EndpointRef: "current-endpoint", CredentialRef: "current-credential", Provider: provider}},
|
||||
}}
|
||||
selected := gatewaySelection()
|
||||
selected.Provider.EndpointRef = "old-endpoint"
|
||||
selected.Provider.CredentialRef = ""
|
||||
if got := gateway.provider(selected); got != provider {
|
||||
t.Fatalf("stable provider identity was not used for stale metadata")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanaryFlagIsForwardedToCapabilityResolver(t *testing.T) {
|
||||
registry := ®istryStub{err: errors.New("stop after resolve")}
|
||||
gateway := cognitiveGateway{resolver: registry, providers: map[capability.ProviderKind][]providerRegistration{}, now: time.Now, allowCanary: true}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"task_file": "dev/tasks/DEV-000238-local-fallback-evidence.json",
|
||||
"task_id": "DEV-000238",
|
||||
"task_file": "dev/tasks/DEV-000241-fleet-qualification-evidence.json",
|
||||
"task_id": "DEV-000241",
|
||||
"task_revision": 1
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"task_id": "DEV-000239",
|
||||
"task_revision": 1,
|
||||
"architecture_revision": "ADR-0018",
|
||||
"base_repo_revision": "6061eb5c13e46cec1e60fc104b022394f0d94dee",
|
||||
"risk_tier": "E",
|
||||
"intent": "Resolve a registered provider by its stable instance identity when a persisted Capability revision contains stale non-secret endpoint credential metadata, while preserving exact metadata matching first.",
|
||||
"requirement_ids": ["model fleet/failover", "credential rotation compatibility", "local fallback attribution"],
|
||||
"allowed_change_scope": {"modules": ["cognitive-worker"], "paths": ["cmd/cognitive-worker/gateway.go", "cmd/cognitive-worker/gateway_registry_test.go", "dev/ACTIVE_TASK.json", "dev/tasks/DEV-000239-stable-provider-resolution.json"]},
|
||||
"forbidden_change_scope": {"paths": ["architecture/**", "security/**", "database/**", "deploy/**", "LLM-local/**", "modules/work/secrets/**", "contracts/**"]},
|
||||
"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": ["Capability ResolvedCognitiveBinding", "protected provider registration"], "may_change": ["internal provider lookup fallback order"]},
|
||||
"semantic_owner": "Cognitive worker provider adapter boundary",
|
||||
"canonical_state": ["no new durable state"],
|
||||
"state_transitions": ["exact provider metadata match -> stable provider identity match -> no provider"],
|
||||
"side_effects_and_privileges": ["provider lookup only; secret values remain in protected runtime"],
|
||||
"persistence_and_migrations": ["none"],
|
||||
"failure_retry_restart": ["missing provider remains explicit and uses existing builtin fallback"],
|
||||
"assumptions": ["ProviderInstanceID is the stable Capability-owned provider identity"],
|
||||
"acceptance_scenarios": ["stale credential metadata still reaches current registered adapter", "exact metadata match retains priority", "no provider remains nil"],
|
||||
"required_tests": ["go test ./cmd/cognitive-worker/...", "go vet ./cmd/cognitive-worker/...", "go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json", "go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json", "go run ./cmd/devctl check-architecture", "git diff --check", "independent", "CI", "production health smoke"],
|
||||
"terminal_gap_states": ["BLOCKED_BY_MISSING_CAPABILITY", "BLOCKED_BY_SPEC_GAP"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"task_id": "DEV-000240",
|
||||
"task_revision": 1,
|
||||
"architecture_revision": "ADR-0018",
|
||||
"base_repo_revision": "383d4c6e4fd53bb0c34ed358e0d1be6a416da6cc",
|
||||
"risk_tier": "E",
|
||||
"intent": "Record live durable evidence of CPU model failure followed by successful local Lifeboat failover after stable provider resolution was deployed.",
|
||||
"requirement_ids": ["model fleet/failover", "durable usage evidence", "false completion prevention"],
|
||||
"allowed_change_scope": {"modules": ["evidence"], "paths": ["docs/evidence/cpu-lifeboat-failover-2026-08-23-v1.json", "dev/ACTIVE_TASK.json", "dev/tasks/DEV-000240-cpu-lifeboat-failover-evidence.json"]},
|
||||
"forbidden_change_scope": {"paths": ["architecture/**", "security/**", "database/**", "deploy/**", "LLM-local/**", "modules/work/secrets/**", "contracts/**"]},
|
||||
"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": ["cognitive advisory gateway", "cognitive usage observations"], "may_change": []},
|
||||
"semantic_owner": "Evidence only",
|
||||
"canonical_state": ["no runtime state mutation; evidence captures existing durable observations"],
|
||||
"state_transitions": ["CPU MODEL_UNAVAILABLE -> builtin local Lifeboat COMPLETED"],
|
||||
"side_effects_and_privileges": ["bounded LOCAL_ONLY advisory request; no external egress"],
|
||||
"persistence_and_migrations": ["existing usage observation persistence only"],
|
||||
"failure_retry_restart": ["the fallback is selected within the bounded gateway request"],
|
||||
"assumptions": ["provider_instance_id and result_class in capability usage observations are authoritative route attribution"],
|
||||
"acceptance_scenarios": ["primary failure is durably observed", "fallback completion is durably observed", "HTTP gateway returns COMPLETED", "public health remains OK"],
|
||||
"required_tests": ["go test ./cmd/cognitive-worker/...", "go vet ./cmd/cognitive-worker/...", "go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json", "go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json", "go run ./cmd/devctl check-architecture", "git diff --check", "independent", "CI", "production health smoke"],
|
||||
"terminal_gap_states": ["BLOCKED_BY_MISSING_CAPABILITY", "BLOCKED_BY_SPEC_GAP"]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"task_id": "DEV-000241",
|
||||
"task_revision": 1,
|
||||
"architecture_revision": "ADR-0018",
|
||||
"base_repo_revision": "ca0d0020739d8f70e2a3ac04820e32794072ab30",
|
||||
"risk_tier": "E",
|
||||
"intent": "Record bounded medium and GPU qualification observations without treating hardware presence or reachability as quality or promotion evidence.",
|
||||
"requirement_ids": ["model fleet inventory", "provider-neutral qualification", "hardware-neutral routing"],
|
||||
"allowed_change_scope": {"modules": ["evidence"], "paths": ["docs/evidence/fleet-qualification-2026-08-23-v1.json", "dev/ACTIVE_TASK.json", "dev/tasks/DEV-000241-fleet-qualification-evidence.json"]},
|
||||
"forbidden_change_scope": {"paths": ["architecture/**", "security/**", "database/**", "deploy/**", "LLM-local/**", "modules/work/secrets/**", "contracts/**"]},
|
||||
"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": ["provider discovery status", "bounded qualification response"], "may_change": []},
|
||||
"semantic_owner": "Evidence only",
|
||||
"canonical_state": ["no runtime state mutation"],
|
||||
"state_transitions": ["discovered model -> bounded reachability observation -> UNRATED result"],
|
||||
"side_effects_and_privileges": ["bounded provider invocation; no promotion, activation or routing mutation"],
|
||||
"persistence_and_migrations": ["evidence artifact only"],
|
||||
"failure_retry_restart": ["one model timeout does not cancel or misclassify other tier evidence"],
|
||||
"assumptions": ["provider discovery IDs are the exact IDs returned by the live worker"],
|
||||
"acceptance_scenarios": ["medium reachability records latency", "GPU timeout is explicit", "both results remain UNRATED", "GPU does not receive an implicit priority"],
|
||||
"required_tests": ["go test ./cmd/cognitive-worker/...", "go vet ./cmd/cognitive-worker/...", "go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json", "go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json", "go run ./cmd/devctl check-architecture", "git diff --check", "independent", "CI", "production health smoke"],
|
||||
"terminal_gap_states": ["BLOCKED_BY_MISSING_CAPABILITY", "BLOCKED_BY_SPEC_GAP"]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"evidence_id": "cpu-lifeboat-failover-2026-08-23-v1",
|
||||
"observed_at": "2026-08-23",
|
||||
"production_revision": "383d4c6e4fd53bb0c34ed358e0d1be6a416da6cc",
|
||||
"request": {"surface": "internal cognitive-worker advisory gateway", "data_policy": "LOCAL_ONLY", "max_output_bytes": 128, "prompt_class": "bounded readiness response"},
|
||||
"http_result": {"status": 200, "finish_reason": "COMPLETED", "output_observed": true},
|
||||
"durable_route_observations": [
|
||||
{"provider_instance_id": "local-cpu-primary", "result_class": "MODEL_UNAVAILABLE", "failure_type": "MODEL_UNAVAILABLE", "latency_millis": 580},
|
||||
{"provider_instance_id": "builtin-local-lifeboat-v1", "result_class": "COMPLETED", "failure_type": null, "latency_millis": 455}
|
||||
],
|
||||
"public_health": {"url": "https://assistant.cin.su/healthz", "status": 200, "runtime": "creator-web"},
|
||||
"status": "CPU_TO_LIFEBOAT_FAILOVER_LIVE_PASS",
|
||||
"secrets_exposed": false,
|
||||
"remaining": ["medium/GPU validated multi-model failover", "quality-based promotion", "long-running failover and restart chaos"]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"evidence_id": "fleet-qualification-2026-08-23-v1",
|
||||
"observed_at": "2026-08-23",
|
||||
"production_revision": "ca0d0020739d8f70e2a3ac04820e32794072ab30",
|
||||
"discovery": {"cpu": "AVAILABLE", "medium": "AVAILABLE", "gpu": "AVAILABLE", "lifeboat": "AVAILABLE"},
|
||||
"probes": [
|
||||
{"provider": "local-medium-primary", "provider_model_id": "Qwen3.6-27B-UD-Q4_K_XL", "status": "REACHABLE", "finish_reason": "COMPLETED", "latency_millis": 8541, "output_observed": true, "quality_assessed": false, "category": "UNRATED"},
|
||||
{"provider": "local-gpu-opportunistic", "provider_model_id": "Qwen3.8-27B-UD-Q4_K_XL", "status": "RESPONDED_WITHOUT_QUALIFICATION", "finish_reason": "TIMEOUT", "latency_millis": 10006, "output_observed": false, "quality_assessed": false, "category": "UNRATED"}
|
||||
],
|
||||
"status": "FLEET_REACHABILITY_OBSERVED_QUALITY_UNRATED",
|
||||
"interpretation": "The medium provider is reachable for this bounded probe; the selected GPU model timed out. Hardware presence does not grant priority or promotion.",
|
||||
"remaining": ["durable qualification result persistence", "independent task-quality evaluation for medium/GPU", "GPU retry/failover under sustained load"],
|
||||
"secrets_exposed": false
|
||||
}
|
||||
Reference in New Issue
Block a user