main · last commit
13 days ago ·
7g0stsfu
ah-xuc.1 Stage 2 foundation: domain buckets/outcome, ports contracts, config surface
Past Stand
bd reopen ah-xuc.1
| Created by | Eugene Blikh |
| Owner | bigbes@gmail.com |
| Created | 2026-07-13T05:14:51Z |
| Started | 2026-07-13T05:19:13Z |
| Updated | 2026-07-13T05:44:24Z |
| Closed | 2026-07-13T05:44:24Z |
Every Stage 2 feature extends the shared contracts; land them first so later waves stay disjoint (SPEC section 13 isolation rule). No new external deps (crypto/hmac is stdlib, yaml.v3 already present) — go.mod stays untouched for the whole epic.
domain: OutcomeStalled ("stalled"); bucket-name constants for triage/blocked/question plus CanonicalBuckets() (States() plus the three — canonical buckets are a superset of states from now on); Run.Timeout time.Duration (0 = use config default).
ports: BoardTask.Labels []string (label titles); StartSpec.Skills []string (absolute skill dirs); Runner gains Publish(ctx, taskID) (PublishInfo, error) with PublishInfo{RemoteURL, Branch, WebURL} — zero-value info with nil error means publish not configured (skipped); error only on a real push failure. Document contracts in comments in the existing style.
config: vikunja.webhook_secret (optional); vikunja.web_url (optional, default = url with trailing /api/v1 stripped) for human task links; buckets now require all nine canonical keys (validate over domain.CanonicalBuckets()); skills_dir (optional path, tilde-expanded); task_types map[label-name]{role, model, skills, timeout — all optional} with validation (role exists, skill names are safe slugs — reuse validSlug, timeout parses positive, any skills referenced require skills_dir set); telegram optional block {token, chat_id, api_base default https://api.telegram.org} — token and chat_id required when the block is present; stall_timeout duration (default 10m, explicit "0" disables, otherwise at least 1m); repos[*].review_remote (optional git URL) and repos[*].review_url (optional template, must contain {branch} when set). Update config.example.yaml with commented examples of every new key.
go test ./internal/domain/... ./internal/config/... green; go vet clean on touched packages; table tests for nine-bucket validation, task_types, telegram block, stall_timeout, review_url template; config.example.yaml stays parseable; commits follow the area convention; only own packages staged
Coordinator refinements: (a) do NOT add a method to the ports.Runner interface — define a SEPARATE port Publisher { Publish(ctx, taskID) (PublishInfo, error) } plus the PublishInfo struct; the runner implements it in ah-xuc.5; this keeps every package (cmd, reconcile fakes) compiling between waves. (b) The nine-bucket requirement invalidates config fixtures outside internal/config: update cmd/agenthubd test fixtures AND the e2e harness fixtures (harness config + fake vikunja board columns Triage/Blocked/Question) in THIS bead — wave 1 runs solo so touching them is safe; goal: go test ./... and go test -tags e2e ./e2e/... stay green at every wave boundary. (c) vikunja.web_url default: vikunja.url with a trailing /api/v1 stripped. (d) stall_timeout: absent = 10m default; explicit "0" = disabled; the current parseDuration rejects nonpositive values, so handle the explicit zero separately. (e) review_url set without review_remote is a config error; review_remote alone is fine.
ah-xuc
— Stage 2: webhooks, Task Spec, full buckets, Telegram, srht push, watchdog
parent-child
closed
ah-xuc.7
— httpapi: Vikunja webhook receiver with HMAC verification
blocks
ah-xuc.2
— internal/spec: Task Spec frontmatter parse, type-label defaults, validation
blocks
ah-xuc.3
— vikunja: fetch task labels into BoardTask.Labels
blocks
ah-xuc.6
— telegram: ports.Notifier implementation (Bot API through HTTPS_PROXY)
blocks
ah-xuc.5
— runner: explicit --skill arguments and Publish to the review remote
blocks
ah-xuc.4
— store: migration v2 — per-run timeout column
blocks
ah-xuc.7
— httpapi: Vikunja webhook receiver with HMAC verification
blocks
closed
ah-xuc.10
— cmd/agenthubd: wire webhook secret and Telegram notifier
blocks
closed
ah-xuc.11
— e2e: Stage 2 flows — webhook poke, Triage bounce, skills, publish, watchdog, Telegram
blocks
closed
ah-xuc.12
— docs: sync SPEC with Stage 2 behavior
blocks
closed
ah-xuc.2
— internal/spec: Task Spec frontmatter parse, type-label defaults, validation
blocks
closed
ah-xuc.8
— reconcile: spec-driven claim, Triage bounce, parked buckets, per-run timeout
blocks
closed
ah-xuc.9
— reconcile: publish review branch, watchdog on stale events, Telegram notifications
blocks
closed
ah-xuc.3
— vikunja: fetch task labels into BoardTask.Labels
blocks
closed
ah-xuc.6
— telegram: ports.Notifier implementation (Bot API through HTTPS_PROXY)
blocks
closed
ah-xuc.5
— runner: explicit --skill arguments and Publish to the review remote
blocks
closed
ah-xuc.4
— store: migration v2 — per-run timeout column
blocks
closed
| id | ah-xuc.1 |
| content_hash | a152c1dd582b5477ff993f9f0c070eea86bf5d7994ae57afd24f3cbf8ac4394f |
| title | Stage 2 foundation: domain buckets/outcome, ports contracts, config surface |
| description | Every Stage 2 feature extends the shared contracts; land them first so later waves stay disjoint (SPEC section 13 isolation rule). No new external deps (crypto/hmac is stdlib, yaml.v3 already present) — go.mod stays untouched for the whole epic. domain: OutcomeStalled ("stalled"); bucket-name constants for triage/blocked/question plus CanonicalBuckets() (States() plus the three — canonical buckets are a superset of states from now on); Run.Timeout time.Duration (0 = use config default). ports: BoardTask.Labels []string (label titles); StartSpec.Skills []string (absolute skill dirs); Runner gains Publish(ctx, taskID) (PublishInfo, error) with PublishInfo{RemoteURL, Branch, WebURL} — zero-value info with nil error means publish not configured (skipped); error only on a real push failure. Document contracts in comments in the existing style. config: vikunja.webhook_secret (optional); vikunja.web_url (optional, default = url with trailing /api/v1 stripped) for human task links; buckets now require all nine canonical keys (validate over domain.CanonicalBuckets()); skills_dir (optional path, tilde-expanded); task_types map[label-name]{role, model, skills, timeout — all optional} with validation (role exists, skill names are safe slugs — reuse validSlug, timeout parses positive, any skills referenced require skills_dir set); telegram optional block {token, chat_id, api_base default https://api.telegram.org} — token and chat_id required when the block is present; stall_timeout duration (default 10m, explicit "0" disables, otherwise at least 1m); repos[*].review_remote (optional git URL) and repos[*].review_url (optional template, must contain {branch} when set). Update config.example.yaml with commented examples of every new key. |
| design | |
| acceptance_criteria | go test ./internal/domain/... ./internal/config/... green; go vet clean on touched packages; table tests for nine-bucket validation, task_types, telegram block, stall_timeout, review_url template; config.example.yaml stays parseable; commits follow the area convention; only own packages staged |
| notes | Coordinator refinements: (a) do NOT add a method to the ports.Runner interface — define a SEPARATE port Publisher { Publish(ctx, taskID) (PublishInfo, error) } plus the PublishInfo struct; the runner implements it in ah-xuc.5; this keeps every package (cmd, reconcile fakes) compiling between waves. (b) The nine-bucket requirement invalidates config fixtures outside internal/config: update cmd/agenthubd test fixtures AND the e2e harness fixtures (harness config + fake vikunja board columns Triage/Blocked/Question) in THIS bead — wave 1 runs solo so touching them is safe; goal: go test ./... and go test -tags e2e ./e2e/... stay green at every wave boundary. (c) vikunja.web_url default: vikunja.url with a trailing /api/v1 stripped. (d) stall_timeout: absent = 10m default; explicit "0" = disabled; the current parseDuration rejects nonpositive values, so handle the explicit zero separately. (e) review_url set without review_remote is a config error; review_remote alone is fine. |
| status | closed |
| priority | 2 |
| issue_type | task |
| assignee | Eugene Blikh |
| estimated_minutes | NULL |
| created_at | 2026-07-13T05:14:51Z |
| created_by | Eugene Blikh |
| owner | bigbes@gmail.com |
| updated_at | 2026-07-13T05:44:24Z |
| closed_at | 2026-07-13T05:44:24Z |
| closed_by_session | |
| external_ref | NULL |
| spec_id | |
| compaction_level | 0 |
| compacted_at | NULL |
| compacted_at_commit | NULL |
| original_size | NULL |
| sender | |
| ephemeral | 0 |
| wisp_type | |
| pinned | 0 |
| is_template | 0 |
| mol_type | |
| work_type | |
| source_system | |
| metadata | �{} |
| source_repo | |
| close_reason | 4 commits landed (3c3e558..7b158c8); hostile review merge-ready with zero findings; empirical validation 8/9 (only pre-existing gofmt debt, pinned to ah-xuc.8) |
| event_kind | |
| actor | |
| target | |
| payload | |
| await_type | |
| await_id | |
| timeout_ns | 0 |
| waiters | |
| hook_bead | |
| role_bead | |
| agent_state | |
| last_activity | NULL |
| role_type | |
| rig | |
| due_at | NULL |
| defer_until | NULL |
| no_history | 0 |
| started_at | 2026-07-13T05:19:13Z |
| is_blocked | 0 |
| id | 37f3de87-cff8-5310-896f-877fce7a1f82 |
| issue_id | ah-xuc.7 |
| type | blocks |
| created_at | 2026-07-13T08:16:50Z |
| created_by | Eugene Blikh |
| metadata | �{} |
| thread_id | |
| depends_on_issue_id | ah-xuc.1 |
| depends_on_wisp_id | NULL |
| depends_on_external | NULL |
| id | 63d4cba5-bfba-51a5-b90c-6a0050f54b13 |
| issue_id | ah-xuc.1 |
| type | parent-child |
| created_at | 2026-07-13T08:14:51Z |
| created_by | Eugene Blikh |
| metadata | �{} |
| thread_id | |
| depends_on_issue_id | ah-xuc |
| depends_on_wisp_id | NULL |
| depends_on_external | NULL |
| id | 8125fd31-7552-5d90-b0ce-82dad1547ce3 |
| issue_id | ah-xuc.2 |
| type | blocks |
| created_at | 2026-07-13T08:16:47Z |
| created_by | Eugene Blikh |
| metadata | �{} |
| thread_id | |
| depends_on_issue_id | ah-xuc.1 |
| depends_on_wisp_id | NULL |
| depends_on_external | NULL |
| id | 868f6fd7-1796-5317-8bda-8e697ce95b71 |
| issue_id | ah-xuc.3 |
| type | blocks |
| created_at | 2026-07-13T08:16:48Z |
| created_by | Eugene Blikh |
| metadata | �{} |
| thread_id | |
| depends_on_issue_id | ah-xuc.1 |
| depends_on_wisp_id | NULL |
| depends_on_external | NULL |
| id | 8cd2a6e1-5f59-5510-a31a-33777006c01a |
| issue_id | ah-xuc.6 |
| type | blocks |
| created_at | 2026-07-13T08:16:49Z |
| created_by | Eugene Blikh |
| metadata | �{} |
| thread_id | |
| depends_on_issue_id | ah-xuc.1 |
| depends_on_wisp_id | NULL |
| depends_on_external | NULL |
| id | ab8333ca-811e-57f0-806b-928b8bb24c7e |
| issue_id | ah-xuc.5 |
| type | blocks |
| created_at | 2026-07-13T08:16:49Z |
| created_by | Eugene Blikh |
| metadata | �{} |
| thread_id | |
| depends_on_issue_id | ah-xuc.1 |
| depends_on_wisp_id | NULL |
| depends_on_external | NULL |
| id | e38b6dff-46bf-5af3-baa9-d7fcf5c17477 |
| issue_id | ah-xuc.4 |
| type | blocks |
| created_at | 2026-07-13T08:16:48Z |
| created_by | Eugene Blikh |
| metadata | �{} |
| thread_id | |
| depends_on_issue_id | ah-xuc.1 |
| depends_on_wisp_id | NULL |
| depends_on_external | NULL |
| id | 019f59e6-461e-7860-834a-a6fc38027e10 |
| issue_id | ah-xuc.1 |
| event_type | created |
| actor | Eugene Blikh |
| old_value | |
| new_value | |
| comment | NULL |
| created_at | 2026-07-13T08:14:51Z |
| id | 019f59ea-3da2-7111-a3a4-0c69038932b3 |
| issue_id | ah-xuc.1 |
| event_type | updated |
| actor | Eugene Blikh |
| old_value | {"id":"ah-xuc.1","title":"Stage 2 foundation: domain buckets/outcome, ports contracts, config surface","description":"Every Stage 2 feature extends the shared contracts; land them first so later waves stay disjoint (SPEC section 13 isolation rule). No new external deps (crypto/hmac is stdlib, yaml.v3 already present) — go.mod stays untouched for the whole epic.\n\ndomain: OutcomeStalled (\"stalled\"); bucket-name constants for triage/blocked/question plus CanonicalBuckets() (States() plus the three — canonical buckets are a superset of states from now on); Run.Timeout time.Duration (0 = use config default).\n\nports: BoardTask.Labels []string (label titles); StartSpec.Skills []string (absolute skill dirs); Runner gains Publish(ctx, taskID) (PublishInfo, error) with PublishInfo{RemoteURL, Branch, WebURL} — zero-value info with nil error means publish not configured (skipped); error only on a real push failure. Document contracts in comments in the existing style.\n\nconfig: vikunja.webhook_secret (optional); vikunja.web_url (optional, default = url with trailing /api/v1 stripped) for human task links; buckets now require all nine canonical keys (validate over domain.CanonicalBuckets()); skills_dir (optional path, tilde-expanded); task_types map[label-name]{role, model, skills, timeout — all optional} with validation (role exists, skill names are safe slugs — reuse validSlug, timeout parses positive, any skills referenced require skills_dir set); telegram optional block {token, chat_id, api_base default https://api.telegram.org} — token and chat_id required when the block is present; stall_timeout duration (default 10m, explicit \"0\" disables, otherwise at least 1m); repos[*].review_remote (optional git URL) and repos[*].review_url (optional template, must contain {branch} when set). Update config.example.yaml with commented examples of every new key.","acceptance_criteria":"go test ./internal/domain/... ./internal/config/... green; go vet clean on touched packages; table tests for nine-bucket validation, task_types, telegram block, stall_timeout, review_url template; config.example.yaml stays parseable; commits follow the area convention; only own packages staged","status":"open","priority":2,"issue_type":"task","owner":"bigbes@gmail.com","created_at":"2026-07-13T05:14:51Z","created_by":"Eugene Blikh","updated_at":"2026-07-13T05:14:51Z"} |
| new_value | {"notes":"Coordinator refinements: (a) do NOT add a method to the ports.Runner interface — define a SEPARATE port Publisher { Publish(ctx, taskID) (PublishInfo, error) } plus the PublishInfo struct; the runner implements it in ah-xuc.5; this keeps every package (cmd, reconcile fakes) compiling between waves. (b) The nine-bucket requirement invalidates config fixtures outside internal/config: update cmd/agenthubd test fixtures AND the e2e harness fixtures (harness config + fake vikunja board columns Triage/Blocked/Question) in THIS bead — wave 1 runs solo so touching them is safe; goal: go test ./... and go test -tags e2e ./e2e/... stay green at every wave boundary. (c) vikunja.web_url default: vikunja.url with a trailing /api/v1 stripped. (d) stall_timeout: absent = 10m default; explicit \"0\" = disabled; the current parseDuration rejects nonpositive values, so handle the explicit zero separately. (e) review_url set without review_remote is a config error; review_remote alone is fine."} |
| comment | NULL |
| created_at | 2026-07-13T08:19:11Z |
| id | 019f59ea-43f2-7392-af22-238c6c9ce41f |
| issue_id | ah-xuc.1 |
| event_type | claimed |
| actor | Eugene Blikh |
| old_value | {"id":"ah-xuc.1","title":"Stage 2 foundation: domain buckets/outcome, ports contracts, config surface","description":"Every Stage 2 feature extends the shared contracts; land them first so later waves stay disjoint (SPEC section 13 isolation rule). No new external deps (crypto/hmac is stdlib, yaml.v3 already present) — go.mod stays untouched for the whole epic.\n\ndomain: OutcomeStalled (\"stalled\"); bucket-name constants for triage/blocked/question plus CanonicalBuckets() (States() plus the three — canonical buckets are a superset of states from now on); Run.Timeout time.Duration (0 = use config default).\n\nports: BoardTask.Labels []string (label titles); StartSpec.Skills []string (absolute skill dirs); Runner gains Publish(ctx, taskID) (PublishInfo, error) with PublishInfo{RemoteURL, Branch, WebURL} — zero-value info with nil error means publish not configured (skipped); error only on a real push failure. Document contracts in comments in the existing style.\n\nconfig: vikunja.webhook_secret (optional); vikunja.web_url (optional, default = url with trailing /api/v1 stripped) for human task links; buckets now require all nine canonical keys (validate over domain.CanonicalBuckets()); skills_dir (optional path, tilde-expanded); task_types map[label-name]{role, model, skills, timeout — all optional} with validation (role exists, skill names are safe slugs — reuse validSlug, timeout parses positive, any skills referenced require skills_dir set); telegram optional block {token, chat_id, api_base default https://api.telegram.org} — token and chat_id required when the block is present; stall_timeout duration (default 10m, explicit \"0\" disables, otherwise at least 1m); repos[*].review_remote (optional git URL) and repos[*].review_url (optional template, must contain {branch} when set). Update config.example.yaml with commented examples of every new key.","acceptance_criteria":"go test ./internal/domain/... ./internal/config/... green; go vet clean on touched packages; table tests for nine-bucket validation, task_types, telegram block, stall_timeout, review_url template; config.example.yaml stays parseable; commits follow the area convention; only own packages staged","notes":"Coordinator refinements: (a) do NOT add a method to the ports.Runner interface — define a SEPARATE port Publisher { Publish(ctx, taskID) (PublishInfo, error) } plus the PublishInfo struct; the runner implements it in ah-xuc.5; this keeps every package (cmd, reconcile fakes) compiling between waves. (b) The nine-bucket requirement invalidates config fixtures outside internal/config: update cmd/agenthubd test fixtures AND the e2e harness fixtures (harness config + fake vikunja board columns Triage/Blocked/Question) in THIS bead — wave 1 runs solo so touching them is safe; goal: go test ./... and go test -tags e2e ./e2e/... stay green at every wave boundary. (c) vikunja.web_url default: vikunja.url with a trailing /api/v1 stripped. (d) stall_timeout: absent = 10m default; explicit \"0\" = disabled; the current parseDuration rejects nonpositive values, so handle the explicit zero separately. (e) review_url set without review_remote is a config error; review_remote alone is fine.","status":"open","priority":2,"issue_type":"task","owner":"bigbes@gmail.com","created_at":"2026-07-13T05:14:51Z","created_by":"Eugene Blikh","updated_at":"2026-07-13T05:19:11Z"} |
| new_value | {"assignee":"Eugene Blikh","status":"in_progress"} |
| comment | NULL |
| created_at | 2026-07-13T08:19:12Z |
| id | 019f59ea-4560-77fe-be93-8b7b7663999c |
| issue_id | ah-xuc.1 |
| event_type | status_changed |
| actor | Eugene Blikh |
| old_value | {"id":"ah-xuc.1","title":"Stage 2 foundation: domain buckets/outcome, ports contracts, config surface","description":"Every Stage 2 feature extends the shared contracts; land them first so later waves stay disjoint (SPEC section 13 isolation rule). No new external deps (crypto/hmac is stdlib, yaml.v3 already present) — go.mod stays untouched for the whole epic.\n\ndomain: OutcomeStalled (\"stalled\"); bucket-name constants for triage/blocked/question plus CanonicalBuckets() (States() plus the three — canonical buckets are a superset of states from now on); Run.Timeout time.Duration (0 = use config default).\n\nports: BoardTask.Labels []string (label titles); StartSpec.Skills []string (absolute skill dirs); Runner gains Publish(ctx, taskID) (PublishInfo, error) with PublishInfo{RemoteURL, Branch, WebURL} — zero-value info with nil error means publish not configured (skipped); error only on a real push failure. Document contracts in comments in the existing style.\n\nconfig: vikunja.webhook_secret (optional); vikunja.web_url (optional, default = url with trailing /api/v1 stripped) for human task links; buckets now require all nine canonical keys (validate over domain.CanonicalBuckets()); skills_dir (optional path, tilde-expanded); task_types map[label-name]{role, model, skills, timeout — all optional} with validation (role exists, skill names are safe slugs — reuse validSlug, timeout parses positive, any skills referenced require skills_dir set); telegram optional block {token, chat_id, api_base default https://api.telegram.org} — token and chat_id required when the block is present; stall_timeout duration (default 10m, explicit \"0\" disables, otherwise at least 1m); repos[*].review_remote (optional git URL) and repos[*].review_url (optional template, must contain {branch} when set). Update config.example.yaml with commented examples of every new key.","acceptance_criteria":"go test ./internal/domain/... ./internal/config/... green; go vet clean on touched packages; table tests for nine-bucket validation, task_types, telegram block, stall_timeout, review_url template; config.example.yaml stays parseable; commits follow the area convention; only own packages staged","notes":"Coordinator refinements: (a) do NOT add a method to the ports.Runner interface — define a SEPARATE port Publisher { Publish(ctx, taskID) (PublishInfo, error) } plus the PublishInfo struct; the runner implements it in ah-xuc.5; this keeps every package (cmd, reconcile fakes) compiling between waves. (b) The nine-bucket requirement invalidates config fixtures outside internal/config: update cmd/agenthubd test fixtures AND the e2e harness fixtures (harness config + fake vikunja board columns Triage/Blocked/Question) in THIS bead — wave 1 runs solo so touching them is safe; goal: go test ./... and go test -tags e2e ./e2e/... stay green at every wave boundary. (c) vikunja.web_url default: vikunja.url with a trailing /api/v1 stripped. (d) stall_timeout: absent = 10m default; explicit \"0\" = disabled; the current parseDuration rejects nonpositive values, so handle the explicit zero separately. (e) review_url set without review_remote is a config error; review_remote alone is fine.","status":"in_progress","priority":2,"issue_type":"task","assignee":"Eugene Blikh","owner":"bigbes@gmail.com","created_at":"2026-07-13T05:14:51Z","created_by":"Eugene Blikh","updated_at":"2026-07-13T05:19:13Z","started_at":"2026-07-13T05:19:13Z"} |
| new_value | {"status":"in_progress"} |
| comment | NULL |
| created_at | 2026-07-13T08:19:13Z |
| id | 019f5a01-510c-7023-85d5-c13bbe0b3b86 |
| issue_id | ah-xuc.1 |
| event_type | closed |
| actor | Eugene Blikh |
| old_value | |
| new_value | 4 commits landed (3c3e558..7b158c8); hostile review merge-ready with zero findings; empirical validation 8/9 (only pre-existing gofmt debt, pinned to ah-xuc.8) |
| comment | NULL |
| created_at | 2026-07-13T08:44:23Z |
| id | 019f7cda-9356-7e34-976b-c0229fea64ab |
| issue_id | ah-xuc.1 |
| event_type | label_added |
| actor | Eugene Blikh |
| old_value | NULL |
| new_value | NULL |
| comment | Added label: milestone:stage-2 |
| created_at | 2026-07-20T03:08:47Z |
| id | 019f7cdc-0c1f-7372-8b3a-91cc2168d4dc |
| issue_id | ah-xuc.1 |
| event_type | label_removed |
| actor | Eugene Blikh |
| old_value | NULL |
| new_value | NULL |
| comment | Removed label: milestone:stage-2 |
| created_at | 2026-07-20T03:10:23Z |
No comments.
Close reason