From c30e0c72ead45979db836c95bbff6639b978e380 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Sat, 22 Aug 2026 12:18:19 +0300 Subject: [PATCH] feat(work): add manual agent canary cli --- cmd/agent-canary/main.go | 50 ++++++++++++++++++++++ dev/ACTIVE_TASK.json | 4 +- dev/tasks/DEV-000125-agent-canary-cli.json | 23 ++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 cmd/agent-canary/main.go create mode 100644 dev/tasks/DEV-000125-agent-canary-cli.json diff --git a/cmd/agent-canary/main.go b/cmd/agent-canary/main.go new file mode 100644 index 0000000..6034b48 --- /dev/null +++ b/cmd/agent-canary/main.go @@ -0,0 +1,50 @@ +package main + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "os" + "time" + + "git.cin.su/m/Assistant/contracts/work" + "git.cin.su/m/Assistant/modules/work/application" +) + +type memoryStore struct{ writes int } + +func (s *memoryStore) SaveDispatchIntent(context.Context, work.AgentDispatchIntent) error { + s.writes++ + return nil +} +func (s *memoryStore) SaveAgentLease(context.Context, work.AgentLease) error { s.writes++; return nil } +func (s *memoryStore) AcceptAgentCallback(context.Context, work.AgentCallback) error { + s.writes++ + return nil +} + +func main() { + enabled := flag.Bool("enable-canary", false, "explicitly enable the manual canary") + implementation := flag.String("implementation", "fake-worker", "allowlisted deterministic implementation") + flag.Parse() + + now := time.UnixMilli(1_700_000_000_000) + intent := work.AgentDispatchIntent{DispatchID: "manual-dispatch-1", IdempotencyKey: "manual-idempotency-1", DelegationID: "manual-delegation-1", RunID: "manual-run-1", ImplementationID: *implementation, ImplementationRevision: 1, SourceRevision: "manual-source-1", WorktreeID: "manual-worktree-1", VerificationPlanRef: "manual-verification-1", CreatedAtUnixMillis: now.UnixMilli()} + store := &memoryStore{} + result, err := application.ExecuteCanaryDryRun(context.Background(), store, application.CanaryConfig{Enabled: *enabled, ImplementationID: "fake-worker", MaxDispatches: 1}, 0, intent, "manual-worker", 1, now, 15*time.Minute) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + output := struct { + DispatchID string `json:"dispatch_id"` + RunID string `json:"run_id"` + CallbackCount int `json:"callback_count"` + StoreWrites int `json:"store_writes"` + }{result.Intent.DispatchID, string(result.Intent.RunID), result.CallbackCount(), store.writes} + if err := json.NewEncoder(os.Stdout).Encode(output); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/dev/ACTIVE_TASK.json b/dev/ACTIVE_TASK.json index 92c2015..1a91cc4 100644 --- a/dev/ACTIVE_TASK.json +++ b/dev/ACTIVE_TASK.json @@ -1,5 +1,5 @@ { - "task_file": "dev/tasks/DEV-000124-agent-canary-gate.json", - "task_id": "DEV-000124", + "task_file": "dev/tasks/DEV-000125-agent-canary-cli.json", + "task_id": "DEV-000125", "task_revision": 1 } diff --git a/dev/tasks/DEV-000125-agent-canary-cli.json b/dev/tasks/DEV-000125-agent-canary-cli.json new file mode 100644 index 0000000..567ae00 --- /dev/null +++ b/dev/tasks/DEV-000125-agent-canary-cli.json @@ -0,0 +1,23 @@ +{ + "task_id": "DEV-000125", + "task_revision": 1, + "architecture_revision": "ADR-0018", + "base_repo_revision": "d2338b1", + "risk_tier": "E", + "intent": "Add a manually invoked CLI harness for the opt-in deterministic agent canary using an in-memory store.", + "requirement_ids": ["WP-301", "Manual canary entrypoint", "Dry-run verification"], + "allowed_change_scope": {"modules": ["work-agent-execution"], "paths": ["cmd/agent-canary/main.go", "dev/ACTIVE_TASK.json", "dev/tasks/DEV-000125-agent-canary-cli.json"]}, + "forbidden_change_scope": {"paths": ["architecture/**", "security/**", "deploy/**", "runtime/**", "adapters/**", "database/**", ".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": ["DEV-000124 canary gate"], "may_change": ["Manual CLI entrypoint"]}, + "semantic_owner": "work-agent-execution", + "canonical_state": ["No durable state; in-memory canary evidence only"], + "state_transitions": ["CLI flags -> canary gate -> deterministic callbacks -> JSON summary"], + "side_effects_and_privileges": ["No network, database, deployment or production mutation"], + "persistence_and_migrations": ["Explicitly does not use production repository"], + "failure_retry_restart": ["Disabled or unauthorized invocation exits nonzero without writes"], + "assumptions": ["Real WorkRepository wiring requires a separate approved runtime task"], + "acceptance_scenarios": ["Default invocation is rejected", "Explicit enablement produces JSON summary", "No secrets or external connections are required"], + "required_tests": ["go test ./...", "go vet ./...", "go run ./cmd/agent-canary", "go run ./cmd/agent-canary -enable-canary", "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"], + "terminal_gap_states": ["BLOCKED_BY_SPEC_GAP", "BLOCKED_BY_CONFLICT"] +}