From 8e26826ae2a615a12d94d8b1460ca78796609d19 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Sat, 22 Aug 2026 12:20:14 +0300 Subject: [PATCH] feat(work): wire canary cli to work repository --- cmd/agent-canary/main.go | 23 +++++++++++++++++-- dev/ACTIVE_TASK.json | 4 ++-- .../DEV-000126-agent-canary-repository.json | 23 +++++++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 dev/tasks/DEV-000126-agent-canary-repository.json diff --git a/cmd/agent-canary/main.go b/cmd/agent-canary/main.go index 6034b48..5fc397b 100644 --- a/cmd/agent-canary/main.go +++ b/cmd/agent-canary/main.go @@ -8,8 +8,10 @@ import ( "os" "time" + "git.cin.su/m/Assistant/adapters/postgres" "git.cin.su/m/Assistant/contracts/work" "git.cin.su/m/Assistant/modules/work/application" + "git.cin.su/m/Assistant/modules/work/ports" ) type memoryStore struct{ writes int } @@ -27,11 +29,25 @@ func (s *memoryStore) AcceptAgentCallback(context.Context, work.AgentCallback) e func main() { enabled := flag.Bool("enable-canary", false, "explicitly enable the manual canary") implementation := flag.String("implementation", "fake-worker", "allowlisted deterministic implementation") + postgresMode := flag.Bool("postgres", false, "use the Work PostgreSQL repository instead of in-memory storage") 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{} + var store ports.ExecutionStore = &memoryStore{} + var closeStore func() + if *postgresMode { + repository, err := postgres.OpenWork(context.Background(), postgres.ContinuityConfig{Host: os.Getenv("POSTGRES_HOST"), Port: os.Getenv("POSTGRES_PORT"), Database: os.Getenv("POSTGRES_DATABASE"), User: os.Getenv("WORK_POSTGRES_USER"), Password: os.Getenv("WORK_POSTGRES_PASSWORD")}) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + store = repository + closeStore = repository.Close + } + if closeStore != nil { + defer closeStore() + } 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) @@ -42,7 +58,10 @@ func main() { 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} + }{result.Intent.DispatchID, string(result.Intent.RunID), result.CallbackCount(), 0} + if memory, ok := store.(*memoryStore); ok { + output.StoreWrites = memory.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 1a91cc4..8884878 100644 --- a/dev/ACTIVE_TASK.json +++ b/dev/ACTIVE_TASK.json @@ -1,5 +1,5 @@ { - "task_file": "dev/tasks/DEV-000125-agent-canary-cli.json", - "task_id": "DEV-000125", + "task_file": "dev/tasks/DEV-000126-agent-canary-repository.json", + "task_id": "DEV-000126", "task_revision": 1 } diff --git a/dev/tasks/DEV-000126-agent-canary-repository.json b/dev/tasks/DEV-000126-agent-canary-repository.json new file mode 100644 index 0000000..c19f925 --- /dev/null +++ b/dev/tasks/DEV-000126-agent-canary-repository.json @@ -0,0 +1,23 @@ +{ + "task_id": "DEV-000126", + "task_revision": 1, + "architecture_revision": "ADR-0018", + "base_repo_revision": "c30e0c7", + "risk_tier": "E", + "intent": "Wire the manual agent canary CLI to the existing Work PostgreSQL repository behind an explicit flag while preserving in-memory default behavior.", + "requirement_ids": ["WP-301", "Repository canary wiring", "Credential-safe adapter use"], + "allowed_change_scope": {"modules": ["work-agent-execution", "work-storage"], "paths": ["cmd/agent-canary/main.go", "dev/ACTIVE_TASK.json", "dev/tasks/DEV-000126-agent-canary-repository.json"]}, + "forbidden_change_scope": {"paths": ["architecture/**", "security/**", "deploy/**", "runtime/**", "database/**", ".gitea/**"]}, + "allowed_architecture_delta": {"new_cross_module_dependencies": 1, "new_canonical_owners": 0, "new_privileges": 0, "new_third_party_dependencies": 0, "new_database_owner_roles": 0}, + "contracts": {"consume": ["DEV-000125 manual canary CLI", "DEV-000121 WorkRepository methods"], "may_change": ["Manual CLI storage selection"]}, + "semantic_owner": "work-agent-execution", + "canonical_state": ["WorkRepository remains canonical for postgres mode"], + "state_transitions": ["CLI -postgres -> OpenWork -> canary coordinator -> repository writes"], + "side_effects_and_privileges": ["Only explicit -postgres mode connects; credentials come from existing environment variables and are never printed"], + "persistence_and_migrations": ["Requires migration 029 to be applied separately; this task does not apply migrations"], + "failure_retry_restart": ["Connection or missing migration errors are returned; no automatic retry or deployment"], + "assumptions": ["Default mode remains in-memory and production entrypoints are unchanged"], + "acceptance_scenarios": ["Default mode remains deterministic", "Postgres mode uses Work repository through ExecutionStore", "No secret values appear in output"], + "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_MIGRATION_DECISION", "BLOCKED_BY_SPEC_GAP", "BLOCKED_BY_CONFLICT"] +}