diff --git a/contracts/work/lease.go b/contracts/work/lease.go index 756df90..0927819 100644 --- a/contracts/work/lease.go +++ b/contracts/work/lease.go @@ -38,3 +38,13 @@ type AgentCallback struct { Kind AgentCallbackKind ObservedAt time.Time } + +type IndependentVerification struct { + ProducerRunID AgentRunID + VerifierRunID AgentRunID + VerifierIdentity string + ArtifactID string + TestEvidenceRef string + Verified bool + Summary string +} diff --git a/dev/ACTIVE_TASK.json b/dev/ACTIVE_TASK.json index c00a6fa..3dbe2f3 100644 --- a/dev/ACTIVE_TASK.json +++ b/dev/ACTIVE_TASK.json @@ -1,5 +1,5 @@ { - "task_file": "dev/tasks/DEV-000118-agent-artifact-attestation.json", - "task_id": "DEV-000118", + "task_file": "dev/tasks/DEV-000119-independent-verification-contract.json", + "task_id": "DEV-000119", "task_revision": 1 } diff --git a/dev/tasks/DEV-000119-independent-verification-contract.json b/dev/tasks/DEV-000119-independent-verification-contract.json new file mode 100644 index 0000000..b1dff72 --- /dev/null +++ b/dev/tasks/DEV-000119-independent-verification-contract.json @@ -0,0 +1,23 @@ +{ + "task_id": "DEV-000119", + "task_revision": 1, + "architecture_revision": "ADR-0018", + "base_repo_revision": "02b472b", + "risk_tier": "E", + "intent": "Add independent verification contract requiring a distinct verifier identity/run and attested artifact evidence before Work completion.", + "requirement_ids": ["WP-301", "Independent verifier", "Work completion gate"], + "allowed_change_scope": {"modules": ["work-agent-verification"], "paths": ["contracts/work/**", "modules/work/domain/**", "tests/agent_execution/**", "dev/ACTIVE_TASK.json", "dev/tasks/DEV-000119-independent-verification-contract.json"]}, + "forbidden_change_scope": {"paths": ["architecture/**", "database/**", "migrations/**", "deploy/**", "security/**", "cmd/**", "runtime/**", "adapters/**", ".gitea/**"]}, + "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": ["ADR-0017 verification separation", "ADR-0020 independent verifier", "Agent artifact attestation from DEV-000118"], "may_change": ["Work independent verification contract"]}, + "semantic_owner": "work-agent-verification", + "canonical_state": [], + "state_transitions": ["producer result + attestation -> verifier assessment -> verified/rejected"], + "side_effects_and_privileges": ["Pure validation; no merge, deployment, binding activation, credential access or external mutation"], + "persistence_and_migrations": ["No schema or migration changes"], + "failure_retry_restart": ["Rejected verification preserves producer evidence; a new verifier run is required"], + "assumptions": ["Verifier identity and run are authenticated later", "Producer and verifier cannot be the same run", "Artifact evidence is immutable"], + "acceptance_scenarios": ["Distinct verifier validates attested artifact", "Same run is rejected", "Missing artifact/test evidence is rejected", "Rejected verification does not erase producer result"], + "required_tests": ["go test ./...", "go vet ./...", "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", "go run ./cmd/devctl/independent", "git diff --check", "independent verification tests"], + "terminal_gap_states": ["BLOCKED_BY_MISSING_CAPABILITY", "BLOCKED_BY_SPEC_GAP", "BLOCKED_BY_CONFLICT"] +} diff --git a/modules/work/domain/lease.go b/modules/work/domain/lease.go index 2964af8..1103a99 100644 --- a/modules/work/domain/lease.go +++ b/modules/work/domain/lease.go @@ -32,3 +32,10 @@ func ValidateAgentCallback(callback work.AgentCallback, lease work.AgentLease, l } return nil } + +func ValidateIndependentVerification(value work.IndependentVerification) error { + if value.ProducerRunID == "" || value.VerifierRunID == "" || value.ProducerRunID == value.VerifierRunID || value.VerifierIdentity == "" || value.ArtifactID == "" || value.TestEvidenceRef == "" || value.Summary == "" { + return ErrCallbackRejected + } + return nil +} diff --git a/tests/agent_execution/verification_test.go b/tests/agent_execution/verification_test.go new file mode 100644 index 0000000..260ff4d --- /dev/null +++ b/tests/agent_execution/verification_test.go @@ -0,0 +1,19 @@ +package agent_execution_test + +import ( + "testing" + + "git.cin.su/m/Assistant/contracts/work" + workdomain "git.cin.su/m/Assistant/modules/work/domain" +) + +func TestIndependentVerificationRequiresDistinctRun(t *testing.T) { + verification := work.IndependentVerification{ProducerRunID: "producer-1", VerifierRunID: "verifier-1", VerifierIdentity: "verifier", ArtifactID: "artifact-1", TestEvidenceRef: "tests-1", Verified: true, Summary: "passed"} + if err := workdomain.ValidateIndependentVerification(verification); err != nil { + t.Fatal(err) + } + verification.VerifierRunID = verification.ProducerRunID + if err := workdomain.ValidateIndependentVerification(verification); err == nil { + t.Fatal("expected same-run rejection") + } +}