This commit is contained in:
@@ -479,6 +479,32 @@ func (r *CapabilityRepository) SaveCognitiveCanaryPromotion(ctx context.Context,
|
||||
return tx.Commit(ctx)
|
||||
}
|
||||
|
||||
func (r *CapabilityRepository) SaveCognitiveActivationPromotion(ctx context.Context, value capability.CognitiveActivationPromotion) error {
|
||||
tx, err := r.pool.Begin(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = tx.Rollback(ctx) }()
|
||||
b, e := value.Binding, value.Evaluation
|
||||
if _, err = tx.Exec(ctx, `INSERT INTO capability.cognitive_bindings (binding_id,revision,capability_id,owner_principal_id,provider_instance_id,provider_revision,model_descriptor_id,model_revision,data_policy,qualification,activation,health,limit_policy_ref) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13) ON CONFLICT DO NOTHING`, b.ID, b.Revision, b.CapabilityID, b.OwnerPrincipalID, b.ProviderInstanceID, b.ProviderRevision, b.ModelDescriptorID, b.ModelRevision, b.DataPolicy, b.Qualification, b.Activation, b.Health, b.LimitPolicyRef); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = tx.Exec(ctx, `INSERT INTO capability.cognitive_evaluated_capabilities (evaluation_id,binding_id,binding_revision,capability_id,result,quality_score_millis,critical_failure_millis,benchmark_version,artifact_id,observed_at_unix_millis) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10) ON CONFLICT DO NOTHING`, e.ID, e.BindingID, e.BindingRevision, e.CapabilityID, e.Result, e.QualityScoreMillis, e.CriticalFailureMillis, e.BenchmarkVersion, e.ArtifactID, e.ObservedAtUnixMillis); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = tx.Exec(ctx, `UPDATE capability.cognitive_bindings SET activation='DEPRECATED' WHERE capability_id=$1 AND owner_principal_id=$2 AND activation='ACTIVE' AND NOT (binding_id=$3 AND revision=$4)`, b.CapabilityID, b.OwnerPrincipalID, b.ID, b.Revision); err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := tx.Exec(ctx, `UPDATE capability.cognitive_binding_revision_heads SET revision=$1,updated_at=CURRENT_TIMESTAMP WHERE binding_id=$2 AND revision=$3`, b.Revision, b.ID, value.ExpectedBindingRevision)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result.RowsAffected() != 1 {
|
||||
return ErrCapabilityBindingConflict
|
||||
}
|
||||
return tx.Commit(ctx)
|
||||
}
|
||||
|
||||
func (r *CapabilityRepository) SavePerformanceEvidence(ctx context.Context, value capability.PerformanceEvidence) error {
|
||||
_, err := r.pool.Exec(ctx, `INSERT INTO capability.cognitive_performance_evidence (evidence_id,binding_id,binding_revision,model_descriptor_id,model_revision,hardware_profile,runtime,quantization,context_units,thinking_enabled,generation_tps_millis,prompt_tps_millis,ttft_micros,latency_micros,memory_bytes,reliability_millis,benchmark_version,artifact_id,observed_at_unix_millis) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19) ON CONFLICT DO NOTHING`, value.ID, value.BindingID, value.BindingRevision, value.ModelDescriptorID, value.ModelRevision, value.HardwareProfile, value.Runtime, value.Quantization, value.ContextUnits, value.ThinkingEnabled, value.GenerationTPSMillis, value.PromptTPSMillis, value.TTFTMicros, value.LatencyMicros, value.MemoryBytes, value.ReliabilityMillis, value.BenchmarkVersion, value.ArtifactID, value.ObservedAtUnixMillis)
|
||||
return err
|
||||
|
||||
@@ -888,6 +888,45 @@ func main() {
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
_ = json.NewEncoder(w).Encode(promotion)
|
||||
})
|
||||
mux.HandleFunc("POST /v1/creator/cognitive-activate", func(w http.ResponseWriter, r *http.Request) {
|
||||
session, ok := authenticateCreator(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var request capability.CognitiveActivationPromotionRequest
|
||||
decoder := json.NewDecoder(io.LimitReader(r.Body, 16<<10))
|
||||
decoder.DisallowUnknownFields()
|
||||
if err := decoder.Decode(&request); err != nil {
|
||||
http.Error(w, "invalid cognitive activation", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
request.RequestedByPrincipalID = session.PrincipalID
|
||||
request.CapabilityID = "creator-advisory"
|
||||
candidates, err := capabilityRepository.LoadCognitiveCandidates(r.Context(), request.CapabilityID, session.PrincipalID)
|
||||
if err != nil {
|
||||
http.Error(w, "cognitive registry unavailable", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
var current capability.ResolvedCognitiveBinding
|
||||
for _, candidate := range candidates {
|
||||
if candidate.Binding.ID == request.BindingID && candidate.Binding.Revision == request.ExpectedBindingRevision {
|
||||
current = candidate
|
||||
break
|
||||
}
|
||||
}
|
||||
promotion, err := capabilitydomain.BuildActivationPromotion(request, current)
|
||||
if err != nil {
|
||||
http.Error(w, "cognitive activation precondition failed", http.StatusConflict)
|
||||
return
|
||||
}
|
||||
if err = capabilityRepository.SaveCognitiveActivationPromotion(r.Context(), promotion); err != nil {
|
||||
http.Error(w, "cognitive activation conflict", http.StatusConflict)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
_ = json.NewEncoder(w).Encode(promotion)
|
||||
})
|
||||
mux.HandleFunc("POST /v1/cognitive-registry/performance-evidence", func(w http.ResponseWriter, r *http.Request) {
|
||||
var value capability.PerformanceEvidence
|
||||
decoder := json.NewDecoder(io.LimitReader(r.Body, 64<<10))
|
||||
|
||||
@@ -206,6 +206,23 @@ type CognitiveCanaryPromotion struct {
|
||||
Evaluation EvaluatedCapability
|
||||
}
|
||||
|
||||
type CognitiveActivationPromotionRequest struct {
|
||||
PromotionID ids.ID
|
||||
RequestedByPrincipalID identity.PrincipalID
|
||||
CapabilityID CapabilityID
|
||||
BindingID CapabilityBindingID
|
||||
ExpectedBindingRevision int64
|
||||
EvaluationID EvaluationID
|
||||
ObservedAtUnixMillis int64
|
||||
}
|
||||
|
||||
type CognitiveActivationPromotion struct {
|
||||
PromotionID ids.ID
|
||||
ExpectedBindingRevision int64
|
||||
Binding CognitiveBinding
|
||||
Evaluation EvaluatedCapability
|
||||
}
|
||||
|
||||
// CognitiveDiscoverySnapshot is provider-neutral observed inventory submitted
|
||||
// to the Capability owner. The owner assigns immutable revisions and always
|
||||
// registers discovered bindings as DISCOVERED/INACTIVE.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"task_id": "DEV-000083",
|
||||
"task_revision": 2,
|
||||
"task_revision": 3,
|
||||
"architecture_revision": "DEV-000073-baseline",
|
||||
"base_repo_revision": "0a2599cfa6255f1a98856d2fd09dc51a2119f525",
|
||||
"risk_tier": "C",
|
||||
@@ -20,10 +20,13 @@
|
||||
"cmd/cognitive-worker/main_test.go",
|
||||
"modules/capability/domain/cognitive_registry.go",
|
||||
"modules/capability/domain/cognitive_registry_test.go",
|
||||
"modules/capability/ports/repository.go",
|
||||
"contracts/capability/cognitive_registry.go",
|
||||
"cmd/creator-web/static/assets/chat.js",
|
||||
"cmd/creator-web/static/chat.html",
|
||||
"cmd/creator-web/chat_test.go",
|
||||
"adapters/postgres/capability_repository.go",
|
||||
"tests/cognitive_canary/promotion_test.go",
|
||||
"deploy/docker-compose.prod.yml",
|
||||
"deploy/docker-compose.dev.yml",
|
||||
"dev/tasks/DEV-000083-lifeboat-benchmark-manifest.json",
|
||||
@@ -44,7 +47,7 @@
|
||||
},
|
||||
"contracts": {
|
||||
"consume": ["existing Cognitive Gateway and Capability Registry", "existing chat response fields", "existing cognitive health endpoint"],
|
||||
"may_change": []
|
||||
"may_change": ["authorized cognitive activation transition"]
|
||||
},
|
||||
"semantic_owner": "capability-observation-consumer",
|
||||
"canonical_state": [],
|
||||
|
||||
@@ -62,6 +62,22 @@ func BuildCanaryPromotion(request capability.CognitiveCanaryPromotionRequest, cu
|
||||
return capability.CognitiveCanaryPromotion{PromotionID: request.PromotionID, ExpectedBindingRevision: request.ExpectedBindingRevision, Provider: provider, Model: model, Binding: binding, Evaluation: evaluation}, nil
|
||||
}
|
||||
|
||||
func BuildActivationPromotion(request capability.CognitiveActivationPromotionRequest, current capability.ResolvedCognitiveBinding) (capability.CognitiveActivationPromotion, error) {
|
||||
if request.PromotionID == "" || request.RequestedByPrincipalID == "" || request.CapabilityID == "" || request.BindingID == "" || request.ExpectedBindingRevision < 1 || request.EvaluationID == "" || request.ObservedAtUnixMillis < 1 || current.Evaluation == nil {
|
||||
return capability.CognitiveActivationPromotion{}, ErrInvalidCognitiveRegistryRecord
|
||||
}
|
||||
if current.Binding.ID != request.BindingID || current.Binding.Revision != request.ExpectedBindingRevision || current.Binding.OwnerPrincipalID != request.RequestedByPrincipalID || current.Binding.CapabilityID != request.CapabilityID || current.Evaluation.ID != request.EvaluationID || current.Evaluation.Result != capability.EvaluationSupported || current.Evaluation.QualityScoreMillis == nil || *current.Evaluation.QualityScoreMillis < 750 || current.Evaluation.CriticalFailureMillis == nil || *current.Evaluation.CriticalFailureMillis != 0 || current.Provider.Health != capability.HealthAvailable || current.Model.Health != capability.HealthAvailable || current.Binding.Qualification != capability.QualificationValidated || current.Binding.Activation != capability.ActivationCanary || current.Binding.Health != capability.HealthAvailable {
|
||||
return capability.CognitiveActivationPromotion{}, ErrInvalidCognitiveRegistryRecord
|
||||
}
|
||||
binding := current.Binding
|
||||
binding.Revision = stableRevision(fmt.Sprint(binding.Revision), string(request.PromotionID), string(capability.ActivationActive))
|
||||
binding.Qualification, binding.Activation, binding.Health = capability.QualificationValidated, capability.ActivationActive, capability.HealthAvailable
|
||||
evaluation := *current.Evaluation
|
||||
evaluation.ID = capability.EvaluationID(stableID("evaluation", string(request.PromotionID), string(binding.ID), fmt.Sprint(binding.Revision)))
|
||||
evaluation.BindingRevision = binding.Revision
|
||||
return capability.CognitiveActivationPromotion{PromotionID: request.PromotionID, ExpectedBindingRevision: request.ExpectedBindingRevision, Binding: binding, Evaluation: evaluation}, nil
|
||||
}
|
||||
|
||||
func stableID(kind string, parts ...string) string {
|
||||
hash := sha256.New()
|
||||
_, _ = hash.Write([]byte(kind))
|
||||
|
||||
@@ -38,3 +38,22 @@ func TestBuildDiscoveryRegistrationCarriesObservedHealthToCanaryPrecondition(t *
|
||||
t.Fatalf("discovery health was not carried into canary candidates: model=%s binding=%s", registration.Models[0].Health, registration.Bindings[0].Health)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildActivationPromotionRequiresHealthyCanary(t *testing.T) {
|
||||
quality := int64(750)
|
||||
critical := int64(0)
|
||||
current := capability.ResolvedCognitiveBinding{
|
||||
Binding: capability.CognitiveBinding{ID: "binding-1", Revision: 2, CapabilityID: "creator-advisory", OwnerPrincipalID: "owner", ProviderInstanceID: "provider-1", ProviderRevision: 3, ModelDescriptorID: "model-1", ModelRevision: 4, DataPolicy: capability.DataPolicyLocalOnly, Qualification: capability.QualificationValidated, Activation: capability.ActivationCanary, Health: capability.HealthAvailable, LimitPolicyRef: "limits"},
|
||||
Provider: capability.ProviderInstance{ID: "provider-1", Revision: 3, Health: capability.HealthAvailable},
|
||||
Model: capability.ModelDescriptor{ID: "model-1", Revision: 4, ProviderInstanceID: "provider-1", Health: capability.HealthAvailable},
|
||||
Evaluation: &capability.EvaluatedCapability{ID: "eval-1", Result: capability.EvaluationSupported, QualityScoreMillis: &quality, CriticalFailureMillis: &critical},
|
||||
}
|
||||
promotion, err := BuildActivationPromotion(capability.CognitiveActivationPromotionRequest{PromotionID: "promotion-1", RequestedByPrincipalID: "owner", CapabilityID: "creator-advisory", BindingID: "binding-1", ExpectedBindingRevision: 2, EvaluationID: "eval-1", ObservedAtUnixMillis: 3}, current)
|
||||
if err != nil || promotion.Binding.Activation != capability.ActivationActive || promotion.Binding.Revision == current.Binding.Revision {
|
||||
t.Fatalf("promotion=%+v err=%v", promotion, err)
|
||||
}
|
||||
current.Binding.Activation = capability.ActivationInactive
|
||||
if _, err = BuildActivationPromotion(capability.CognitiveActivationPromotionRequest{PromotionID: "promotion-2", RequestedByPrincipalID: "owner", CapabilityID: "creator-advisory", BindingID: "binding-1", ExpectedBindingRevision: 2, EvaluationID: "eval-1", ObservedAtUnixMillis: 3}, current); err == nil {
|
||||
t.Fatal("expected inactive binding to be rejected")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ type Repository interface {
|
||||
LoadCognitiveCandidates(context.Context, capability.CapabilityID, identity.PrincipalID) ([]capability.ResolvedCognitiveBinding, error)
|
||||
LoadCognitiveCandidate(context.Context, capability.CapabilityBindingID, int64) (capability.ResolvedCognitiveBinding, error)
|
||||
SaveCognitiveCanaryPromotion(context.Context, capability.CognitiveCanaryPromotion) error
|
||||
SaveCognitiveActivationPromotion(context.Context, capability.CognitiveActivationPromotion) error
|
||||
SaveCognitiveUsageObservation(context.Context, capability.CognitiveUsageObservation) error
|
||||
SaveCognitiveDiscovery(context.Context, capability.CognitiveDiscoveryRegistration) error
|
||||
SaveEvaluatedCapability(context.Context, capability.EvaluatedCapability) error
|
||||
|
||||
Reference in New Issue
Block a user