Skip to content

docs(adr): add polling-based work discovery ADR - #2409

Merged
ifireball merged 6 commits into
fullsend-ai:mainfrom
ifireball:docs/adr-0049-polling-work-discovery
Jul 5, 2026
Merged

docs(adr): add polling-based work discovery ADR#2409
ifireball merged 6 commits into
fullsend-ai:mainfrom
ifireball:docs/adr-0049-polling-work-discovery

Conversation

@ifireball

@ifireball ifireball commented Jun 18, 2026

Copy link
Copy Markdown
Member

Fixes #2263

Summary

  • Adds ADR 0063 for per-repo polling via fullsend poll input drivers (Jira first) on the same driver architecture as fullsend dispatch (ADR 0061).
  • Poll input drivers discover work and emit NormalizedEvent values; harness CEL trigger expressions own routing (no poll-side trigger config).
  • Shared dispatch pipeline: authorize (ADR 0054) → CEL → gha-dispatch output driver.
  • Jira write-then-verify coordination, repo-namespaced lock keys, lastCheck only on successful dispatch, fullsend poll --watch and fullsend poll cancel.
  • Jira NormalizedEvent schema extension + jira-poll-adapter.
  • Updates docs/architecture.md and docs/roadmap.md.

Test plan

  • ADR frontmatter and status pass repo ADR lint in CI
  • Cross-references to ADRs 0061, 0054, 0033 resolve
  • No ADR number collision on main (0063; 0062 is dispatch-version-skew)

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

Site preview

Preview: https://ba134e3d-site.fullsend-ai.workers.dev

Commit: 351d3fd63b0d2274f57f49ce644d41a5a4644205

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 18, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 10:07 AM UTC · Completed 10:21 AM UTC
Commit: d18e9a7 · View workflow run →

@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@ifireball ifireball self-assigned this Jun 18, 2026
@fullsend-ai-review

fullsend-ai-review Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review

Findings

Medium

  • [internal-inconsistency] docs/normative/normalized-event/v1/README.md:7 — The PR updates the Scope section (line 22+) to say "v1 adapters and examples target GitHub webhooks and Jira poll input" and the schema description from "GitHub-oriented" to "Forge-neutral", but two earlier references in the README remain GitHub-only: line 7 still reads "v1 normative scope is GitHub Actions only" and line 3 still says "GitHub-oriented routing input". These contradict the updated scope.
    Remediation: Update line 3 to "Forge-neutral routing input" (or similar) and line 7 to "v1 normative scope is GitHub Actions webhooks and Jira poll input" to match the updated Scope section.

  • [scope-violation] docs/normative/normalized-event/v1/normalized-event.schema.json:337 — Adding jira to the source.system enum expands v1 scope, which is allowed as a non-breaking change per the versioning rules. However, the schema description (line 5) still says "GitHub-oriented routing input", creating the same incomplete-update pattern as the README finding above. The scope expansion is intentional and well-motivated, but the documentation should be updated consistently across all scope-declaring locations.
    Remediation: Update the schema description at line 5 to reflect the expanded scope (e.g., "Forge-neutral routing input... v1 targets GitHub Actions webhooks and Jira poll input"). See also: [internal-inconsistency] finding at README.md.

Previous run

Review

Findings

Medium

  • [internal-inconsistency] docs/normative/normalized-event/v1/README.md:7 — The diff updates the Scope section (line 22) to include Jira poll input alongside GitHub webhooks, and updates the schema description from "GitHub-oriented" to "Forge-neutral", but two earlier references in the README remain GitHub-only: line 7 still reads "v1 normative scope is GitHub Actions only", and the opening description (line 3) still says "GitHub-oriented routing input". These contradict the updated scope and schema changes.
    Remediation: Update line 7 to match the new scope (e.g., "v1 normative scope covers GitHub Actions webhooks and Jira poll input") and update the line 3 summary from "GitHub-oriented" to "Forge-neutral" to match the schema description change.
Previous run (2)

Looks good to me


Labels: PR adds a new ADR and updates architecture/roadmap docs for the dispatch subsystem

Previous run (3)

Review

Findings

Medium

  • [internal-inconsistency] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:768 — Open question at lines 768–770 asks "Whether poll-triggered invocations pass synthetic event context into reusable-dispatch.yml or use a dedicated workflow_dispatch input shape with explicit stage and work_item fields." However, the Decision section (lines 473–477) already resolves this: the poll-trigger workflow calls stage reusable workflows directly with explicit stage, work_item, and poll inputs and "does not re-run reusable-dispatch.yml routing because the poller already determined the stage." The open question re-asks a choice the Decision section already made.
    Remediation: Remove or narrow this open question to focus on the exact schema of the poll-trigger workflow's inputs (field names, types, backward-compat constraints) rather than whether the poll path goes through reusable-dispatch.yml at all.

Low

  • [misleading-citation] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:205 — Line 204–206 cites ADR 0024 in the context of trigger design on harness files, but ADR 0024 covers harness execution configuration and does not discuss triggers. The subsequent reference to ADR 0045 (line 209) is correctly qualified ("not covered by"), but the ADR 0024 citation implies it has content relevant to triggers when it does not.
    Remediation: Reword to clarify ADR 0024 is referenced for the current harness schema context, not because it addresses triggers.

  • [edge-case] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:655 — In the optimistic locking algorithm, step 7.1 says "If the lock property timestamp is stale, remove the lock." If two concurrent pollers both detect the same stale lock and both remove it, both can proceed to write new locks, degrading the optimistic locking to the same race it was designed to prevent. The stale-lock removal should either use a conditional write (compare-and-swap) or be explicitly acknowledged as an accepted risk mitigated by the idempotency requirement at line 737.
    Remediation: Either specify conditional write for stale-lock removal, or add a note that this race is accepted because the idempotency requirement makes duplicate invocation safe.

Info

  • [authorization] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:297 — Current GitHub dispatch has inconsistent authorization across stages (/fs-triage, /fs-code, /fs-review do not require is_authorized today). The ADR documents this accurately and notes a pending ADR will tighten all human-initiated triggers. Poll driver implementations must track that ADR.

  • [authorization] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:329 — Jira's default trust boundary is weaker than GitHub's: any authenticated commenter can invoke agents unless actor.groups/project_roles are configured. The ADR documents this correctly and calls it out as a risk in the Consequences section.

  • [secrets-handling] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:765 — Credential placement for Jira and workflow dispatch credentials is listed as an open question. Implementation must ensure credentials are stored securely and not embedded in config.yaml values.

Previous run (4)

Review

Findings

High

  • [missing-authorization] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md — This is a non-trivial change (778 lines) with no linked issue. Per project rules, non-trivial changes require explicit authorization via a linked issue. The roadmap references issue JIRA trigger model — define how JIRA events reach fullsend agents #2263 ("JIRA trigger model") which directly maps to this ADR.
    Remediation: Link this PR to issue JIRA trigger model — define how JIRA events reach fullsend agents #2263 or another issue that documents the problem being solved.

  • [stale-doc] docs/architecture.md — Per AGENTS.md, when an ADR has status "Accepted", docs/architecture.md must be updated in the same PR. The "Agent Dispatch and Coordination Layer" section (lines 139–154) needs updating to reference ADR 0049 and describe polling-based dispatch as a complement to event-driven dispatch. Several open questions in that section are partially answered by this ADR's optimistic locking design.
    Remediation: Update docs/architecture.md "Agent Dispatch and Coordination Layer" section to add ADR 0049 under "Decided:" and describe the polling subsystem.

Medium

  • [race-condition] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:644 — The optimistic locking algorithm has a race window that can lead to duplicate invocations. While the ADR acknowledges this risk in Consequences, it does not state whether agents must be idempotent as a safety requirement or describe an additional mechanism beyond the two-layer defense (jitter + pre-invoke verification).

  • [stale-doc] docs/roadmap.md — The roadmap has a "JIRA-driven workflows" section in the "Next" phase that references issue JIRA trigger model — define how JIRA events reach fullsend agents #2263 for "JIRA trigger model". ADR 0049 directly addresses this and should be cross-referenced.

  • [parity-mapping-inaccuracy] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:410 — The parity table row for /fs-fix omits the bot exclusion check (COMMENT_USER_TYPE != Bot) that exists in reusable-dispatch.yml. The same omission occurs at line 305 for the needs-info auto-triage authorization description.

  • [stale-lock-threshold] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:659 — The default stale lock threshold of 120s may be insufficient. GitHub Actions queue times can exceed this during peak load, meaning the agent runner may not have started its lock-refresh routine before another poller treats the lock as stale. Consider increasing the default or splitting into dispatch-pending and agent-execution thresholds.

  • [internal-inconsistency] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:463 — The invocation driver says it uses workflow_dispatch on fullsend.yml, but the per-repo shim does not listen on workflow_dispatch. ADR 0041 allows workflow_dispatch for non-event entry points, but the ADR should clarify whether the shim needs modification or a dedicated poll-trigger workflow is required.

  • [authorization-claim-inconsistency] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:299 — The needs-info auto-triage authorization description omits the bot check that exists in reusable-dispatch.yml, presenting it as purely an association check.

Low

  • [stale-reference] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:201 — Claims ADR 0045 is working toward triggers on harness files, but ADR 0045 discusses forge-portable harness schema and leaves trigger definitions out of scope.
  • [edge-case] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:605 — The issue_created trigger baseline uses "issue creation time" when no prior check exists. On first deployment, every existing issue matching JQL would trigger, causing a thundering herd.
  • [naming-consistency] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md — Inconsistent terminology: "agent mappings", "stage mappings", "role", and "pipeline stage" used interchangeably.
  • [terminology-consistency] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:134 — Uses both "fullsend.yml" and ".github/workflows/fullsend.yml" for the same file.
  • [scope-creep] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md — The ADR scopes polling to per-repo mode only but introduces general-purpose abstractions. Clarifying the boundary between the authorized scope (per-repo Jira) and the speculative architecture (multi-driver) would strengthen the document.
  • [incomplete-doc] docs/problems/intent-representation.md — This problem doc discusses JIRA integration; a cross-reference to ADR 0049 would be helpful.

Info

  • [authorization] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:329 — Jira's default trust boundary is weaker than GitHub's: any authenticated commenter can invoke agents unless actor.groups/project_roles are configured. The ADR documents this correctly.
  • [authorization] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:297 — Current GitHub dispatch has inconsistent authorization across stages. Poll driver implementations must track the pending authorization ADR.
  • [secrets-handling] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md:753 — Credential placement is an open question. Implementation must ensure credentials are stored securely.
  • [open-question-tracking] docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md — The ADR lists 13 open questions, some of which (e.g., exact config.yaml schema) may warrant resolution before acceptance.

fullsend-ai-review[bot]

This comment was marked as outdated.

@ifireball
ifireball force-pushed the docs/adr-0049-polling-work-discovery branch from d18e9a7 to cb73aef Compare June 18, 2026 11:31
@ifireball ifireball changed the title docs(adr): add ADR 0049 polling-based work discovery docs(adr): add polling-based work discovery ADR Jun 18, 2026
@ifireball

Copy link
Copy Markdown
Member Author

Rebased onto latest main and pushed review fixes in cb73aeff:

  • Authorization: Fixes #2263 in commit + PR body
  • architecture.md / roadmap.md: cross-references updated per AGENTS.md
  • Idempotency: agent stages invoked via polling MUST be idempotent (Consequences)
  • Bot exclusion: parity table + needs-info auth table + exclude_bots / dispatch-equivalent gates
  • Stale lock: default raised to 300s with runner refresh guidance
  • Poll workflow: dedicated .github/workflows/fullsend-poll.yml via workflow_dispatch (shim unchanged)
  • ADR 0045: corrected stale reference; first-deploy thundering herd note; initial Jira vs future driver extensibility clarified

Please re-review when CI is green.

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 18, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 11:35 AM UTC · Completed 11:47 AM UTC
Commit: cb73aef · View workflow run →

Comment thread docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md Outdated
Comment thread docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md Outdated
Comment thread docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md Outdated
@rh-hemartin

Copy link
Copy Markdown
Member

I don't like the proposed conditionals. I would go with CEL expressions and have each poll_provider pass some native information. The information passed would be defined by the platform itself, and we would just forward it. This decouples our code a bit from the platforms, their version and breaking changes. A good starting point would be author details under author and event information under event, or something like that.

@ifireball

Copy link
Copy Markdown
Member Author

I don't like the proposed conditionals. I would go with CEL expressions and have each poll_provider pass some native information. The information passed would be defined by the platform itself, and we would just forward it. This decouples our code a bit from the platforms, their version and breaking changes. A good starting point would be author details under author and event information under event, or something like that.

That means that event processing and routing needs to happen in the Go code - not necessarily how I see it. I want to keep the option to convert the logic into something that is native to the execution platform or event source at runtime.

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Squad Report — 10-agent review

Agents dispatched: 10 (3× Claude-coder, 3× Claude-researcher, 2× Gemini, 2× Codex)
Unique findings posted inline: 17 (CRITICAL: 1, HIGH: 4, MEDIUM: 12)
Updated in-place: 1 (stale-lock-threshold, updated from earlier review)
Already posted (skipped): 4 (race-condition, parity-mapping-inaccuracy, internal-inconsistency, authorization-claim-inconsistency)

Findings are posted as inline comments below. See each comment for severity, details, and suggested fixes.

Assisted-by: Claude (review), Gemini (review), Codex (review)

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Squad Report — #2409

Agents dispatched: 10 (4× claude-coder, 4× claude-researcher, 1× gemini-code-review, 1× cursor-code-review)
Models used: Claude, Gemini, Codex
Total findings posted: 17 (1 critical, 4 high, 12 medium) — after dedup and false-positive removal
False positives removed: 7

See inline comments for details. Key themes:

  • ADR number collision (critical) — 0049 already taken on main; must renumber to 0055
  • Jira API constraints underestimated — no server-side changelog filter, points-based rate limits, elevated permissions for group/role lookups
  • Lock mechanism gaps — write-then-verify is not optimistic locking, namespace collisions across repos, no cancel mechanism
  • Authorization parity — ADR 0054 (already accepted) requires authorization on all dispatch paths; this ADR must comply
  • Premature architecture.md strikethrough — open question only partially decided

Assisted-by: Claude (triage, verification), Gemini (review), Codex (review)

Comment thread docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md Outdated
Comment thread docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md Outdated
Comment thread docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md Outdated
Comment thread docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md Outdated
Comment thread docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md Outdated
Comment thread docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md Outdated
Comment thread docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md Outdated
Comment thread docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md Outdated
Comment thread docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md Outdated
Comment thread docs/ADRs/0049-polling-based-work-discovery-and-agent-invocation.md Outdated
@rh-hemartin

Copy link
Copy Markdown
Member

That means that event processing and routing needs to happen in the Go code - not necessarily how I see it. I want to keep the option to convert the logic into something that is native to the execution platform or event source at runtime.

I understand... I'm worried about the complexity we will need to assume in order to support all the conditions the platform supports. But we can try it out.

Comment thread docs/ADRs/0062-polling-based-work-discovery.md Outdated
@ifireball

Copy link
Copy Markdown
Member Author

ADR rewrite summary (e56d0ab → latest)

This PR was rebased onto current main and renumbered 0049 → ADR 0062 (0049–0061 are taken).

What changed architecturally

Before After
~790-line ADR with poll-side triggers, actor blocks, parity table ~500 lines focused on discovery + coordination
poll_drivers[].agent_mappings[].triggers in config Dropped — routing is harness CEL per ADR 0061
Separate invocation driver / stage routing fullsend poll uses the same driver architecture as fullsend dispatch
fullsend watch (deferred separate command) fullsend poll --watch (flag reserved; impl deferred)
“Optimistic locking” Write-then-verify (Jira has no CAS); idempotency is mandatory
Stale lock 300s 900s default + two-phase lock guidance
lastCheck before dispatch lastCheck only after successful dispatch
Global lock keys Repo-namespaced fullsend.poll.{owner}.{repo}.*

Pipeline (new mental model)

fullsend poll [--watch]
  → poll input driver (jira-poll): discover + lock + emit NormalizedEvent
  → fullsend dispatch core: authorize (ADR 0054) → harness CEL (ADR 0061)
  → output driver (gha-dispatch): dispatch directly, not JSON plan

Review feedback addressed

  • ADR number collision → 0062
  • ADR 0054 / authorization → delegated to dispatch core (not poll config)
  • JQL entity-property indexing → client-side lock filter documented
  • Trigger payload / slash args → NormalizedEvent.transition.comment
  • M/N backlog starvation, rate limits, lock handoff TOCTOU → documented
  • architecture.md / roadmap.md updated; no strikethrough overclaim

Latest commit: Jira NormalizedEvent extension

Added jira-poll-adapter.md — field mapping, transition table, actor rules, example fixture, CEL sample. repo stays the target GitHub repo; Jira issue is entity with key + numeric id.

Schema follow-up (non-blocking): add source.system: jira and optional entity.key to normalized-event.schema.json.

Open questions — triage

Deferred items are now a table in ADR 0062 with resolution owner:

  • Implementation epic #2263 — config schema, gha-dispatch, credentials, lock refresh, --watch defaults
  • Small schema PR — Jira enum + entity.key in normative JSON schema
  • Post-MVP issuespoll cancel, GitHub/GitLab poll drivers, dev-panel linked PRs, formal metrics (#896)

Please re-review when CI is green.

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 1, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 10:20 AM UTC · Ended 10:33 AM UTC
Commit: f417572 · View workflow run →

@ifireball
ifireball force-pushed the docs/adr-0049-polling-work-discovery branch from ef757e7 to 7c3f126 Compare July 1, 2026 10:33
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 1, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 10:37 AM UTC · Ended 10:45 AM UTC
Commit: f417572 · View workflow run →

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 1, 2026

Copy link
Copy Markdown

🤖 Finished Review · ❌ Failure · Started 10:48 AM UTC · Completed 11:14 AM UTC
Commit: 37cdced · View workflow run →

ifireball and others added 5 commits July 2, 2026 09:40
Per-repo polling via fullsend poll input drivers (Jira first) and the
shared fullsend dispatch pipeline. Harness CEL triggers (ADR 0061) own
routing; poll drivers emit NormalizedEvents and write-then-verify locks.

Update architecture.md and roadmap.md cross-references.

Fixes fullsend-ai#2263

Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Define jira-poll adapter mapping in normative docs, link from ADR 0062,
and triage remaining open questions to implementation follow-ups.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Add source.system jira, optional entity.key (required for Jira events),
jira-fs-triage-comment example fixture, and align adapter docs with schema.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Add fullsend poll cancel to ADR 0062, defer exportable metrics to post-MVP,
drop dev-panel scope from Jira adapter, and rely on GHA concurrency groups
for duplicate dispatch mitigation instead of a new idempotency mandate.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Per review: poll --watch is the only named interface; no need to reference
a separate watch subcommand that was never released.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@ifireball
ifireball force-pushed the docs/adr-0049-polling-work-discovery branch from 37cdced to da94ec9 Compare July 2, 2026 06:43
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 2, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 6:44 AM UTC · Ended 6:46 AM UTC
Commit: 9f4f2b6 · View workflow run →

0062 is now dispatch-version-skew on main; update cross-references in
architecture, roadmap, and normative Jira poll docs.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 2, 2026

Copy link
Copy Markdown

🤖 Finished Review · ❌ Failure · Started 6:47 AM UTC · Completed 7:01 AM UTC
Commit: 351d3fd · View workflow run →

@ggallen ggallen left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review

Findings

Medium

  1. [design] Two-phase lock deferred but load-bearing0063-polling-based-work-discovery.md ~L394: "Consider a two-phase lock" is phrased as a suggestion in the Decision section. The handoff gap between poller exit and runner first refresh is the primary duplicate-dispatch failure mode. If GHA queue latency exceeds stale_threshold − runner_startup − refresh_interval/2, a second poller steals the lock. The poll-trigger workflow "SHOULD refresh the lock as its first step" (~L299) uses SHOULD rather than MUST. This should either be decided (pending→running phases) or explicitly moved to Open Questions with the risk documented.

  2. [design] Agent idempotency stated as SHOULD but is the actual safety net0063 ~L355: "Agent implementations SHOULD still be safe to re-run." Since GHA concurrency groups have known gaps (cross-stage races, pre-group-entry window), idempotency is not optional defense-in-depth — it's the real safety net for duplicate dispatch. Consider MUST, or at minimum document why SHOULD is acceptable.

  3. [design] Config drift: orphaned JQL queries — Poll discovery config lives in config.yaml while routing lives in harness CEL triggers. If a harness is removed but its JQL query remains, the poller discovers work, generates NormalizedEvents, pays the API cost, but matches zero harnesses. No validation or warning is specified to detect this drift.

  4. [completeness] Missing consequence: credential surface area — The ADR introduces Jira API token dependencies into per-repo config (a new credential to manage and rotate), but Consequences doesn't list this. It appears only in Open Questions. Deserves an explicit negative consequence.

Low

  1. [cross-ref] ADR number collision risk — Three open PRs (#2409, #2583, #2743) all claim ADR number 0063. Whichever merges first owns it; the others must renumber. Recommend running /renumber-adr before merge.

  2. [cross-ref] Minor title truncations in References — ADR 0016 listed as "Unidirectional control flow" (actual: "…through the execution stack"). ADR 0041 omits "agent" from "…event-driven agent dispatch." Non-blocking.

  3. [schema] entity.key pattern is Jira-specific — Pattern ^[A-Za-z][A-Za-z0-9_]+-\d+$ doesn't allow hyphens in the prefix portion. Fine for Jira, but the field description says "Human-readable work item key when the source system uses one" — may need loosening when future systems are added.

  4. [style] "Consider a..." in Decision section — L394's advisory language in a section that should be declarative. Either commit to it or move to Open Questions.

  5. [completeness] fullsend poll cancel lacks --dry-run — As an operational recovery tool used under pressure, previewing what would be cancelled before acting is standard practice.

  6. [completeness] API budget section is directional — Provides no per-cycle budget estimate. With M=50 candidates and client-side lock filtering, operators have no baseline for tuning.

Schema & Consistency

  • Schema changes are valid JSON Schema 2020-12. The if/then conditional for entity.key when source.system is jira is correctly structured.
  • Example fixture validates against the updated schema.
  • Inline example in adapter doc matches the fixture file.
  • Transition kinds in adapter doc are all valid per the schema enum.
  • Environment variables are consistent between ADR and adapter doc.
  • All cross-reference links resolve correctly across all 7 files.

Verdict

Approve. The architecture is sound — the composition model over ADR 0061 is clean, the dual-layer duplicate mitigation is pragmatic, and per-repo scoping is appropriate. The medium findings are real design gaps but are mitigatable during implementation. None block merge for a docs-only ADR.

@ifireball
ifireball added this pull request to the merge queue Jul 5, 2026
Merged via the queue into fullsend-ai:main with commit 1b29d03 Jul 5, 2026
16 checks passed
@ifireball
ifireball deleted the docs/adr-0049-polling-work-discovery branch July 5, 2026 22:28
@fullsend-ai-retro

fullsend-ai-retro Bot commented Jul 5, 2026

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 10:30 PM UTC · Completed 10:42 PM UTC
Commit: 351d3fd · View workflow run →

@fullsend-ai-retro

Copy link
Copy Markdown

PR #2409 added ADR 0063 (polling-based work discovery) across a 17-day lifecycle. The review agent ran 7+ times (2 successful, 3 cancelled, 2 failed-but-analysis-completed), approving after a major rewrite. Two human reviewers also approved but caught substantive design gaps the agent missed: RFC 2119 keyword misuse on load-bearing mechanisms, incomplete operational consequences, config drift risks, and advisory language in the Decision section. The agent's findings were limited to surface-level inconsistencies. One proposal targets enriching AGENTS.md ADR review guidance with the specific analytical checks humans applied and the agent missed. Related existing issues: #1480 (shallow docs feedback), #1469 (missing feature-level design assessment).

Proposals filed

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

Labels

component/dispatch Workflow dispatch and triggers component/docs User-facing documentation ready-for-merge All reviewers approved — ready to merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JIRA trigger model — define how JIRA events reach fullsend agents

4 participants