~bigbes/agents-dev · issues

eefkdm0u6ipbhk8k092drg2n0gsdpkl9 · 69 rows

idcontent_hashtitledescriptiondesignacceptance_criterianotesstatuspriorityissue_typeassigneeestimated_minutescreated_atcreated_byownerupdated_atclosed_atclosed_by_sessionexternal_refspec_idcompaction_levelcompacted_atcompacted_at_commitoriginal_sizesenderephemeralwisp_typepinnedis_templatemol_typework_typesource_systemmetadatasource_repoclose_reasonevent_kindactortargetpayloadawait_typeawait_idtimeout_nswaitershook_beadrole_beadagent_statelast_activityrole_typerigdue_atdefer_untilno_historystarted_atis_blocked
ah-xuc19aa9e472e32b714a672302d4a5b9431d5154fa20c3d0f98ef188f68d40ea1b7Stage 2: webhooks, Task Spec, full buckets, Telegram, srht push, watchdogPer 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.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.closed3epicNULLNULL2026-07-12T23:36:28ZEugene Blikhbigbes@gmail.com2026-07-13T08:38:18Z2026-07-13T08:38:18ZNULL0NULLNULLNULL000�{}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.0NULLNULLNULL0NULL0
ah-xuc.1a152c1dd582b5477ff993f9f0c070eea86bf5d7994ae57afd24f3cbf8ac4394fStage 2 foundation: domain buckets/outcome, ports contracts, config surfaceEvery 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 stagedCoordinator 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.closed2taskEugene BlikhNULL2026-07-13T05:14:51ZEugene Blikhbigbes@gmail.com2026-07-13T05:44:24Z2026-07-13T05:44:24ZNULL0NULLNULLNULL000�{}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)0NULLNULLNULL02026-07-13T05:19:13Z0
ah-xuc.1093e494bccda4f59baacc19a0e3b326af7c363fd21532a445b37b51577c6c63e9cmd/agenthubd: wire webhook secret and Telegram notifierWiring only. agenthubd run(): construct internal/telegram when the config block is present, otherwise keep the existing slog no-op notifier; pass the notifier into reconcile.Deps; pass the webhook secret and a hook invoking Reconciler.Poke into httpapi.Deps. internal/deps updated if that is the wiring point. Startup board preflight: with nine required buckets the existing adapter title lookup already fails fatal with the found-titles list when the Triage/Blocked/Question columns are missing on the board — verify that failure stays readable at startup. ahub needs no changes (validate-config picks up the new keys through the config package).go build ./cmd/... green; go test ./cmd/... green including a run() smoke asserting the webhook route responds when the secret is set and is absent when unset, and that the telegram notifier is selected when configured; go vet cleanCoordinator refinement: also wire the runner as ports.Publisher into reconcile.Deps.closed2taskEugene BlikhNULL2026-07-13T05:16:18ZEugene Blikhbigbes@gmail.com2026-07-13T07:53:56Z2026-07-13T07:53:56ZNULL0NULLNULLNULL000�{}95560cc; reviewer merge-ready (single wiring path, nil-safe, pointer-identity tested); validator all-pass incl. first live daemon runs — readable fatal preflight, telegram deferred past preflight with no I/O0NULLNULLNULL02026-07-13T07:35:21Z0
ah-xuc.11b6a041aecb730cbf5ad794b8bba2833ccb247eeb242441fa1b256c4a6130e930e2e: Stage 2 flows — webhook poke, Triage bounce, skills, publish, watchdog, TelegramExtend the e2e harness (build tag e2e, fake vikunja plus stub pi/zellij, stub-honesty rules from commit b3ee57d). Fake vikunja gains labels on tasks and the nine-bucket board. - webhook poke: long poll_interval, POST a correctly signed payload to /webhooks/vikunja, assert the claim happens promptly (poke, not poll); a bad signature does nothing. - Triage bounce: a Ready task with broken frontmatter lands in Triage with the diagnostic comment and no record or run row. - skills: a task whose spec names skills (fixture SKILL.md dirs under a temp skills_dir) — the stub pi records argv; assert the --skill absolute paths and the retained --no-skills. - publish: repo review_remote points at a local bare repository; after a successful run the In Review comment carries the review link and the bare repo has the agent/task-N ref at the expected commit. - watchdog: stub pi hangs without touching events.jsonl; with a short stall_timeout the run is killed and the card lands in Failed with a stalled comment. - telegram: telegram.api_base points at a fake httptest Bot API; assert sendMessage calls for the in_review and stalled paths, and that the token appears only in the request path, never in daemon logs.go test -tags e2e ./e2e/... green and hermetic (loopback only); each flow asserted through externally observable surfaces — board moves, comments, bare repo refs, fake TG requests — not daemon internalsclosed2taskEugene BlikhNULL2026-07-13T05:16:24ZEugene Blikhbigbes@gmail.com2026-07-13T08:38:17Z2026-07-13T08:38:17ZNULL0NULLNULLNULL000�{}8e29554; reviewer merge-ready with zero findings — stub honesty, hermeticity, timing discipline, full-argv equality all verified; 3-run flake probe: all six Stage 2 flows green in all runs (the one flake found is pre-existing Stage 1, filed as ah-wka)0NULLNULLNULL02026-07-13T07:53:57Z0
ah-xuc.1214d3638d45c9064a76941832983973f494233fccabe6a738101abdf7f06e6d89docs: sync SPEC with Stage 2 behaviorSPEC.md gains normative Stage 2 sections mirroring what landed, in the established style (invariants and failure modes, not narrative): domain deltas (stalled outcome, canonical buckets as a superset of states, Run.Timeout), ports deltas (Labels, Skills, Publish), store v2 migration, vikunja labels, runner skills plus publish (never force-push), reconciler claim spec resolution + Triage bounce + parked buckets + per-run timeout + watchdog + notification ordering, httpapi webhook endpoint (HMAC, disabled when unset), config reference with the full new example, security notes (webhook secret, TG token redaction, srht push scope), roadmap section 14 marks Stage 2 delivered. Cross-check config.example.yaml for drift. AGENTS.md and CLAUDE.md only if conventions changed (mirror both if so — independent files).Each new SPEC section spot-checked against the shipped code; no contradiction with Stage 1 sections; the research-v3 supersede note stays accurateclosed2taskEugene BlikhNULL2026-07-13T05:16:35ZEugene Blikhbigbes@gmail.com2026-07-13T08:38:17Z2026-07-13T08:38:17ZNULL0NULLNULLNULL000�{}e13b65c + b48849f (two wording nits); accuracy reviewer merge-ready — every behavioral claim verified against code; SPEC section-12 example validates through ahub validate-config; pre-existing RunStatus.MetaAttempt drift filed as ah-6u00NULLNULLNULL02026-07-13T07:53:57Z0
ah-xuc.2fa1ad68d45c1cb503c73e2f25b2c07769c319f1d2adc6eefbb30f03d70297a4ainternal/spec: Task Spec frontmatter parse, type-label defaults, validationNew pure package internal/spec (imports domain, config, yaml only — no board/store/runner I/O). Custom fields do not exist in Vikunja, so the machine-readable part of a task lives as YAML frontmatter at the head of the description; labels give per-type defaults. Parse: frontmatter delimited by --- lines at the very start of the description (tolerate CRLF; no frontmatter = empty spec). Known fields: role, model, skills (list of names), timeout (duration string). Unknown fields are collected as warnings, never errors. Returns spec + body (description with frontmatter stripped) + warnings. Resolve(cfg, labels, description): merge precedence config defaults < type:<name> label preset (cfg.TaskTypes) < frontmatter. More than one type:* label is a validation error; a type:* label naming an unknown task type is a validation error. Validation (bounce-class) errors: broken YAML, unknown role, skill name not a safe slug, skills requested while skills_dir unset, missing <skills_dir>/<name>/SKILL.md, SKILL.md frontmatter with an empty description, timeout unparseable or nonpositive. Output: Resolved{RoleName, Model, SkillPaths (absolute), Timeout, Body, Warnings}. Filesystem checks go through a small injected func so most tests need no real skills tree; add one real-FS test with t.TempDir() fixtures. Validation errors must be a typed, human-readable list — the reconciler posts them verbatim in the Triage bounce comment — distinct from internal errors.go test ./internal/spec/... green, go vet clean; table tests cover merge precedence for every field and each bounce class; frontmatter stripping keeps the body exact after the closing delimiterclosed2featureEugene BlikhNULL2026-07-13T05:15:08ZEugene Blikhbigbes@gmail.com2026-07-13T06:22:47Z2026-07-13T06:22:47ZNULL0NULLNULLNULL000�{}d714741 + eb5a4be (review-gap pinning); hostile adversarial review merge-ready (yaml alias bombs bounded, path traversal blocked, error taxonomy sound)0NULLNULLNULL02026-07-13T05:44:24Z0
ah-xuc.3130d6553f11713918d8f32dca70661607918c8ae7bed880ea98a1b417dca5b30vikunja: fetch task labels into BoardTask.LabelsStage 2 type defaults key off Vikunja labels and the adapter currently drops them. wireTask gains the labels array (verify the exact field shape against the live docs.json or the go-vikunja v2.3.0 source, as was done for result-count semantics in commit 7802095). Snapshot copies label titles into ports.BoardTask.Labels ([]string, empty-safe, order as returned). Extend the httptest fixtures with tasks carrying zero, one, and several labels, including one with a type: prefix. No behavior change for existing methods.go test ./internal/vikunja/... green, go vet clean; fixtures cover labeled and label-less tasksclosed2taskEugene BlikhNULL2026-07-13T05:15:10ZEugene Blikhbigbes@gmail.com2026-07-13T06:22:48Z2026-07-13T06:22:48ZNULL0NULLNULLNULL000�{}1e9fc7e; wire shape pinned against upstream go-vikunja v2.3.0; review clean0NULLNULLNULL02026-07-13T05:44:24Z0
ah-xuc.433d26ffac04170d2d8e34c39c29e316a661775ceecd8aa8f20c5d11929a7589dstore: migration v2 — per-run timeout columnThe effective timeout can differ per run once Task Spec overrides land, and a daemon restart must keep enforcing the right deadline, so it is persisted on the run row. Schema user_version 2: runs gains timeout_seconds INTEGER NOT NULL DEFAULT 0 (0 = config default at enforcement time). Fresh databases create straight at v2; existing v1 files get ALTER TABLE on open. Follow the existing hand-rolled migrator (PRAGMA user_version gate, BEGIN IMMEDIATE serialization, first-boot busy retry — keep every one of those properties). CreateRun/UpdateRun/LatestRun round-trip domain.Run.Timeout, stored as integer seconds.go test ./internal/store/... green, go vet clean; tests: fresh create lands at user_version 2; a v1 database upgrades in place preserving rows; timeout round-trips; existing first-boot race tests keep passingclosed2taskEugene BlikhNULL2026-07-13T05:15:22ZEugene Blikhbigbes@gmail.com2026-07-13T06:22:49Z2026-07-13T06:22:49ZNULL0NULLNULLNULL000�{}c04f7d7; step-list migrator preserves all race properties (verified under -race); review clean0NULLNULLNULL02026-07-13T05:44:25Z0
ah-xuc.5b5fbb872b97c09d1baaee1d165892ef0ed8473656472b639900c43d5dbb8e0afrunner: explicit --skill arguments and Publish to the review remoteTwo runner extensions, both behind existing seams. All argv construction stays in commands.go per SPEC section 9. Skills: piArgv gains the resolved skill dirs — one --skill <absolute-path> per entry, appended while keeping --no-skills and --no-extensions (pi 0.70.2 loads explicit --skill paths even under --no-skills, giving a deterministic per-run set). Start threads StartSpec.Skills through. Publish(ctx, taskID): resolve the task worktree, branch, and repo the same way Summary does today. When the repo has no review_remote, return a zero PublishInfo and nil error (publish not configured). Otherwise git -C <worktree> push <review_remote> <branch> with the branch pushed to the same name — plain push, never force (SPEC: agent branches are never force-pushed). On success fill PublishInfo{RemoteURL, Branch, WebURL} where WebURL is the repo review_url with {branch} substituted (empty when review_url unset). Push failures return a wrapped error carrying a stderr prefix.go test ./internal/runner/... green, go vet clean; argv table tests for skills present/absent and push; PATH-shim git stub verifies push argv, success, and failure propagation; a Start test asserts --skill flags reach the pi argvCoordinator refinement: implement ports.Publisher (separate port defined in ah-xuc.1) as a method on the existing runner type — the ports.Runner interface itself does not change.closed2featureEugene BlikhNULL2026-07-13T05:15:26ZEugene Blikhbigbes@gmail.com2026-07-13T06:22:49Z2026-07-13T06:22:49ZNULL0NULLNULLNULL000�{}28f75aa + eae0845; refspec refs/heads/X:refs/heads/X pinned, no-force verified, findWorktree semantics shared with Summary; review clean0NULLNULLNULL02026-07-13T05:44:25Z0
ah-xuc.6e8c8ca06f34dfebba7004095b3bec4be6a1dd7a6c04bce0af09d4edc831fed76telegram: ports.Notifier implementation (Bot API through HTTPS_PROXY)New package internal/telegram implementing ports.Notifier. POST {api_base}/bot{token}/sendMessage with JSON {chat_id, text, disable_web_page_preview: true}. http.Client with a 10s timeout whose transport keeps ProxyFromEnvironment semantics so HTTPS_PROXY is honored (Telegram is blocked from the lab network; egress goes through the proxy) — do not build a bare Transport without the Proxy field. Non-2xx responses and ok:false bodies become errors carrying a short body prefix; the bot token must never appear in logs or error strings — redact the URL when wrapping errors. No retries: the reconciler treats Notify as best-effort. api_base comes from config telegram.api_base so tests and e2e can point it at httptest.go test ./internal/telegram/... green, go vet clean; httptest covers success, HTTP error, ok:false, and token redaction in returned errors; a test asserts proxy resolution from the environment is activeclosed2featureEugene BlikhNULL2026-07-13T05:15:38ZEugene Blikhbigbes@gmail.com2026-07-13T06:22:50Z2026-07-13T06:22:50ZNULL0NULLNULLNULL000�{}e15fe4c; token-leak vectors traced to stdlib source and closed; proxy semantics verified empirically; review clean0NULLNULLNULL02026-07-13T05:44:25Z0
ah-xuc.762a6806491ee4096a8206ec5b958064c69d772d7f8376188ca61bbfc8a354510httpapi: Vikunja webhook receiver with HMAC verificationPOST /webhooks/vikunja as a reconciler poke. Design principle 1: a webhook only triggers an immediate iteration; polling stays the source of truth because Vikunja delivers webhooks once, without retries. Deps gain WebhookSecret string and a Webhook hook (non-blocking; cmd wires it to Reconciler.Poke). Empty secret = feature disabled: the route is not registered at all. Verification: X-Vikunja-Signature carries hex HMAC-SHA256 over the raw request body; compute over the exact bytes read and compare with hmac.Equal; missing or wrong signature = 401 with a terse body that echoes nothing back; cap the body at 256 KiB. After verification decode {event_name} best-effort for the log line only — the payload is otherwise untrusted and unused. Respond 200 fast, call the hook once per verified delivery. Exposing the loopback listener to Vikunja is infra (ah-k23), not this bead.go test ./internal/httpapi/... green, go vet clean; tests: a valid computed signature pokes the hook and returns 200; tampered body, wrong secret, and missing header return 401 without invoking the hook; oversized body rejected; unset secret leaves the route absent and existing routes unaffectedclosed2featureEugene BlikhNULL2026-07-13T05:15:43ZEugene Blikhbigbes@gmail.com2026-07-13T06:22:50Z2026-07-13T06:22:50ZNULL0NULLNULLNULL000�{}61400ae; HMAC discipline verified (full-read-before-verify, uniform 401, constant-time compare); review clean0NULLNULLNULL02026-07-13T05:44:26Z0
ah-xuc.8d48513a80bea7b4ebcfc74514ea6d2a7079500b44f1b1eebca7b445db6e316b7reconcile: spec-driven claim, Triage bounce, parked buckets, per-run timeoutClaim-path integration of Stage 2. Same-package constraint: this bead owns the internal/reconcile edits for the claim path; the finalize-path bead must not start until this one is committed. iterate(): canonical buckets triage/blocked/question become parked buckets — superviseRuntime only (detached supervision persists runtime truth; no claim, no kill, no card moves, no comments). They are never claim sources and never terminal targets. Blocked and Question get real semantics in Stage 4; Stage 2 only reserves and parks them. claim(): resolve the Task Spec via internal/spec from BoardTask.Labels plus Description. A validation failure bounces: MoveToBucket(triage) first, then one diagnostic comment listing the problems verbatim plus a hint to fix the spec and drag back to Ready, then event spec_rejected — move-then-comment discipline so a persistent move failure cannot spam comments; appendEvent dedup applies. No record is persisted and the card never goes to Failed for spec problems. Warnings (unknown fields) never block: append them to the claim comment. Success path: the spec role name resolves through cfg.Roles; model override applies; the prompt renders over the frontmatter-stripped Body; resolved SkillPaths go into StartSpec.Skills; the effective timeout (spec override or config default) goes into StartSpec.Timeout and is persisted as Run.Timeout. check(): deadline enforcement uses run.Timeout when positive, else cfg.Timeout — in both the running arm and the degraded neither-state arm. Extend fakes_test.go (fake runner captures Skills and Timeout; board tasks carry Labels) and cover: each bounce class end to end, merge precedence reaching StartSpec, parked buckets neither claim nor kill while detached supervision still finalizes a finished runtime, per-run timeout enforced at the right boundary with the fake clock — both shorter and longer than the config default.go test ./internal/reconcile/... green, go vet clean; bounce tests assert move-before-comment ordering and zero Failed transitions; parked-bucket tests assert no board writes; timeout tests cover run.Timeout smaller and larger than the config default Additional: pre-existing gofmt drift in internal/reconcile/reconcile_test.go (comment alignment around lines 983-984 and 1345, present since before Stage 2) — run gofmt -w on the files you touch and fold the fix into this bead's commit.closed2featureEugene BlikhNULL2026-07-13T05:16:00ZEugene Blikhbigbes@gmail.com2026-07-13T06:57:17Z2026-07-13T06:57:17ZNULL0NULLNULLNULL000�{}9823250 + 06_pin commit; review merge-ready (all SPEC section-10 invariants traced clean); validator 10/10 incl. e2e byte-identical for spec-less tasks; adopt-over-bounce coverage gap closed0NULLNULLNULL02026-07-13T06:23:38Z0
ah-xuc.95c6568a5b55170ea70ba05fb8c0af96dcfaf33b977424934bdb124f8c46e5c10reconcile: publish review branch, watchdog on stale events, Telegram notificationsFinalize-path integration of Stage 2. Starts only after the claim-path bead is committed (same package). Publish: in finalize, on the success path with moveCard set, call runner.Publish before posting the In Review comment. Zero PublishInfo = not configured, plain comment. Success adds a review link line (WebURL, falling back to RemoteURL plus branch) and appends event published. Failure degrades: the comment still posts with a push-failed line carrying the error, event publish_failed (deduped). A refinalize repeats the push — pushing an up-to-date branch is idempotent and fine. Watchdog: in the check() running arm, when cfg.StallTimeout > 0 and now minus max(st.LastEvent, run.StartedAt) exceeds StallTimeout, the run is stalled: kill and finalize with OutcomeStalled, exit -1 (share the timeoutKill shape). The neither-state arm stays deadline-only — no events are observable there. failureComment renders the stalled outcome distinctly (agent went silent, not merely slow). Notifications: Notify best-effort — log on error, never gate the flow, guard the nil notifier — after a successful move plus comment: finalize with moveCard (success and failure including timeout and stalled) and the spec bounce. Text: outcome emoji, task id and title, outcome word, cost when known, and the human task link built from vikunja web_url. Tests with fakes: the In Review comment contains the review link; publish failure still posts the comment; the stall kill fires just past the boundary and not before; a run with events flowing but past run.Timeout still dies by deadline; notify recorded after move and comment in that order; nil notifier safe; a notify failure does not fail finalize.go test ./internal/reconcile/... green, go vet clean; ordering asserted move then comment then notify; stalled and timeout outcomes distinguishable in comments, events, and notificationsCoordinator refinement: publishing arrives via a new optional reconcile Deps field of type ports.Publisher (nil-guarded like Notifier); finalize publishes only when the field is non-nil. cmd wires the runner into it in ah-xuc.10.closed2featureEugene BlikhNULL2026-07-13T05:16:07ZEugene Blikhbigbes@gmail.com2026-07-13T07:35:20Z2026-07-13T07:35:20ZNULL0NULLNULLNULL000�{}d5d1efc + 64a7216 (review fix: bounded publish ctx via publish_timeout knob, zero-delta recorder covers publish/notify); reviewer merge-ready after fix, validator 10/10 with all 24 subtests by name0NULLNULLNULL02026-07-13T06:57:43Z0
ah-ydx8735805091c14831debfbdb26c8f324f6832e8b80ebcc313e05201a7bd3c85f8Stage 3: mem0 memory lifecycle + Context PackPer SPEC SS14.3: mem0 REST client (X-API-Key, scoping user_id=proj:<slug>/global, run_id=task:<id> — agent_id filter is buggy upstream); load cascade on claim -> .task/CONTEXT.md section; save on Done; post-run summarizer role; Context Pack builder (task+thread+parent-chain+memory+git, ~40k char budget, deterministic order, truncate-from-tail).open3epicNULLNULL2026-07-12T23:36:28ZEugene Blikhbigbes@gmail.com2026-07-12T23:36:28ZNULLNULL0NULLNULLNULL000�{}0NULLNULLNULL0NULL0
ah-ydx.1942024e29b162a28d01e0bddbd3bf862f1ff8bf498c45bd03199c5a0dc916489internal/mem0: REST client for live mem0.bigb.esTyped Go client for the self-hosted Mem0 server (LIVE at mem0.bigb.es, phoebe-lab/mem0 stack): X-API-Key auth, add/search/get-all/delete memories. Encode scoping conventions as helpers: user_id='proj:<slug>' | 'global', run_id='task:<id>'; do NOT rely on agent_id filtering (buggy upstream per SPEC §14.3). Stdlib-only, httptest unit tests; live verification (incl. API-key provisioning via dashboard/register) is a follow-up ops step.closed2featureEugene BlikhNULL2026-07-18T13:23:56ZEugene Blikhbigbes@gmail.com2026-07-18T13:41:11Z2026-07-18T13:41:11ZNULL0NULLNULLNULL000�{}internal/mem0 client merged to master (55b9b43); routes confirmed against mem0 v2.0.11 source; live verification against mem0.bigb.es tracked in ah-ydx.30NULLNULLNULL02026-07-18T13:25:07Z0
ah-ydx.2f548f321fdf44dbfaaa3c420a175ff8b3bea76ab1cf76d097509d87eeb461072internal/ctxpack: Context Pack builderDeterministic prompt-context assembler per SPEC §14.3: ordered sections (task, comment thread, parent chain, memory, git log/diffstat) under a ~40k char budget, per-section truncate-from-tail with stable ordering so identical inputs render identical packs. Pure package + table tests first; wiring into runner PROMPT.md rendering is a separate integration step after wave 1 merges.closed2featureEugene BlikhNULL2026-07-18T13:23:56ZEugene Blikhbigbes@gmail.com2026-07-18T13:41:11Z2026-07-18T13:41:11ZNULL0NULLNULLNULL000�{}internal/ctxpack merged to master (342410e); format contract pinned by golden tests; runner integration tracked in ah-ydx.30NULLNULLNULL02026-07-18T13:25:08Z0
ah-ydx.316681b27f4960105b6ca27beabc1e8219b7b6edab3c59c243830102a1c17bd7aMemory lifecycle: load-on-claim CONTEXT section, save-on-DoneWire mem0 into the task loop per SPEC §14.3: on claim, search mem0 (proj scope + global) and render a memory section into the prompt context via ctxpack; on Done/Cancelled terminal scan (shares the ah-07g hook), save run summary/verdict facts back to mem0 (run_id='task:<id>'). Depends on the mem0 client, ctxpack, and the ah-07g terminal-state scan.MEM0 SERVER HEALTHY (2026-07-18, after user-authorized override delete + restart): /configure now reflects env-of-truth (deepseek/deepseek-v4-flash + nvidia/nemotron-embed-1b-v2). FULL live smoke green: ADD infer=false 200/event=ADD; SEARCH 200 with score (embeddings ok); ADD infer=true 200 (LLM extraction ok); LIST/PURGE/EMPTY clean; bogus key 401. Server-side contract fully verified — lifecycle implementation unblocked once ah-07g lands the terminal-state hook. OPERATIONAL RULE: mem0 config is ENV-ONLY; never POST /configure (GET redacts secrets, round-trip corrupts stored creds — happened + fixed today, backup at phoebe:/root/mem0-settings-backup.sql); if a stored override reappears (dashboard onboarding creates one), delete settings row key=config_overrides + restart.closed2featureEugene BlikhNULL2026-07-18T13:23:57ZEugene Blikhbigbes@gmail.com2026-07-18T16:22:33Z2026-07-18T16:22:33ZNULL0NULLNULLNULL000�{}Merged b761cbe: recall-on-claim (## Relevant memories via ctxpack, proj+global scopes, 15s budget, feature-off byte-identical) + save-on-Done (save→archive→prune ordering, infer=true, once-only via worktree signal, Cancelled excluded). Rollout: install MEM0_API_KEY in /etc/agent-hub/env, live-smoke recall block + one memory_saved event.0NULLNULLNULL02026-07-18T15:59:39Z0
ah-ydx.4082c3365aabe053240cf35195442ee1ca6547ba635899ad10f3319fea286fd7eFull Context Pack: thread comments, parent chain, git log sections in promptah-ydx.2's ctxpack renders only the memory section today. SPEC §14.3's full pack adds: board comment thread, parent-chain summaries (delegation), git log/diffstat of the branch — assembled with the memory section under the ~40k budget in canonical order. Backlog until the current prompt shape shows its limits in live runs.closed3featureEugene BlikhNULL2026-07-18T16:22:34ZEugene Blikhbigbes@gmail.com2026-07-18T18:47:54Z2026-07-18T18:47:54ZNULL0NULLNULLNULL000�{}Full Context Pack live: thread + parent-chain + memory + git sections through one 40k-budget ctxpack build on the claim path; context_pack audit event; per-section graceful degradation.0NULLNULLNULL02026-07-18T18:19:54Z0
ah-ziqf6ed15a8569893a586511b86daf9a0cfc59c0fd794875182892371c1c8323d80yonote: comments.resolve 400s — live API requires isResolved boolean in bodyLive re-smoke of the Q&A loop (ah-eje, task 5) proved comments.resolve is broken: the daemon's POST /api/comments.resolve got HTTP 400 invalid_type 'Invalid input: expected boolean, received undefined (isResolved)'. Yonote 1.47.1 requires an isResolved:true field in the resolve payload; our client sends only {id}. Deterministic — every resolve fails, answer delivery is unaffected (non-fatal WARN path worked as designed). Fix: add IsResolved to the resolve wire payload in internal/yonote/comments.go, adjust tests, re-verify live that a fresh qa question ends isResolved:true.closed2bugEugene BlikhNULL2026-07-19T18:11:32ZEugene Blikhbigbes@gmail.com2026-07-19T18:21:38Z2026-07-19T18:21:38ZNULL0NULLNULLNULL000�{}Fixed in 2720611: resolve payload now {id, isResolved:true}. Live-verified (task 6 / comment 732b89b2): resolve succeeded, no WARN, comment isResolved:true.0NULLNULLNULL02026-07-19T18:11:47Z0