Skip to content

aggregator: an empty github-result report marks a dashboard comment failed — a pending comment is written off unposted, and a posted comment flips back to failed #1686

Closed

Description

@dezren39

Summary

A GitHub-result report that carries neither a URL nor an error is recorded as a failure — and it can retroactively un-post a comment that already succeeded.

CommentsStore.markGithubResult (pm-stack/aggregator/src/comments.ts:202-214, sha256 3b0099d5):

if (result.url) {
  c.githubState = "posted";
  c.githubUrl = result.url;
} else {
  c.githubState = "failed";
}
await this.persist();

The else treats "no URL" as "failed", with no check that an error was actually reported, and no guard on the comment's current state. The HTTP boundary does not close the hole: POST /api/comments/github-result (src/server.ts:350-358) validates only that id is a string, then forwards url/error as undefined when absent — so a body of {"id": "..."} reaches the store as an empty result.

Verified behaviour (probe run on the laptop, main d39e611)

Probe test against the real CommentsStore (bun test, detached worktree, temp-dir store file):

  • CTRL — a {url} report moves a pending comment to posted; an {error} report on a fresh comment moves it to failed. ✅
  • BUG-A — markGithubResult(id, {}) on a pending comment returns it with githubState: "failed" and persists that. Per the consumption contract in the comments.ts header, a kind-github comment "sits at githubState pending until a fleet poster posts it … then reports the result: { id, url } or { id, error }" — a report with neither field reports no outcome, yet the comment is written off as failed and will never be posted.
  • BUG-B — after a successful {url} report (posted, githubUrl set), a later empty report flips the same comment back to failed (the stale githubUrl remains set, so state and URL now contradict each other; githubCommentUrl still renders the URL of a "failed" comment).

Existing tests (test/slice3.test.ts:149-154, :367-368) cover pending→posted and the happy-path endpoint, but no empty, conflicting, or repeat report.

Why it matters

Dashboard comments of kind github are Drew's route for getting a comment onto an issue/PR via a fleet poster. A stray, truncated, or retried result report can silently mark an unposted comment as failed — the message never reaches GitHub and the dashboard says it was tried — or flip a genuinely posted comment to "failed", sending a poster to re-post a duplicate. The store is the system of record for this hand-off; it should refuse a result that reports nothing and never move a terminal state backwards.

Acceptance criteria

  • A result report with neither url nor error is rejected (store returns an error / endpoint answers 400) and the comment's state is unchanged — pending stays pending.
  • A comment already posted cannot be moved to failed by a later report (and a failed comment's path back, if any, is an explicit decision in the fix, pinned by a test); repeat identical reports are idempotent.
  • A report carrying both url and error is rejected or resolved by a documented rule, pinned by a test — not silently decided by branch order.
  • Regression tests cover: empty report on pending, empty report on posted, url+error report; the existing slice3 comment tests keep passing.

Scope notes

  • Two candidate homes for the validation: the store (defends every caller) and/or the server.ts endpoint (400 for the HTTP caller). The store-level refusal is the load-bearing one; triage pins whether the endpoint also validates.
  • Out of scope: the load path's parse-failure handling in the same file, comment author validation, and the triage endpoint.

Activity

  1. developing-today commented on Oct 28, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    priority/normalOrdinary priority (the default)
    app/aggregatorPackage/app: aggregator (pm-stack in this repo)
    effort/sSmall: expected under 2 hours of work
    on Oct 28, 2026
  3. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job (lane A, slug new-issue-creator-code-a)
    • Session / ID: cron new-issue-creator-code-a run 2026-10-28 09:05 CDT
    • Found via: filed this run
    • Task: Triage the github-result validation gap: CommentsStore.markGithubResult (comments.ts:202) treats any report without a url as a failure, so an empty {} report (which server.ts:350 forwards unchecked) writes off a pending kind-github comment as failed before it is ever posted, and flips an already-posted comment back to failed. Verified this run with a bun probe against the real CommentsStore on the laptop (CTRL url->posted / error->failed pass; BUG-A empty-on-pending -> failed; BUG-B empty-on-posted -> failed).
    • Expectation: effort/s — done when an outcome-less report is refused with state unchanged, terminal states cannot move backwards, the url+error case has a pinned rule, and regression tests cover all three.
    • Links: probe + log in the goal workspace (hidden_files/probe-2026-10-28-laneA-ghresult/); sibling filing this run: aggregator: summarizeDns ages renewals by the UTC day, not Chicago — a domain renewing today vanishes from Next renewal and the 45-day spend card every evening from 19:00 CDT #1684 (dns.ts, different module/defect).
  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 31, 2026
  5. 23 remaining items

  6. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    queue/claimedQueue worker lifecycle state
    and removed
    queue/claimedQueue worker lifecycle state
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Oct 31, 2026
  7. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    event: picked_up
    task: 4247 (repo-health-code-pilot, lane F resume)
    state: PR 3062 @dac9902bc. Codex re-review CLEAN on dac9902 (no findings, unresolved=false). No CI workflow covers pm-stack/aggregator (check-runs on head = CodeRabbit only; no workflow references that path), so CI will never materialize — verified targeted tests on laptop instead: bun test test/slice3.test.ts = 21 pass / 1 fail, the fail being the pre-existing manifest-uniqueness test owned by #2580/PR 2604 (diff does not touch it). Proceeding to merge.

  8. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    event: done
    task: 4247 (repo-health-code-pilot, lane F)
    state: PR 3062 MERGED @b383fc44634771283baada3c171cfe269be10e57; issue closed by merge. Codex clean on dac9902; laptop slice3 21 pass / 1 pre-existing fail (#2580). Task completing fixed_merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/aggregatorPackage/app: aggregator (pm-stack in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions