~bigbes/agents-dev · parade

main · last commit 13 days ago · 7g0stsfu

← Back to the parade

ah-xuc Stage 2: webhooks, Task Spec, full buckets, Telegram, srht push, watchdog epic Past Stand

status: closed P3 epic
bd reopen ah-xuc
Created byEugene Blikh
Ownerbigbes@gmail.com
Created2026-07-12T23:36:28Z
Updated2026-07-13T08:38:18Z
Closed2026-07-13T08:38:18Z
Description
Per SPEC SS14.2: Vikunja webhook receiver (HMAC) as reconciler poke; Task Spec YAML frontmatter (role/model/skills/limits) + label type defaults + validation -> Triage bounce; buckets Triage/Blocked/Question; Telegram notifier (honor HTTPS_PROXY; TG blocked from lab network); push agent/task-N branch to git.srht.bigb.es for review + link in In Review comment; watchdog on stale events.jsonl; pi --skill materialization from /srv/skills.
Design
Stage 2 design decisions (coordinator, 2026-07-13):
1. Webhook: POST /webhooks/vikunja on the SAME loopback mux; exposure to Vikunja is infra (ah-k23, tunnel/reverse-proxy). Hex HMAC-SHA256 of the raw body in X-Vikunja-Signature, constant-time compare; secret vikunja.webhook_secret; unset secret = route not registered. Any verified event = Poke(); payload untrusted beyond event_name logging. Poll loop remains the source of truth (Vikunja delivers webhooks once, no retries).
2. Buckets: triage/blocked/question are PARKED buckets — mapped and title-validated, never claim sources, never kill triggers, detached runtime supervision only. Triage is the bounce target for spec validation failures (not Failed — the human fixes and re-drags). Blocked/Question earn real semantics in Stage 4. domain.CanonicalBuckets() = States() + the three; buckets are a superset of states; config requires all nine keys.
3. Task Spec: YAML frontmatter (--- delimited) at the head of the description. Fields: role, model, skills, timeout. Merge precedence: config defaults < type:<name> label preset (config task_types) < frontmatter. Multiple type:* labels or an unknown type = validation error. Unknown frontmatter fields = warnings appended to the claim comment, never a bounce. Prompt renders over the frontmatter-stripped body.
4. Skills: names are safe slugs; resolved to <skills_dir>/<name>; SKILL.md must exist with a non-empty frontmatter description (pi refuses skills without one). pi argv keeps --no-skills --no-extensions and adds explicit --skill <abs> per skill — deterministic set.
5. Per-run timeout: effective value (spec/type override or config default) persisted on the run row (migration v2, runs.timeout_seconds, 0 = config default) so restarts enforce the right deadline.
6. Watchdog: stalled = Running and now - max(events.jsonl mtime, StartedAt) > stall_timeout (default 10m, 0 disables, else >= 1m). Kill + finalize OutcomeStalled/exit -1. Neither-state observation stays deadline-only.
7. Telegram: optional config block {token, chat_id, api_base}; default-transport proxy semantics honor HTTPS_PROXY; notify is best-effort after move+comment on finalize (success/failed/timeout/stalled) and spec bounce; token redacted from errors/logs. Unconfigured = existing slog no-op.
8. Publish: Runner.Publish(ctx, taskID) -> PublishInfo{RemoteURL, Branch, WebURL}; plain git push of agent/task-N to per-repo review_remote (never force); zero info + nil err = not configured; failure degrades to a push-failed line in the In Review comment; re-push on refinalize is idempotent. review_url template with {branch} builds the human link.
9. vikunja.web_url (default: url minus /api/v1) builds human task links for comments and notifications.
10. Scope cuts: NO worker pool / max_parallel in Stage 2 (research mentions it; epic and SPEC roadmap do not). No repo selection via spec (multi-repo is Stage 5). No new external deps.
Infra prerequisites tracked in ah-k23: three new board columns (Triage/Blocked/Question), Vikunja webhook target+secret, srht repos + SSH key for the daemon user, TG bot token + proxy path.

Subtasks 12 of 12 done

  • ah-xuc.1 — Stage 2 foundation: domain buckets/outcome, ports contracts, config surface P2 closed @Eugene Blikh
  • ah-xuc.10 — cmd/agenthubd: wire webhook secret and Telegram notifier P2 closed @Eugene Blikh
  • ah-xuc.11 — e2e: Stage 2 flows — webhook poke, Triage bounce, skills, publish, watchdog, Telegram P2 closed @Eugene Blikh
  • ah-xuc.12 — docs: sync SPEC with Stage 2 behavior P2 closed @Eugene Blikh
  • ah-xuc.2 — internal/spec: Task Spec frontmatter parse, type-label defaults, validation P2 closed @Eugene Blikh
  • ah-xuc.3 — vikunja: fetch task labels into BoardTask.Labels P2 closed @Eugene Blikh
  • ah-xuc.4 — store: migration v2 — per-run timeout column P2 closed @Eugene Blikh
  • ah-xuc.5 — runner: explicit --skill arguments and Publish to the review remote P2 closed @Eugene Blikh
  • ah-xuc.6 — telegram: ports.Notifier implementation (Bot API through HTTPS_PROXY) P2 closed @Eugene Blikh
  • ah-xuc.7 — httpapi: Vikunja webhook receiver with HMAC verification P2 closed @Eugene Blikh
  • ah-xuc.8 — reconcile: spec-driven claim, Triage bounce, parked buckets, per-run timeout P2 closed @Eugene Blikh
  • ah-xuc.9 — reconcile: publish review branch, watchdog on stale events, Telegram notifications P2 closed @Eugene Blikh

Depends on

No outgoing dependencies.

Depended on by

  • ah-xuc.10 — cmd/agenthubd: wire webhook secret and Telegram notifier parent-child
  • ah-xuc.5 — runner: explicit --skill arguments and Publish to the review remote parent-child
  • ah-xuc.2 — internal/spec: Task Spec frontmatter parse, type-label defaults, validation parent-child
  • ah-xuc.7 — httpapi: Vikunja webhook receiver with HMAC verification parent-child
  • ah-xuc.8 — reconcile: spec-driven claim, Triage bounce, parked buckets, per-run timeout parent-child
  • ah-xuc.4 — store: migration v2 — per-run timeout column parent-child
  • ah-xuc.1 — Stage 2 foundation: domain buckets/outcome, ports contracts, config surface parent-child
  • ah-xuc.12 — docs: sync SPEC with Stage 2 behavior parent-child
  • ah-xuc.6 — telegram: ports.Notifier implementation (Bot API through HTTPS_PROXY) parent-child
  • ah-xuc.11 — e2e: Stage 2 flows — webhook poke, Triage bounce, skills, publish, watchdog, Telegram parent-child
  • ah-xuc.9 — reconcile: publish review branch, watchdog on stale events, Telegram notifications parent-child
  • ah-xuc.3 — vikunja: fetch task labels into BoardTask.Labels parent-child

Unblocks — everything waiting on this, transitively

  • ah-xuc.10 — cmd/agenthubd: wire webhook secret and Telegram notifier parent-child 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.5 — runner: explicit --skill arguments and Publish to the review remote parent-child closed
  • ah-xuc.2 — internal/spec: Task Spec frontmatter parse, type-label defaults, validation parent-child 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.7 — httpapi: Vikunja webhook receiver with HMAC verification parent-child closed
  • ah-xuc.4 — store: migration v2 — per-run timeout column parent-child closed
  • ah-xuc.1 — Stage 2 foundation: domain buckets/outcome, ports contracts, config surface parent-child 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

No comments.

Close reason

Stage 2 delivered: 21 commits b3ee57d..HEAD (webhook HMAC poke, Task Spec frontmatter + type-label presets + Triage bounce, parked buckets Triage/Blocked/Question, per-run timeout with store v2, stall watchdog, Telegram notifier via HTTPS_PROXY, review-branch publish to srht remotes with bounded push, e2e flows, SPEC synced to Stages 1-2). Every wave gated by hostile review + empirical validation; final epic-wide gate 11/11. Runtime prerequisites (board columns, webhook target, srht repos, TG bot) remain in ah-k23.
  • Eugene Blikh created the issue · 2026-07-13T02:36:27Z
  • Eugene Blikh added subtask ah-xuc.1 · 2026-07-13T08:14:51Z
  • Eugene Blikh added subtask ah-xuc.2 · 2026-07-13T08:15:07Z
  • Eugene Blikh added subtask ah-xuc.3 · 2026-07-13T08:15:10Z
  • Eugene Blikh added subtask ah-xuc.4 · 2026-07-13T08:15:21Z
  • Eugene Blikh added subtask ah-xuc.5 · 2026-07-13T08:15:26Z
  • Eugene Blikh added subtask ah-xuc.6 · 2026-07-13T08:15:38Z
  • Eugene Blikh added subtask ah-xuc.7 · 2026-07-13T08:15:43Z
  • Eugene Blikh added subtask ah-xuc.8 · 2026-07-13T08:15:59Z
  • Eugene Blikh added subtask ah-xuc.9 · 2026-07-13T08:16:06Z
  • Eugene Blikh added subtask ah-xuc.10 · 2026-07-13T08:16:17Z
  • Eugene Blikh added subtask ah-xuc.11 · 2026-07-13T08:16:24Z
  • Eugene Blikh added subtask ah-xuc.12 · 2026-07-13T08:16:35Z
  • Eugene Blikh updated design to Stage 2 design decisions (coordinator, 2026-07-13): 1. Webhook: POST /webhooks/vikunja on the SAME loopback mux; exposure to Vikunja is infra (ah-k23, tunnel/reverse-proxy). Hex HMAC-SHA256 of the raw body in X-Vikunja-Signature, constant-time compare; secret vikunja.webhook_secret; unset secret = route not registered. Any verified event = Poke(); payload untrusted beyond event_name logging. Poll loop remains the source of truth (Vikunja delivers webhooks once, no retries). 2. Buckets: triage/blocked/question are PARKED buckets — mapped and title-validated, never claim sources, never kill triggers, detached runtime supervision only. Triage is the bounce target for spec validation failures (not Failed — the human fixes and re-drags). Blocked/Question earn real semantics in Stage 4. domain.CanonicalBuckets() = States() + the three; buckets are a superset of states; config requires all nine keys. 3. Task Spec: YAML frontmatter (--- delimited) at the head of the description. Fields: role, model, skills, timeout. Merge precedence: config defaults < type:<name> label preset (config task_types) < frontmatter. Multiple type:* labels or an unknown type = validation error. Unknown frontmatter fields = warnings appended to the claim comment, never a bounce. Prompt renders over the frontmatter-stripped body. 4. Skills: names are safe slugs; resolved to <skills_dir>/<name>; SKILL.md must exist with a non-empty frontmatter description (pi refuses skills without one). pi argv keeps --no-skills --no-extensions and adds explicit --skill <abs> per skill — deterministic set. 5. Per-run timeout: effective value (spec/type override or config default) persisted on the run row (migration v2, runs.timeout_seconds, 0 = config default) so restarts enforce the right deadline. 6. Watchdog: stalled = Running and now - max(events.jsonl mtime, StartedAt) > stall_timeout (default 10m, 0 disables, else >= 1m). Kill + finalize OutcomeStalled/exit -1. Neither-state observation stays deadline-only. 7. Telegram: optional config block {token, chat_id, api_base}; default-transport proxy semantics honor HTTPS_PROXY; notify is best-effort after move+comment on finalize (success/failed/timeout/stalled) and spec bounce; token redacted from errors/logs. Unconfigured = existing slog no-op. 8. Publish: Runner.Publish(ctx, taskID) -> PublishInfo{RemoteURL, Branch, WebURL}; plain git push of agent/task-N to per-repo review_remote (never force); zero info + nil err = not configured; failure degrades to a push-failed line in the In Review comment; re-push on refinalize is idempotent. review_url template with {branch} builds the human link. 9. vikunja.web_url (default: url minus /api/v1) builds human task links for comments and notifications. 10. Scope cuts: NO worker pool / max_parallel in Stage 2 (research mentions it; epic and SPEC roadmap do not). No repo selection via spec (multi-repo is Stage 5). No new external deps. Infra prerequisites tracked in ah-k23: three new board columns (Triage/Blocked/Question), Vikunja webhook target+secret, srht repos + SSH key for the daemon user, TG bot token + proxy path. · 2026-07-13T08:17:17Z
  • Eugene Blikh closed the issue · 2026-07-13T11:38:18Z
    Stage 2 delivered: 21 commits b3ee57d..HEAD (webhook HMAC poke, Task Spec frontmatter + type-label presets + Triage bounce, parked buckets Triage/Blocked/Question, per-run timeout with store v2, stall watchdog, Telegram notifier via HTTPS_PROXY, review-branch publish to srht remotes with bounded push, e2e flows, SPEC synced to Stages 1-2). Every wave gated by hostile review + empirical validation; final epic-wide gate 11/11. Runtime prerequisites (board columns, webhook target, srht repos, TG bot) remain in ah-k23.
  • Eugene Blikh added label milestone:stage-2 · 2026-07-20T03:08:46Z
  • Eugene Blikh removed label milestone:stage-2 · 2026-07-20T03:10:23Z
Stored rows — what this pane was built from, as read
issues 1 row
id ah-xuc
content_hash 19aa9e472e32b714a672302d4a5b9431d5154fa20c3d0f98ef188f68d40ea1b7
title Stage 2: webhooks, Task Spec, full buckets, Telegram, srht push, watchdog
description Per SPEC SS14.2: Vikunja webhook receiver (HMAC) as reconciler poke; Task Spec YAML frontmatter (role/model/skills/limits) + label type defaults + validation -> Triage bounce; buckets Triage/Blocked/Question; Telegram notifier (honor HTTPS_PROXY; TG blocked from lab network); push agent/task-N branch to git.srht.bigb.es for review + link in In Review comment; watchdog on stale events.jsonl; pi --skill materialization from /srv/skills.
design Stage 2 design decisions (coordinator, 2026-07-13): 1. Webhook: POST /webhooks/vikunja on the SAME loopback mux; exposure to Vikunja is infra (ah-k23, tunnel/reverse-proxy). Hex HMAC-SHA256 of the raw body in X-Vikunja-Signature, constant-time compare; secret vikunja.webhook_secret; unset secret = route not registered. Any verified event = Poke(); payload untrusted beyond event_name logging. Poll loop remains the source of truth (Vikunja delivers webhooks once, no retries). 2. Buckets: triage/blocked/question are PARKED buckets — mapped and title-validated, never claim sources, never kill triggers, detached runtime supervision only. Triage is the bounce target for spec validation failures (not Failed — the human fixes and re-drags). Blocked/Question earn real semantics in Stage 4. domain.CanonicalBuckets() = States() + the three; buckets are a superset of states; config requires all nine keys. 3. Task Spec: YAML frontmatter (--- delimited) at the head of the description. Fields: role, model, skills, timeout. Merge precedence: config defaults < type:<name> label preset (config task_types) < frontmatter. Multiple type:* labels or an unknown type = validation error. Unknown frontmatter fields = warnings appended to the claim comment, never a bounce. Prompt renders over the frontmatter-stripped body. 4. Skills: names are safe slugs; resolved to <skills_dir>/<name>; SKILL.md must exist with a non-empty frontmatter description (pi refuses skills without one). pi argv keeps --no-skills --no-extensions and adds explicit --skill <abs> per skill — deterministic set. 5. Per-run timeout: effective value (spec/type override or config default) persisted on the run row (migration v2, runs.timeout_seconds, 0 = config default) so restarts enforce the right deadline. 6. Watchdog: stalled = Running and now - max(events.jsonl mtime, StartedAt) > stall_timeout (default 10m, 0 disables, else >= 1m). Kill + finalize OutcomeStalled/exit -1. Neither-state observation stays deadline-only. 7. Telegram: optional config block {token, chat_id, api_base}; default-transport proxy semantics honor HTTPS_PROXY; notify is best-effort after move+comment on finalize (success/failed/timeout/stalled) and spec bounce; token redacted from errors/logs. Unconfigured = existing slog no-op. 8. Publish: Runner.Publish(ctx, taskID) -> PublishInfo{RemoteURL, Branch, WebURL}; plain git push of agent/task-N to per-repo review_remote (never force); zero info + nil err = not configured; failure degrades to a push-failed line in the In Review comment; re-push on refinalize is idempotent. review_url template with {branch} builds the human link. 9. vikunja.web_url (default: url minus /api/v1) builds human task links for comments and notifications. 10. Scope cuts: NO worker pool / max_parallel in Stage 2 (research mentions it; epic and SPEC roadmap do not). No repo selection via spec (multi-repo is Stage 5). No new external deps. Infra prerequisites tracked in ah-k23: three new board columns (Triage/Blocked/Question), Vikunja webhook target+secret, srht repos + SSH key for the daemon user, TG bot token + proxy path.
acceptance_criteria
notes
status closed
priority 3
issue_type epic
assignee NULL
estimated_minutes NULL
created_at 2026-07-12T23:36:28Z
created_by Eugene Blikh
owner bigbes@gmail.com
updated_at 2026-07-13T08:38:18Z
closed_at 2026-07-13T08:38:18Z
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 Stage 2 delivered: 21 commits b3ee57d..HEAD (webhook HMAC poke, Task Spec frontmatter + type-label presets + Triage bounce, parked buckets Triage/Blocked/Question, per-run timeout with store v2, stall watchdog, Telegram notifier via HTTPS_PROXY, review-branch publish to srht remotes with bounded push, e2e flows, SPEC synced to Stages 1-2). Every wave gated by hostile review + empirical validation; final epic-wide gate 11/11. Runtime prerequisites (board columns, webhook target, srht repos, TG bot) remain in ah-k23.
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 NULL
is_blocked 0
dependencies 12 rows
id 12e9e9c8-2748-58a3-ba44-9ca7ef884ac7
issue_id ah-xuc.10
type parent-child
created_at 2026-07-13T08:16:17Z
created_by Eugene Blikh
metadata �{}
thread_id
depends_on_issue_id ah-xuc
depends_on_wisp_id NULL
depends_on_external NULL
id 23b27664-16c6-5611-b0d7-eb405e062295
issue_id ah-xuc.5
type parent-child
created_at 2026-07-13T08:15:26Z
created_by Eugene Blikh
metadata �{}
thread_id
depends_on_issue_id ah-xuc
depends_on_wisp_id NULL
depends_on_external NULL
id 252a0719-62cd-54d5-8db4-9309eb609a4e
issue_id ah-xuc.2
type parent-child
created_at 2026-07-13T08:15:07Z
created_by Eugene Blikh
metadata �{}
thread_id
depends_on_issue_id ah-xuc
depends_on_wisp_id NULL
depends_on_external NULL
id 2f0edb7d-9d7d-5865-b263-93db7cce7609
issue_id ah-xuc.7
type parent-child
created_at 2026-07-13T08:15:43Z
created_by Eugene Blikh
metadata �{}
thread_id
depends_on_issue_id ah-xuc
depends_on_wisp_id NULL
depends_on_external NULL
id 3fba1fe9-f3a2-5360-8b0a-f344c7e79be6
issue_id ah-xuc.8
type parent-child
created_at 2026-07-13T08:15:59Z
created_by Eugene Blikh
metadata �{}
thread_id
depends_on_issue_id ah-xuc
depends_on_wisp_id NULL
depends_on_external NULL
id 5669575f-fde5-5b23-900f-c355ce60fe1b
issue_id ah-xuc.4
type parent-child
created_at 2026-07-13T08:15:21Z
created_by Eugene Blikh
metadata �{}
thread_id
depends_on_issue_id ah-xuc
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 a15afbfe-2443-533e-be9d-c7e27fbc77e2
issue_id ah-xuc.12
type parent-child
created_at 2026-07-13T08:16:35Z
created_by Eugene Blikh
metadata �{}
thread_id
depends_on_issue_id ah-xuc
depends_on_wisp_id NULL
depends_on_external NULL
id a40dca03-2215-5737-bc0b-af57df910a5f
issue_id ah-xuc.6
type parent-child
created_at 2026-07-13T08:15:38Z
created_by Eugene Blikh
metadata �{}
thread_id
depends_on_issue_id ah-xuc
depends_on_wisp_id NULL
depends_on_external NULL
id c444dec4-d3cd-580b-a8b6-a8d8ebc2d660
issue_id ah-xuc.11
type parent-child
created_at 2026-07-13T08:16:24Z
created_by Eugene Blikh
metadata �{}
thread_id
depends_on_issue_id ah-xuc
depends_on_wisp_id NULL
depends_on_external NULL
id d8b95e75-79d8-555c-941d-5259c652680e
issue_id ah-xuc.9
type parent-child
created_at 2026-07-13T08:16:06Z
created_by Eugene Blikh
metadata �{}
thread_id
depends_on_issue_id ah-xuc
depends_on_wisp_id NULL
depends_on_external NULL
id d8fdc3c7-ff08-5a0f-8663-42c0e5ff9cc0
issue_id ah-xuc.3
type parent-child
created_at 2026-07-13T08:15:10Z
created_by Eugene Blikh
metadata �{}
thread_id
depends_on_issue_id ah-xuc
depends_on_wisp_id NULL
depends_on_external NULL
events 5 rows
id 019f58b0-7816-7c6b-a36d-bbbd7f5b5eb4
issue_id ah-xuc
event_type created
actor Eugene Blikh
old_value
new_value
comment NULL
created_at 2026-07-13T02:36:27Z
id 019f59e8-8043-7459-b96e-7d73392d0d2f
issue_id ah-xuc
event_type updated
actor Eugene Blikh
old_value {"id":"ah-xuc","title":"Stage 2: webhooks, Task Spec, full buckets, Telegram, srht push, watchdog","description":"Per SPEC SS14.2: Vikunja webhook receiver (HMAC) as reconciler poke; Task Spec YAML frontmatter (role/model/skills/limits) + label type defaults + validation -\u003e Triage bounce; buckets Triage/Blocked/Question; Telegram notifier (honor HTTPS_PROXY; TG blocked from lab network); push agent/task-N branch to git.srht.bigb.es for review + link in In Review comment; watchdog on stale events.jsonl; pi --skill materialization from /srv/skills.","status":"open","priority":3,"issue_type":"epic","owner":"bigbes@gmail.com","created_at":"2026-07-12T23:36:28Z","created_by":"Eugene Blikh","updated_at":"2026-07-12T23:36:28Z"}
new_value {"design":"Stage 2 design decisions (coordinator, 2026-07-13):\n1. Webhook: POST /webhooks/vikunja on the SAME loopback mux; exposure to Vikunja is infra (ah-k23, tunnel/reverse-proxy). Hex HMAC-SHA256 of the raw body in X-Vikunja-Signature, constant-time compare; secret vikunja.webhook_secret; unset secret = route not registered. Any verified event = Poke(); payload untrusted beyond event_name logging. Poll loop remains the source of truth (Vikunja delivers webhooks once, no retries).\n2. Buckets: triage/blocked/question are PARKED buckets — mapped and title-validated, never claim sources, never kill triggers, detached runtime supervision only. Triage is the bounce target for spec validation failures (not Failed — the human fixes and re-drags). Blocked/Question earn real semantics in Stage 4. domain.CanonicalBuckets() = States() + the three; buckets are a superset of states; config requires all nine keys.\n3. Task Spec: YAML frontmatter (--- delimited) at the head of the description. Fields: role, model, skills, timeout. Merge precedence: config defaults \u003c type:\u003cname\u003e label preset (config task_types) \u003c frontmatter. Multiple type:* labels or an unknown type = validation error. Unknown frontmatter fields = warnings appended to the claim comment, never a bounce. Prompt renders over the frontmatter-stripped body.\n4. Skills: names are safe slugs; resolved to \u003cskills_dir\u003e/\u003cname\u003e; SKILL.md must exist with a non-empty frontmatter description (pi refuses skills without one). pi argv keeps --no-skills --no-extensions and adds explicit --skill \u003cabs\u003e per skill — deterministic set.\n5. Per-run timeout: effective value (spec/type override or config default) persisted on the run row (migration v2, runs.timeout_seconds, 0 = config default) so restarts enforce the right deadline.\n6. Watchdog: stalled = Running and now - max(events.jsonl mtime, StartedAt) \u003e stall_timeout (default 10m, 0 disables, else \u003e= 1m). Kill + finalize OutcomeStalled/exit -1. Neither-state observation stays deadline-only.\n7. Telegram: optional config block {token, chat_id, api_base}; default-transport proxy semantics honor HTTPS_PROXY; notify is best-effort after move+comment on finalize (success/failed/timeout/stalled) and spec bounce; token redacted from errors/logs. Unconfigured = existing slog no-op.\n8. Publish: Runner.Publish(ctx, taskID) -\u003e PublishInfo{RemoteURL, Branch, WebURL}; plain git push of agent/task-N to per-repo review_remote (never force); zero info + nil err = not configured; failure degrades to a push-failed line in the In Review comment; re-push on refinalize is idempotent. review_url template with {branch} builds the human link.\n9. vikunja.web_url (default: url minus /api/v1) builds human task links for comments and notifications.\n10. Scope cuts: NO worker pool / max_parallel in Stage 2 (research mentions it; epic and SPEC roadmap do not). No repo selection via spec (multi-repo is Stage 5). No new external deps.\nInfra prerequisites tracked in ah-k23: three new board columns (Triage/Blocked/Question), Vikunja webhook target+secret, srht repos + SSH key for the daemon user, TG bot token + proxy path."}
comment NULL
created_at 2026-07-13T08:17:17Z
id 019f5aa0-88ab-7036-9543-c212c67ea38d
issue_id ah-xuc
event_type closed
actor Eugene Blikh
old_value
new_value Stage 2 delivered: 21 commits b3ee57d..HEAD (webhook HMAC poke, Task Spec frontmatter + type-label presets + Triage bounce, parked buckets Triage/Blocked/Question, per-run timeout with store v2, stall watchdog, Telegram notifier via HTTPS_PROXY, review-branch publish to srht remotes with bounded push, e2e flows, SPEC synced to Stages 1-2). Every wave gated by hostile review + empirical validation; final epic-wide gate 11/11. Runtime prerequisites (board columns, webhook target, srht repos, TG bot) remain in ah-k23.
comment NULL
created_at 2026-07-13T11:38:18Z
id 019f7cda-91af-7cc1-bdac-89704908c309
issue_id ah-xuc
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:46Z
id 019f7cdc-0b0c-769b-8590-79393129165d
issue_id ah-xuc
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