Skip to content

Phase 08: GitHub Action + README#16

Merged
Galzi1 merged 29 commits into
mainfrom
fix/qodo-issue-comment-filter
Apr 11, 2026
Merged

Phase 08: GitHub Action + README#16
Galzi1 merged 29 commits into
mainfrom
fix/qodo-issue-comment-filter

Conversation

@Galzi1

@Galzi1 Galzi1 commented Apr 11, 2026

Copy link
Copy Markdown
Owner

Summary

Phase 8: github-action-readme
Goal: A repository maintainer can add a provided workflow file and have PR comments automatically extracted after merged PRs or manual recovery runs, with no wasted API calls when nothing is new, and a new user can get from zero to a generated KB by following the README alone.
Status: Verified via UAT, security audit, Nyquist validation, and live consumer-repo demo

This ships the copyable GitHub Actions workflow, the standalone action-state helper, and an automation-first README/.env surface. The branch also includes the follow-up fixes discovered during the live Phase 8 demo so the shipped workflow, extractor filters, and classifier behavior match the validated happy path.

Changes

Plan 01: Action State Helper

Added a standalone github_pr_kb.action_state module that makes workflow run/skip decisions testable and deterministic.

Key files:

  • src/github_pr_kb/action_state.py
  • tests/test_action_state.py

Plan 02: Workflow Automation

Shipped the merged-PR plus workflow_dispatch automation workflow, including cache restore, rolling PR publication, and monotonic cursor persistence.

Key files:

  • .github/workflows/github-pr-kb.yml
  • tests/test_action_workflow.py

Plan 03: README Rewrite

Rewrote the README around the shipped workflow and aligned .env.example with the real local config surface.

Key files:

  • README.md
  • .env.example
  • tests/test_readme.py

Demo hardening included on this branch

Follow-up fixes from the live consumer-repo validation are included in this PR so the shipped phase matches the validated behavior.

Key files:

  • src/github_pr_kb/classifier.py
  • src/github_pr_kb/extractor.py
  • tests/test_classifier.py
  • tests/test_extractor.py

Requirements Addressed

  • ACTION-01 — User can trigger automated extraction via a provided GitHub Actions workflow file
  • ACTION-02 — GitHub Action only runs extraction when new PRs exist since the last run (cost-aware guard)
  • ACTION-03 — GitHub Action persists last-run state so incremental runs skip already-processed PRs
  • INFRA-03 — README documents setup, environment variables, CLI usage, and includes example KB output

Verification

  • UAT passed: .planning/phases/08-github-action-readme/08-UAT.md (4/4 checks passed)
  • Security passed: .planning/phases/08-github-action-readme/08-SECURITY.md (threats_open: 0, 14 threats closed)
  • Nyquist validation passed: .planning/phases/08-github-action-readme/08-VALIDATION.md (0 gaps)
  • Automated validation:
    • .\.venv\Scripts\python.exe -m pytest tests\test_action_state.py tests\test_action_workflow.py tests\test_readme.py -q
    • .\.venv\Scripts\python.exe -m pytest tests -q
  • Live consumer-repo demo:
    • Feature PR with human review comments: Galzi1/github-pr-kb-demo#10
    • Final workflow replay: run 24277455924
    • Generated KB PR opened and merged: Galzi1/github-pr-kb-demo#11
    • Post-merge steady-state run: 24277477172

Key Decisions

  • Keep workflow skip/cursor logic in a stdlib-only Python helper instead of opaque YAML.
  • Bootstrap consumer repos from a second checkout via KB_TOOL_REPOSITORY and immutable KB_TOOL_REF.
  • Prefer GitHub App auth for repository-variable writes, with KB_VARIABLES_TOKEN as the fallback path.
  • Persist KB_LAST_SUCCESSFUL_CURSOR only after successful publication, and only as the monotonic max against the freshest stored value.
  • Keep docs automation-first and explicitly separate committed KB output from transient .github-pr-kb/cache/.

Galzi1 and others added 23 commits April 9, 2026 00:27
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
fix: recover wrapped classifier JSON for phase 8 demo
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@qodo-code-review

Copy link
Copy Markdown
ⓘ You are approaching your monthly quota for Qodo. Upgrade your plan

Review Summary by Qodo

Phase 8 Complete: GitHub Actions Automation Workflow + README Rewrite with Bot Comment Filtering

✨ Enhancement 🧪 Tests 📝 Documentation

Grey Divider

Walkthroughs

Description
  **Phase 8 Completion: GitHub Actions Automation + README Rewrite**
• Shipped copyable GitHub Actions workflow (.github/workflows/github-pr-kb.yml) triggered on
  merged PRs and manual workflow_dispatch with dual-mode auth (GitHub App preferred, PAT fallback)
• Implemented action_state helper module for testable, deterministic workflow skip/cursor
  decisions with stdlib-only imports and CLI interface
• Added robust comment filtering: Qodo bot issue comments excluded, automation KB publication PR
  skipped, while preserving inline review comments
• Enhanced classifier robustness to parse JSON from markdown fences, prose-wrapped responses, and
  varied model output formats
• Rewrote README with automation-first structure, credential-role matrix, platform-aware local
  setup, and explicit committed-vs-not-committed artifact guidance
• Added comprehensive test coverage for action state logic, workflow contract, extractor filtering,
  classifier parsing, and README/.env.example alignment
• Completed Phase 8 with all three plans (action-state helper, workflow automation, README rewrite)
  verified through UAT, security audit, Nyquist validation, and live consumer-repo demo
• Configuration extended with kb_bot_branch field to identify rolling KB publication PR without
  hardcoding
Diagram
flowchart LR
  A["Merged PR Event<br/>or Manual Dispatch"] -->|"action_state helper"| B["Skip/Cursor Decision"]
  B -->|"Monotonic Cursor"| C["Extract New Comments"]
  C -->|"Filter Qodo Issues<br/>Skip Automation PR"| D["Cleaned Comments"]
  D -->|"Robust Parsing"| E["Classify Comments"]
  E -->|"Generate KB"| F["Publish Rolling PR"]
  F -->|"Persist Cursor"| G["Repository Variable"]
  H["README + .env.example"] -->|"Automation-First<br/>Dual Auth"| I["User Bootstrap"]
Loading

Grey Divider

File Changes

1. src/github_pr_kb/action_state.py ✨ Enhancement +183/-0

Workflow decision helper for GitHub Action skip/cursor logic

• New stdlib-only module for workflow skip/cursor decision logic, intentionally import-safe to run
 before repository secrets are available
• Implements decide_action_run() function that handles both auto merged-PR events and manual
 workflow_dispatch paths with separate cursor logic
• Provides CLI interface via main() that emits JSON-serialized ActionRunDecision for workflow
 consumption
• Includes comprehensive timestamp normalization and ISO-8601 formatting with timezone validation

src/github_pr_kb/action_state.py


2. tests/test_action_state.py 🧪 Tests +150/-0

Tests for action state decision logic and CLI interface

• Comprehensive test coverage for action_state module including merged PR events, manual dispatch,
 cursor monotonicity, and forced runs
• Tests validate that repeated auto events are skipped, manual runs use separate cursor logic, and
 next_cursor never regresses past stored_cursor
• Includes subprocess-based CLI execution test to verify the helper runs without repository or API
 secrets
• Tests malformed timestamp input rejection to ensure robust error handling

tests/test_action_state.py


3. tests/test_extractor.py 🧪 Tests +106/-1

Extractor tests for bot comment filtering and automation PR skipping

• Added head_ref parameter to make_mock_pr() helper to support branch-name-based filtering
• New test test_qodo_issue_comments_are_filtered() verifies that Qodo bot issue comments are
 excluded from extraction
• New test test_qodo_review_comment_is_kept() confirms that Qodo inline review comments remain
 eligible for extraction
• New test test_automation_kb_pr_is_skipped() validates that the rolling KB publication PR is
 excluded entirely from extraction

tests/test_extractor.py


View more (28)
4. tests/test_action_workflow.py 🧪 Tests +121/-0

GitHub Actions workflow contract and execution tests

• New test file with contract assertions for .github/workflows/github-pr-kb.yml workflow structure
 and behavior
• Tests verify merged-PR and workflow_dispatch triggers, no cron schedule, concurrency
 serialization, and merged-only guard
• Validates tool bootstrap strategy: explicit KB_TOOL_REPOSITORY and KB_TOOL_REF checkout with
 uv sync --project installation
• Tests confirm cache restoration, explicit KB publication staging via git pathspecs, monotonic
 cursor persistence, and pinned action refs by full commit SHA
• Includes execution-oriented smoke test that runs the helper command through project checkout
 environment

tests/test_action_workflow.py


5. src/github_pr_kb/classifier.py ✨ Enhancement +61/-3

Classifier robustness for varied model output formats

• Added _parse_classification_response() function to extract JSON from bare, fenced, or
 prose-wrapped model output instead of requiring raw top-level JSON
• New _is_valid_classification_payload() helper validates that parsed objects satisfy the
 classifier response contract (category, summary, confidence fields)
• Regex pattern _JSON_FENCE_RE matches markdown-fenced JSON blocks with optional language
 specifier
• Updated _classify_comment() to use robust parsing instead of direct json.loads(), improving
 resilience to model output variations

src/github_pr_kb/classifier.py


6. tests/test_classifier.py 🧪 Tests +90/-0

Classifier parsing robustness tests for model output variations

• New test test_markdown_fenced_json_is_parsed() validates extraction of JSON from markdown code
 fences
• New test test_prose_wrapped_json_is_parsed() confirms JSON extraction from prose-wrapped model
 responses
• New test test_unrelated_json_dict_is_skipped_before_valid_classification() ensures invalid JSON
 objects are skipped before finding valid classifications
• New test test_schema_less_json_object_is_rejected() verifies that empty or schema-invalid JSON
 objects are properly rejected

tests/test_classifier.py


7. src/github_pr_kb/extractor.py ✨ Enhancement +18/-0

Extractor filtering for bot comments and automation PRs

• New is_ignored_issue_comment() function filters out Qodo bot issue comments while preserving
 Qodo review comments
• New _is_automation_kb_pr() helper identifies the rolling KB publication PR by branch name using
 settings.kb_bot_branch
• Updated _comment_to_record() to call is_ignored_issue_comment() before noise filtering
• Updated extract() method to skip automation KB PRs early in the loop with informational logging

src/github_pr_kb/extractor.py


8. src/github_pr_kb/config.py ⚙️ Configuration changes +1/-0

Configuration for automation KB publication branch name

• Added kb_bot_branch: str = "automation/github-pr-kb" configuration field to define the dedicated
 automation branch name
• Allows extractor to identify and skip the rolling KB publication PR without hardcoding the branch
 name

src/github_pr_kb/config.py


9. tests/test_readme.py 🧪 Tests +92/-0

README and environment template contract tests

• New test file with text-contract assertions for README and .env.example alignment
• Tests verify automation-first section ordering, workflow file documentation, copyable bootstrap
 strategy with KB_TOOL_REPOSITORY and KB_TOOL_REF
• Validates credential-role separation between local/runtime auth and workflow repository-variable
 auth
• Tests confirm platform-aware local setup guidance, committed-vs-not-committed documentation, and
 .env.example alignment with local config surface

tests/test_readme.py


10. .planning/phases/08-github-action-readme/08-02-PLAN.md 📝 Documentation +278/-0

Phase 8 Plan 02: GitHub Actions workflow automation execution plan

• Detailed execution plan for GitHub Actions workflow implementation (Plan 02 of Phase 8)
• Specifies workflow triggers (merged PR + workflow_dispatch), tool bootstrap strategy, cache
 handling, and monotonic cursor persistence
• Documents threat model covering variable auth, cursor persistence, git publication scope, and
 external ref pinning
• Includes acceptance criteria for workflow contract tests and implementation tasks

.planning/phases/08-github-action-readme/08-02-PLAN.md


11. .planning/phases/08-github-action-readme/08-DEMO-COMPLETE.md 📝 Documentation +303/-0

Phase 8 demo completion status and validation checklist

• Comprehensive demo completion status and checklist for Phase 8 end-to-end validation in
 github-pr-kb-demo repository
• Documents prior validation progress, current limitations, and remaining work required for complete
 demo
• Provides comment-input contract with realistic example review comments aligned to supported
 categories
• Includes five-minute triage checklist for diagnosing extraction, classification, generation,
 dedup, and permission failures
• Defines article-fidelity checklist for human review of generated KB PRs

.planning/phases/08-github-action-readme/08-DEMO-COMPLETE.md


12. .planning/phases/08-github-action-readme/08-DEMO-COMPLETE-RISK-REVIEW.md 📝 Documentation +139/-0

Risk review and recommendations for Phase 8 demo completion

• Risk analysis and devil's advocacy review of the demo completion plan
• Identifies 8 key risks including unresolved classifier failure mode, insufficient observability,
 and overclaiming confidence from single curated run
• Provides inversion tests and failure-of-imagination scenarios to stress-test plan assumptions
• Recommends promoting diagnosis to hard gate, adding comment-input contract, and reducing
 confidence claim scope

.planning/phases/08-github-action-readme/08-DEMO-COMPLETE-RISK-REVIEW.md


13. .planning/phases/08-github-action-readme/08-03-PLAN.md 📝 Documentation +203/-0

Phase 8 Plan 03: README and environment template documentation plan

• Detailed execution plan for README rewrite and .env.example alignment (Plan 03 of Phase 8)
• Specifies automation-first documentation structure, credential-role separation, and copyable
 workflow bootstrap explanation
• Documents platform-aware local setup guidance, committed-vs-not-committed clarity, and
 .env.example alignment requirements
• Includes threat model covering auth setup, repo hygiene, and documentation consistency

.planning/phases/08-github-action-readme/08-03-PLAN.md


14. .planning/phases/08-github-action-readme/08-01-PLAN.md ✨ Enhancement +197/-0

Action state helper plan with TDD test contract

• Introduces a new plan for creating a testable action_state helper module to decide workflow
 skip/cursor behavior
• Defines two execution tasks: TDD-style test-first approach for skip/cursor logic, then
 implementation of the helper with CLI entrypoint
• Specifies exact test scenarios covering auto merged-event paths, manual recovery paths, and
 deterministic error handling
• Establishes handoff contract for downstream workflow plan including timestamp sourcing and
 monotonic persistence requirements

.planning/phases/08-github-action-readme/08-01-PLAN.md


15. .planning/phases/08-github-action-readme/08-RESEARCH.md 📝 Documentation +304/-0

Phase 8 research on Actions patterns and auth strategies

• Comprehensive research document covering GitHub Actions patterns, auth strategies, and state
 persistence mechanisms
• Recommends reusing existing CLI subcommands (extract, classify, generate) instead of run
 command for incremental control
• Identifies dual-mode auth pattern (PAT quickstart + GitHub App advanced path) for
 repository-variable writes
• Documents runtime state inventory and validates that no new external dependencies are required

.planning/phases/08-github-action-readme/08-RESEARCH.md


16. .github/workflows/github-pr-kb.yml ✨ Enhancement +317/-0

Merged-PR and manual-dispatch GitHub Actions workflow

• Shipped copyable GitHub Actions workflow triggered on merged PRs and workflow_dispatch for
 manual recovery
• Bootstraps the tool from external checkout via KB_TOOL_REPOSITORY and immutable KB_TOOL_REF
• Implements dual-mode auth (GitHub App preferred, PAT fallback) for repository-variable operations
• Stages only KB output (kb/INDEX.md, kb/**/*.md, kb/.manifest.json) while preserving
 .github-pr-kb/cache/ outside git
• Persists KB_LAST_SUCCESSFUL_CURSOR monotonically after successful publication using fresh
 repository-variable read

.github/workflows/github-pr-kb.yml


17. .planning/phases/08-github-action-readme/08-02-RISK-REVIEW.md 📝 Documentation +105/-0

Workflow automation risk review and mitigation guidance

• Risk review identifying critical unknowns in workflow portability, concurrency safety, and GitHub
 App auth specification
• Flags R1 (helper execution path breaks in copied repos), R2 (out-of-order runs corrupt cursor), R3
 (App auth underspecified)
• Recommends explicit helper invocation through tool environment, workflow concurrency plus
 monotonic persistence, and immutable tool ref pinning
• Validates that plan correctly reuses action_state helper and makes workflow copy-ready as
 first-class requirement

.planning/phases/08-github-action-readme/08-02-RISK-REVIEW.md


18. .planning/phases/08-github-action-readme/08-03-RISK-REVIEW.md 📝 Documentation +99/-0

README documentation risk review and alignment guidance

• Risk review for README rewrite plan identifying credential-role confusion, platform-specific
 guidance, and .env.example drift risks
• Flags R1 (token role confusion), R3 (README/.env.example divergence), R2 (Windows-only test
 command)
• Recommends token-role matrix in README, platform-specific commands, and explicit .env.example
 alignment
• Validates automation-first ordering and explicit committed-vs-not-committed guidance as plan
 strengths

.planning/phases/08-github-action-readme/08-03-RISK-REVIEW.md


19. README.md 📝 Documentation +151/-20

Automation-first README rewrite with dual auth paths

• Rewrote README to lead with GitHub Actions automation setup before local CLI usage
• Added sections for workflow bootstrap, tool versioning, credential roles, PAT quickstart, GitHub
 App advanced path, and manual recovery inputs
• Documented committed vs not-committed artifacts (KB output committed, .github-pr-kb/cache/ not
 committed)
• Preserved local setup instructions with platform-aware commands (Windows
 .venv\Scripts\python.exe and Unix .venv/bin/python)
• Added credential role matrix separating local runtime auth from workflow repository-variable auth

README.md


20. .planning/phases/08-github-action-readme/08-DISCUSSION-LOG.md 📝 Documentation +164/-0

Phase 8 decision discussion and alternatives audit trail

• Audit trail documenting decisions made during Phase 8 context gathering
• Records user choices on trigger model (post-merge + manual dispatch), publication mode (rolling
 bot PR), state persistence (repository variable), and README structure (automation-first)
• Captures alternatives considered for each decision dimension
• Preserves rationale for incremental boundary, PR state scope, cache persistence, and recovery
 cursor role

.planning/phases/08-github-action-readme/08-DISCUSSION-LOG.md


21. .planning/phases/08-github-action-readme/08-01-RISK-REVIEW.md 📝 Documentation +70/-0

Action state helper risk review and cursor safety guidance

• Risk review for action_state helper plan identifying timestamp sourcing, concurrency, and manual
 cursor regression risks
• Flags R1 (manual backfill can regress cursor), R2 (concurrent runs corrupt state), R3 (timestamp
 semantics drift)
• Recommends fixing manual cursor formula to use `max(stored_cursor, manual_since,
 latest_merged_at)` and adding concurrency/monotonic persistence to workflow
• Validates that moving logic to Python improves testability while requiring explicit workflow
 concurrency safeguards

.planning/phases/08-github-action-readme/08-01-RISK-REVIEW.md


22. .planning/phases/08-github-action-readme/08-VALIDATION.md 📝 Documentation +108/-0

Phase 8 validation strategy and Nyquist compliance audit

• Structured validation strategy with Nyquist compliance mapping for Phase 8 requirements
• Defines per-task verification map linking requirements to test types and automated commands
• Documents live consumer-repo validation evidence from Galzi1/github-pr-kb-demo (feature PR
 ingestion, KB generation, post-merge steady-state)
• Confirms all phase behaviors have automated verification and zero validation gaps

.planning/phases/08-github-action-readme/08-VALIDATION.md


23. .planning/phases/08-github-action-readme/08-CONTEXT.md 📝 Documentation +119/-0

Phase 8 context, decisions, and canonical reference surfaces

• Context document establishing Phase 8 boundary, implementation decisions (D-01 through D-14), and
 canonical references
• Locks trigger model (post-merge + manual dispatch), incremental boundary (PR updated_at),
 publication mode (rolling bot PR), and auth setup (dual-mode)
• References existing code surfaces (cli.py, extractor.py, generator.py, config.py) and
 established patterns (.github-pr-kb/ ignored, KB/ committed)
• Defers agent discretion on exact event syntax, bot PR naming, manual dispatch inputs, and README
 formatting

.planning/phases/08-github-action-readme/08-CONTEXT.md


24. .planning/phases/08-github-action-readme/08-SECURITY.md 📝 Documentation +77/-0

Phase 8 security threat register and audit trail

• Security audit document with 14 threats identified and closed across helper, workflow, and
 documentation
• Covers trust boundaries for workflow inputs, helper outputs, repository-variable writes, and
 README guidance
• Mitigations include timestamp validation, deterministic error handling, concurrency-safe cursor
 persistence, and explicit auth role documentation
• Confirms threats_open: 0 and status: verified with all dispositions assigned

.planning/phases/08-github-action-readme/08-SECURITY.md


25. .planning/ROADMAP.md 📝 Documentation +6/-4

Roadmap update for Phase 8 completion and plan inventory

• Updated Phase 8 goal wording from "schedule" to "merged PRs or manual recovery runs"
• Added three completed plans to Phase 8 (08-01, 08-02, 08-03) with brief descriptions
• Updated progress tracking to show Phase 8 as 3/3 plans complete and ready for verification
• Changed overall progress from 29% to 100% with all 15 plans completed

.planning/ROADMAP.md


26. .planning/STATE.md 📝 Documentation +14/-14

Project state update for Phase 8 completion

• Updated project state to reflect Phase 8 completion (phase 8, plan 03 complete)
• Changed status from "Phase 7 context gathered" to "Phase 8 plans complete — ready for
 verification"
• Updated progress metrics: 7/8 completed phases, 15/15 completed plans, 100% overall progress
• Updated timestamps and session continuity markers to 2026-04-10

.planning/STATE.md


27. .planning/phases/08-github-action-readme/08-02-SUMMARY.md 📝 Documentation +32/-0

Plan 02 workflow automation completion summary

• Summary document for Plan 02 (Workflow Automation) capturing accomplishments and outcomes
• Documents shipped workflow file, tool bootstrap mechanism, auth wiring, cache handling, and
 contract tests
• Lists key decisions on copyability, auth precedence, and cursor persistence strategy
• Confirms requirements ACTION-01, ACTION-02, ACTION-03 completed

.planning/phases/08-github-action-readme/08-02-SUMMARY.md


28. .planning/phases/08-github-action-readme/08-UAT.md 📝 Documentation +45/-0

Phase 8 user acceptance testing results (4/4 passed)

• User acceptance testing document with 4 test cases covering workflow bootstrap, cursor guard,
 auth/publication, and README onboarding
• All 4 tests passed with zero issues, pending items, or gaps
• Validates copyable workflow, no-new-PR guard, auth separation, and README local guidance
• Confirms Phase 8 UAT complete as of 2026-04-10

.planning/phases/08-github-action-readme/08-UAT.md


29. .planning/phases/08-github-action-readme/08-03-SUMMARY.md 📝 Documentation +33/-0

Phase 8 Plan 03 README Rewrite Summary Documentation

• Created comprehensive summary document for Phase 8 Plan 03 (README Rewrite)
• Documents accomplishments including README contract tests, automation-first ordering, and
 credential-role clarity
• Specifies key files modified (README.md, .env.example) and created (tests/test_readme.py)
• Outlines key decisions on documentation structure and configuration surface alignment

.planning/phases/08-github-action-readme/08-03-SUMMARY.md


30. .env.example 📝 Documentation +20/-9

Environment Configuration File Documentation and Structure

• Rewrote header comments to clarify local CLI/runtime configuration purpose and workflow secret
 separation
• Expanded documentation with explicit warnings against adding workflow-only tokens to .env
• Reorganized variables with descriptive comments for each section (GitHub, Anthropic, output,
 confidence)
• Changed future-phase comments to active variable declarations with current model names and
 defaults

.env.example


31. .planning/phases/08-github-action-readme/08-01-SUMMARY.md 📝 Documentation +31/-0

Phase 8 Plan 01 Action State Helper Summary Documentation

• Created summary document for Phase 8 Plan 01 (Action State Helper)
• Documents implementation of decide_action_run(...) for merged-event and manual-dispatch paths
• Specifies key files created (src/github_pr_kb/action_state.py, tests/test_action_state.py)
• Outlines key decisions on stdlib-only Python helper, timestamp normalization, and monotonic cursor
 handling

.planning/phases/08-github-action-readme/08-01-SUMMARY.md


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Apr 11, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX Issues (0)

Grey Divider


Action required

1. Manual dispatch skips incorrectly🐞
Description
In workflow_dispatch runs, the workflow derives latest_merged_at from only the first 100 closed PRs
sorted by updated time; if none of those are merged, latest_merged_at is empty and not passed to
action_state, which then returns should_run=false and the workflow skips even when a manual backfill
(since) was requested. This can prevent recovery/backfill unless force=true in repos where merged
PRs exist but aren’t present in that first page of results.
Code

.github/workflows/github-pr-kb.yml[R125-160]

+      - name: Find latest merged PR updated_at for manual runs
+        id: latest-merged
+        if: ${{ github.event_name == 'workflow_dispatch' }}
+        shell: bash
+        env:
+          GH_TOKEN: ${{ steps.app-token.outputs.token || env.KB_VARIABLES_TOKEN }}
+        run: |
+          set -euo pipefail
+          latest_merged_at="$(
+            gh api "/repos/${GITHUB_REPOSITORY}/pulls?state=closed&sort=updated&direction=desc&per_page=100" \
+              --jq 'map(select(.merged_at != null))[0].updated_at // ""'
+          )"
+          echo "value=${latest_merged_at}" >> "$GITHUB_OUTPUT"
+
+      - name: Decide whether to run the pipeline
+        id: decision
+        shell: bash
+        run: |
+          set -euo pipefail
+          cmd=(uv run --project .github-pr-kb-tool python -m github_pr_kb.action_state --event-name "${GITHUB_EVENT_NAME}")
+          if [ -n "${{ steps.stored-cursor.outputs.value }}" ]; then
+            cmd+=(--stored-cursor "${{ steps.stored-cursor.outputs.value }}")
+          fi
+          if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then
+            cmd+=(--merged --event-updated-at "${{ github.event.pull_request.updated_at }}")
+          else
+            if [ -n "${{ steps.latest-merged.outputs.value }}" ]; then
+              cmd+=(--latest-merged-at "${{ steps.latest-merged.outputs.value }}")
+            fi
+            if [ -n "${{ github.event.inputs.since }}" ]; then
+              cmd+=(--manual-since "${{ github.event.inputs.since }}")
+            fi
+            if [ "${{ github.event.inputs.force }}" = "true" ]; then
+              cmd+=(--force)
+            fi
+          fi
Evidence
The workflow’s manual-run “latest merged” query is capped at per_page=100 and filters merged PRs
client-side; when that filtered set is empty it emits "" and the workflow omits --latest-merged-at.
The action_state helper treats latest_merged_at as required for non-forced workflow_dispatch
decisions (latest None => should_run False), so this query limitation can incorrectly suppress
manual runs.

.github/workflows/github-pr-kb.yml[125-137]
.github/workflows/github-pr-kb.yml[139-160]
src/github_pr_kb/action_state.py[112-145]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The workflow_dispatch path can skip incorrectly because `latest_merged_at` is computed from only the first 100 closed PRs (sorted by `updated`) and then filtered for `merged_at != null`. If that first page happens to contain no merged PRs, `--latest-merged-at` is omitted and `decide_action_run()` returns `should_run=false`, blocking manual recovery/backfill.
### Issue Context
This is purely a workflow data-fetch problem: the helper requires `latest_merged_at` for the non-forced manual decision, but the workflow’s current GitHub API query can fail to find a merged PR even when one exists.
### Fix Focus Areas
- .github/workflows/github-pr-kb.yml[125-160]
### Suggested change
Replace the current pulls-list query with a query that reliably returns the latest merged PR, e.g. using the Search API:
- `gh api "/search/issues?q=repo:${GITHUB_REPOSITORY}+is:pr+is:merged&sort=updated&order=desc&per_page=1" --jq '.items[0].updated_at // ""'`
(Alternatively, paginate `/pulls?...per_page=100&page=N` until a merged PR is found, but Search is simpler and deterministic.)
Also consider always passing `--latest-merged-at` (even as empty) and/or updating the helper contract only if you intentionally want manual runs to proceed with `manual_since` even when `latest_merged_at` cannot be determined.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Bad cursor breaks persistence🐞
Description
The cursor persistence step parses the existing repository variable with datetime.fromisoformat
without validation, so a manually repaired/edited KB_LAST_SUCCESSFUL_CURSOR value can crash the job
after extract/classify/generate. This turns a recoverable state issue into a late-pipeline failure
and blocks cursor repair via the workflow itself.
Code

.github/workflows/github-pr-kb.yml[R287-308]

+          endpoint="/repos/${GITHUB_REPOSITORY}/actions/variables/${KB_VARIABLE_NAME}"
+          stderr_file="$(mktemp)"
+          set +e
+          fresh_cursor="$(gh api "${endpoint}" --jq '.value' 2>"${stderr_file}")"
+          status=$?
+          set -e
+          if [ "${status}" -eq 0 ]; then
+            variable_exists="true"
+          elif grep -q "404" "${stderr_file}"; then
+            fresh_cursor=""
+            variable_exists="false"
+          else
+            cat "${stderr_file}" >&2
+            exit "${status}"
+          fi
+          rm -f "${stderr_file}"
+          persisted_cursor="$(python -c "from datetime import datetime, timezone; import sys; values = [datetime.fromisoformat(raw.replace('Z', '+00:00')).astimezone(timezone.utc) for raw in sys.argv[1:] if raw]; print(max(values).isoformat().replace('+00:00', 'Z') if values else '')" "${fresh_cursor}" "${candidate_cursor}")"
+          if [ "${variable_exists}" = "true" ]; then
+            gh api --method PATCH "${endpoint}" -f name="${KB_VARIABLE_NAME}" -f value="${persisted_cursor}" >/dev/null
+          else
+            gh api --method POST "/repos/${GITHUB_REPOSITORY}/actions/variables" -f name="${KB_VARIABLE_NAME}" -f value="${persisted_cursor}" >/dev/null
+          fi
Evidence
The workflow computes persisted_cursor by applying datetime.fromisoformat() to both the freshly-read
variable value and the candidate cursor, with no error handling; any non-ISO value in the existing
variable will raise and fail the step. The repo’s own risk documentation explicitly calls out
manually repairing the cursor variable as a contingency, meaning non-ideal values are a realistic
operational scenario to tolerate.

.github/workflows/github-pr-kb.yml[287-308]
.planning/phases/08-github-action-readme/08-02-RISK-REVIEW.md[61-66]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`Persist KB_LAST_SUCCESSFUL_CURSOR` assumes the stored variable is always a valid ISO-8601 timestamp. If maintainers manually repair/reset the variable (explicitly called out in repo risk docs) and make a formatting mistake, the `python -c datetime.fromisoformat(...)` expression will raise and fail the workflow late.
### Issue Context
The stored cursor is mutable repository state outside git; defensive parsing improves reliability and makes recovery easier.
### Fix Focus Areas
- .github/workflows/github-pr-kb.yml[287-308]
### Suggested change
Replace the one-liner with a small inline python script that:
- attempts to parse each input cursor
- ignores unparsable values (or fails with a clear error before doing expensive work)
- enforces timezone presence
- emits the max of the valid parsed values
Example approach:

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment thread .github/workflows/github-pr-kb.yml
Comment thread src/github_pr_kb/action_state.py Outdated


def decide_action_run(
*,

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

What's *,? What is it used for and why?

Comment thread tests/test_readme.py Outdated

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

What's the point in having tests for a README.md file? I've never seen such tests before.

Galzi1 and others added 2 commits April 11, 2026 11:07
- Use Search API for reliable merged-PR lookup in workflow_dispatch
  (fixes potential skip when first 100 closed PRs have no merges)
- Add comment explaining keyword-only (*,) syntax in action_state.py
- Remove test_readme.py (README structural tests deemed unnecessary)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace fragile one-liner with inline Python that catches ValueError/TypeError
on malformed KB_LAST_SUCCESSFUL_CURSOR values, emits a GitHub Actions warning,
and continues with any valid cursor. Prevents late-pipeline crash when cursor
is manually repaired with a formatting mistake.

Addresses Qodo review: 'Bad cursor breaks persistence'

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Galzi1 and others added 4 commits April 11, 2026 11:39
- New test_e2e_pipeline.py runs extract -> classify -> generate
  against Galzi1/github-pr-kb-demo with real API keys
- 9 assertions covering cache files, classification, KB articles,
  frontmatter, manifest, INDEX.md, and category structure
- Gated: requires RUN_INTEGRATION_TESTS=1 + real tokens; skipped
  in unit test runs (marked @pytest.mark.e2e)
- New e2e-pipeline CI job runs only on pushes to main (cost guard)
- Uses same pinned actions (checkout, setup-uv) as existing jobs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ntmatter

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Galzi1
Galzi1 merged commit 23765f0 into main Apr 11, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant