Tasks: the poller reads all three PR comment surfaces
The last spec artifact. A DAG derived from the approved design and testing plan.
Task list
[x] 1. Write the failing unit tests for fetch, merge and filtering
list_commentson a PR issuesgh pr view --json commentsplus the twogh api …/pulls/<n>/{reviews,comments}reads; on an issue it issues the one call it always did.- The merged list is time-ordered; empty-body and
PENDINGreviews are absent; an outdated inline comment falls back tooriginal_line. - Depends on: none
- Requirements: R1.3, R1.4, R1.5, R2.2, R2.3, R2.4, R4.1, R4.2
- Test:
T1 — uv run pytest cli/tests/test_poller.py -k "comments or review"(red→green)
[x] 2. Write the failing unit tests for the per-kind event shapes and the guards
comment_eventemitspull_request_review/pull_request_review_comment/issue_commentwith the payload key each name implies, and the anchor on the inline one;router.event_actorandrouter.event_bodyresolve on the produced payloads.- Negative: unauthorized reviewer, the-loop's own self-marked review,
user: null. - Depends on: none
- Requirements: R1.3, R2.2, R3.1, R3.2, R3.3
- Test:
T8 — uv run pytest cli/tests/test_poller.py -k "unauthorized or self_authored"(red→green)
[x] 3. Write the failing integration test (Gherkin) for a whole poll cycle
- Two cycles over one polled PR: the review body and the inline comment are dispatched once each and not again; the empty approval and the unauthorized review never are.
- Depends on: none
- Requirements: R1.1, R1.2, R2.1, R2.2, R3.1, R5.2
- Test:
T2 — uv run pytest cli/tests/test_poller_integration.py -k review(red→green)
[x] 4. Capture the red run as evidence
- Depends on: 1, 2, 3
- Requirements: R5.1
- Test:
T12 — evidence/red.md
[x] 5.
Commentcarries provider extras- Add
raw: Dict = field(default_factory=dict)topoller/base.py, documented as the provider's own channel (mirrorsWorkItem.raw); the core never reads it. - Depends on: 1, 2, 3
- Requirements: R1.3, R2.2
- Test:
T1,T13
- Add
[x] 6. Fetch and merge the three streams
GhCommentgainskind,state,path,line;GhClientgainslist_reviews/list_review_comments(bothgh api --paginate), andlist_commentsmerges/sorts/filters for a PR only.- Depends on: 5
- Requirements: R1.1, R1.4, R1.5, R2.1, R2.3, R4.1, R4.2, R4.4
- Test:
T1(green)
[x] 7. Shape the event per kind
GitHubPollProvider.list_commentspasses the extras throughComment.raw;comment_eventbranches on the kind.- Depends on: 6
- Requirements: R1.3, R2.2, R2.4, R3.3
- Test:
T2,T8(green)
[x] 8. Raise the retained-id cap
_SEEN_COMMENTS_CAP500 → 2000 with the reasoning at the constant.- Depends on: 5
- Requirements: R4.3
- Test:
T10
[x] 9. Update the capability doc and the user-facing docs
docs/capabilities/webhook-triggers.md: which surfaces the poll ingress reads, plus a history row. Checkdocs/config/cli/polling-options.mdand the README for statements this makes wrong.- Depends on: 7
- Requirements: R5.3
- Test:
T14(markdownlint) +T13(test_docs_parity.py)
[x] 10. Verification, evidence, reviews
- Execute
testing-plan.md, commit evidence, run the self-review rounds and the security review, write the reviewer briefing. - Depends on: 8, 9
- Requirements: all
- Test:
T13,T14
- Execute
Dependency graph (DAG)
flowchart LR
T1["1 · unit red<br/>fetch & merge"] --> T4["4 · capture red"]
T2["2 · unit red<br/>events & guards"] --> T4
T3["3 · integration red<br/>poll cycle"] --> T4
T4 --> T5["5 · Comment.raw"]
T5 --> T6["6 · fetch three streams"] --> T7["7 · event per kind"] --> T9["9 · docs"]
T5 --> T8["8 · id cap"]
T8 --> T10["10 · verify, evidence, review"]
T9 --> T10Tasks 1–3 are independent red roots; nothing production-side starts before task 4 has the red on record.
Checkpoints
- After task 4: the red run is committed as its own commit, before any fix.
- After task 7: targeted suites green (T1, T2, T8).
- After task 9:
uv run pytest(T13) and the lint/typecheck/markdown set (T14). - After task 10: the
verificationnode fillstesting-plan.md§ Verification results, then the review phases run.
Deviations
- Task 6 also left
gh pr view --json commentsalone rather than folding it into the REST reads. Anticipated indesign.md; recorded here because the task text could be read as replacing the existing call. - Task 2's
user: nullcase is asserted at theGhClientparsing layer (author becomes"") plus the existingis_authorized("")unit coverage, rather than as a third end-to-end negative — the two halves compose, and a third cycle test would assert the allowlist, not this change.
Review comments
Appended by the-loop's
record-feedbackhook when a human gate approves with comments (issue-109).
None yet.