Skip to content

fix(#705): paginate all open issues in pre-scribe backlog fetch - #708

Open
fullsend-ai-coder[bot] wants to merge 5 commits into
mainfrom
agent/705-paginate-backlog-issues
Open

fix(#705): paginate all open issues in pre-scribe backlog fetch#708
fullsend-ai-coder[bot] wants to merge 5 commits into
mainfrom
agent/705-paginate-backlog-issues

Conversation

@fullsend-ai-coder

Copy link
Copy Markdown
Contributor

Summary

  • Replace gh issue list --limit 1000 with gh api --paginate in scripts/pre-scribe.sh to fetch all open issues, eliminating the truncation that caused duplicate issue creation on repos with >1000 open issues
  • Add open_issue_total and backlog_truncated metadata fields to scribe-meta.json for backlog coverage observability
  • Add scripts/pre-scribe-test.sh with 7 tests covering pagination, PR filtering, body truncation, empty repos, null bodies, metadata fields, and label/milestone preservation

Context

The scribe agent's pre-script used gh issue list --limit 1000 which returns issues ordered by most recently updated. On repos with >1000 open issues (e.g., ~1,879 at time of failure), issues not updated recently fell out of the agent's matching context. The agent then filed duplicate new issues for topics that already had trackers — even when meeting notes acknowledged those existing issues.

The fix uses gh api --paginate with the REST API, which follows Link header pagination to fetch all pages. The REST /issues endpoint includes pull requests in the response, so the pipeline filters them with select(.pull_request == null) and maps html_urlurl for format compatibility.

Test plan

  • New pre-scribe-test.sh passes all 7 tests
  • Existing post-scribe-test.sh passes (one pre-existing failure due to missing bc in sandbox — unrelated)
  • Secret scan passes
  • Verify on a repo with >1000 open issues that all issues appear in backlog.json
  • Verify scribe-meta.json includes open_issue_total and backlog_truncated fields

Closes #705

Post-script verification

  • Branch is not main/master (agent/705-paginate-backlog-issues)
  • Secret scan passed (gitleaks — 91f61f3441baedf3f912c9afd4bd574c98793b96..HEAD)
  • PR body secret scan passed (gitleaks — no-git)

Replace `gh issue list --limit 1000` with `gh api --paginate` to
fetch all open issues regardless of repo size. The previous limit
caused the scribe agent to miss issues not updated recently on
repos with >1000 open issues, leading to duplicate issue creation.

The REST API `/issues` endpoint includes pull requests, so the
pipeline filters them with `select(.pull_request == null)` and
maps `html_url` to `url` to match the expected backlog format.

Add `open_issue_total` and `backlog_truncated` metadata fields to
`scribe-meta.json` for observability of backlog coverage.

Add `pre-scribe-test.sh` with tests covering pagination, PR
filtering, body truncation, empty repos, and metadata fields.

Note: pre-commit hooks could not run (network restrictions in
sandbox). shellcheck was not available. The post-script runs an
authoritative pre-commit on the runner.

Closes #705
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 6, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 3:12 PM UTC · Completed 3:27 PM UTC
Commit: b8b36ad · View workflow run →

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review

Findings

Medium

Low

  • [stale-docs] agents/scribe.md:36 — The agent prompt documents metadata as containing only cutoff_date and notes_url. The PR adds open_issue_total and backlog_truncated to scribe-meta.json, but the scribe agent prompt does not document these fields. The existing pattern omits other pre-existing fields too (repo, backlog_issues, etc.), so this is consistent — but if the agent should act on the new fields, the prompt needs updating.

  • [edge-case] scripts/pre-scribe.shREPO_OPEN_COUNT is fetched via a separate API call after the paginated issue fetch completes. If issues or PRs are created or closed between the two calls, PAGINATED_TOTAL and REPO_OPEN_COUNT may disagree. The code includes a TRUNCATION_TOLERANCE of 5 to absorb typical churn. Since backlog_truncated is advisory metadata with no downstream logic gating on it, the residual risk is limited to a potentially misleading metadata value.

Previous run

Review

Findings

Medium

Low

  • [stale-docs] agents/scribe.md:36 — The agent prompt documents metadata as containing only cutoff_date and notes_url. The PR adds open_issue_total and backlog_truncated to scribe-meta.json, but the scribe agent prompt does not document these fields. The existing pattern omits other pre-existing fields too (repo, backlog_issues, etc.), so this is consistent — but if the agent should act on the new fields, the prompt needs updating.

  • [edge-case] scripts/pre-scribe.shREPO_OPEN_COUNT is fetched via a separate API call after the paginated issue fetch completes. If issues or PRs are created or closed between the two calls, PAGINATED_TOTAL and REPO_OPEN_COUNT may disagree, potentially producing a false-positive backlog_truncated=true. Since this field is advisory metadata with no downstream logic gating on it, the impact is limited to a misleading metadata value.

  • [test-robustness] scripts/pre-scribe-test.shbuild_mock_gh uses sed -i with | delimiter to inject the fixture path. If the mktemp -d path contains |, substitution breaks. Standard Linux mktemp paths are safe, making this theoretical-only.

Previous run (2)

Review

Findings

Medium

Low

  • [stale-docs] agents/scribe.md:36 — The agent prompt documents metadata as containing only cutoff_date and notes_url. The PR adds open_issue_total and backlog_truncated to scribe-meta.json, but the scribe agent prompt does not document these fields. The existing pattern omits other pre-existing fields too (repo, backlog_issues, etc.), so this is consistent — but if the agent should act on the new fields, the prompt needs updating.

  • [edge-case] scripts/pre-scribe.sh:77 — The truncation detection computes OPEN_ISSUE_TOTAL=$((REPO_OPEN_COUNT - PR_COUNT)), but PR_COUNT comes from gh pr list --limit 100 (line 69), which caps at 100 open PRs. GitHub's open_issues_count includes all PRs. On repos with >100 open PRs, PR_COUNT under-counts, inflating OPEN_ISSUE_TOTAL and potentially producing a false-positive backlog_truncated=true.

  • [test-coverage-gap] scripts/pre-scribe-test.sh — Tests 6 and 6b verify the jq metadata template with hardcoded values but do not test the actual truncation detection logic — the bash arithmetic $((REPO_OPEN_COUNT - PR_COUNT)) and the comparison [[ ISSUE_COUNT -lt OPEN_ISSUE_TOTAL ]]. The core new feature (detecting a paginated fetch returned fewer issues than the repo reports) has no automated test coverage.

  • [test-robustness] scripts/pre-scribe-test.sh:53build_mock_gh uses sed -i with | delimiter to inject the fixture path. If the mktemp -d path contains |, substitution breaks. Standard Linux mktemp paths are safe, making this theoretical-only.

Previous run (3)

Review

Findings

Medium

Low

  • [incomplete-metadata-update] scripts/pre-scribe.sh:179backlog_truncated is hardcoded to false and open_issue_total is set to the same value as backlog_issues. Since --paginate fetches all issues, truncation cannot occur, making these values correct. However, neither field can ever carry a different value than its companion — the new fields add no dynamic runtime information beyond what backlog_issues already provides. See also: [scope-design-nuance] finding on this file.

  • [scope-design-nuance] scripts/pre-scribe.sh — If gh api --paginate silently fails partway (e.g., rate limit mid-pagination), backlog_truncated would still report false. A dynamic check (e.g., comparing fetched count against an API total) would more robustly fulfill the issue Scribe: backlog truncation (--limit 1000) causes duplicate new issues for stale open issues #705 acceptance criterion. See also: [incomplete-metadata-update] finding on this file.

  • [test-coverage-gap] scripts/pre-scribe-test.sh:54 — The run_backlog_fetch function duplicates the gh api/jq pipeline from pre-scribe.sh rather than sourcing the actual script. This is a reasonable trade-off given Drive credential requirements, but future pipeline changes in pre-scribe.sh require a parallel update in the test.

  • [test-robustness] scripts/pre-scribe-test.sh:43build_mock_gh escapes only forward slashes in the fixture path before Perl regex substitution. Characters special to Perl regex (., +, $) in mktemp paths could theoretically cause failures, though in practice Linux mktemp paths are safe.

  • [stale-docs] agents/scribe.md:36 — The agent prompt documents metadata as containing only cutoff_date and notes_url. The PR adds open_issue_total and backlog_truncated. The existing pattern omits other pre-existing fields too (repo, backlog_issues, etc.), so this is consistent — but if the agent should act on the new fields, the prompt needs updating.


Labels: PR modifies scribe agent pre-script (scripts/pre-scribe.sh) and adds scribe-specific tests

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment scribe-agent labels Aug 6, 2026
@ascerra

ascerra commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

/fs-fix

@fullsend-ai-coder

fullsend-ai-coder Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Finished Fix · ✅ Success · Started 1:13 PM UTC · Completed 1:22 PM UTC

Commit: b8b36ad · View workflow run →

- Fetch repo open_issues_count from GitHub API and compare against
  paginated issue count to dynamically set open_issue_total and
  backlog_truncated (addresses incomplete-metadata-update and
  scope-design-nuance findings)
- Replace perl -pi -e with sed -i using | delimiter in test mock to
  avoid regex metacharacter issues (addresses test-robustness finding)
- Add test_metadata_truncated test case for truncation=true scenario
- Update metadata test jq template to use separate open_total/truncated
  args matching the production template

Addresses review feedback on #708
@fullsend-ai-coder

Copy link
Copy Markdown
Contributor Author

🔧 Fix agent — iteration 1 (human-triggered)

Addressed 3 of 6 review findings with code fixes: made open_issue_total and backlog_truncated dynamic via repo API comparison, replaced fragile Perl regex substitution with sed in tests, and added a truncation=true test case. Disagreed with 3 findings: protected-path (informational), test-coverage-gap (acknowledged trade-off), stale-docs (protected path, consistent pattern).

Fixed (3):

  1. incomplete-metadata-update + scope-design-nuance: open_issue_total and backlog_truncated are hardcoded with no dynamic runtime information (scripts/pre-scribe.sh): Added gh api repos/{repo} call to fetch open_issues_count, computing OPEN_ISSUE_TOTAL (subtracting PR_COUNT for issue-only estimate) and BACKLOG_TRUNCATED dynamically by comparing fetched vs expected count. Updated both metadata jq templates to use these variables instead of hardcoded values. Falls back gracefully to fetched count if the API call fails.
  2. test-robustness: build_mock_gh escapes only forward slashes before Perl regex substitution (scripts/pre-scribe-test.sh): Replaced perl -pi -e with sed -i using | delimiter, eliminating the need for manual escaping entirely. File paths from mktemp never contain |, making the substitution safe against all regex metacharacters.
  3. metadata test template alignment (scripts/pre-scribe-test.sh): Updated test_metadata_fields to pass open_total and truncated as separate jq arguments matching the new production template. Added test_metadata_truncated test case verifying backlog_truncated=true when fetched count (950) diverges from API total (1879).

Disagreed (3):

  1. protected-path: PR modifies files under scripts/ protected path: This is an informational finding about the review process (human approval required for protected paths), not a code issue. No code change needed.
  2. test-coverage-gap: run_backlog_fetch duplicates the pipeline rather than sourcing the actual script: The reviewer acknowledges this is 'a reasonable trade-off given Drive credential requirements.' The full pre-scribe.sh requires Google Drive credentials and GitHub tokens that are unavailable in the test environment. The duplicated pipeline tests the actual jq filter expressions end-to-end, which is the critical correctness concern.
  3. stale-docs: agents/scribe.md documents metadata as containing only cutoff_date and notes_url: The agents/ path is protected and the reviewer notes 'The existing pattern omits other pre-existing fields too (repo, backlog_issues, etc.), so this is consistent.' The agent already has access to the full JSON; the prompt excerpt is intentionally minimal.

Tests: passed

Next steps:

  • /fs-review — request a re-review of the changes
  • /fs-fix <your instruction> — run another fix pass with specific guidance
  • Push commits directly — review re-runs automatically on push
    Updated by fullsend fix agent

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 9, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 1:23 PM UTC · Ended 1:35 PM UTC

Commit: 9007375 · View workflow run →

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 9, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 1:36 PM UTC · Completed 1:52 PM UTC

Commit: d66f6e4 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@ascerra

ascerra commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

/fs-fix

@fullsend-ai-coder

fullsend-ai-coder Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Finished Fix · ✅ Success · Started 2:01 PM UTC · Completed 2:09 PM UTC

Commit: d66f6e4 · View workflow run →

…pped PR_COUNT

Compare PAGINATED_TOTAL (all items including PRs from paginated response)
directly against REPO_OPEN_COUNT instead of subtracting PR_COUNT from
gh pr list --limit 100, which caps at 100 and produces false-positive
backlog_truncated=true on repos with >100 open PRs.

Save raw paginated response to count total items before filtering, then
derive OBSERVED_PR_COUNT from the difference. Update test pipeline to
mirror the two-step approach and add test_truncation_detection_logic
covering the bash arithmetic (including the >100 PRs edge case).

Addresses review feedback on #708
@fullsend-ai-coder

Copy link
Copy Markdown
Contributor Author

🔧 Fix agent — iteration 2 (human-triggered)

Fixed 2 of 5 review findings. The edge-case finding (PR_COUNT cap at 100 causing false-positive truncation) was the substantive bug — restructured truncation detection to compare paginated total directly against API count, eliminating the dependency on capped PR_COUNT. Added test coverage for the truncation detection bash logic with 5 test cases including the >100 PRs edge case. Disagreed with 3 findings: protected-path (informational), stale-docs (protected path, consistent pattern), test-robustness (theoretical only per reviewer).

Fixed (2):

  1. edge-case: PR_COUNT from gh pr list --limit 100 caps at 100, inflating OPEN_ISSUE_TOTAL (scripts/pre-scribe.sh): Replaced PR_COUNT-based truncation detection with PAGINATED_TOTAL comparison. Save raw paginated response to count all items (issues+PRs) before filtering, then compare directly against REPO_OPEN_COUNT. Derives OBSERVED_PR_COUNT from the actual paginated response instead of capped gh pr list output. Eliminates false-positive backlog_truncated=true on repos with >100 open PRs.
  2. test-coverage-gap: truncation detection logic has no automated test coverage (scripts/pre-scribe-test.sh): Added test_truncation_detection_logic with 5 cases covering: no truncation, truncation detected, >100 PRs (the edge case that motivated the production fix), API failure fallback, and zero PRs. Tests the actual bash arithmetic and comparison logic from pre-scribe.sh. Also updated run_backlog_fetch to mirror the new two-step production pipeline.

Disagreed (3):

  1. protected-path: PR modifies files under scripts/ protected path: Informational finding about the review process (human approval required for protected paths), not a code issue. No code change needed.
  2. stale-docs: agents/scribe.md documents metadata as containing only cutoff_date and notes_url: agents/ is a protected path. The reviewer notes the existing pattern omits other pre-existing fields too (repo, backlog_issues, etc.), making this consistent. The agent has access to the full JSON at runtime.
  3. test-robustness: build_mock_gh uses sed -i with | delimiter: The reviewer explicitly states this is 'theoretical-only' since standard Linux mktemp paths never contain |. The risk is zero in practice.

Tests: passed

Next steps:

  • /fs-review — request a re-review of the changes
  • /fs-fix <your instruction> — run another fix pass with specific guidance
  • Push commits directly — review re-runs automatically on push
    Updated by fullsend fix agent

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 9, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 2:10 PM UTC · Completed 2:24 PM UTC

Commit: a8ec1f8 · View workflow run →

@ascerra

ascerra commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

/fs-fix

@fullsend-ai-coder

fullsend-ai-coder Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Finished Fix · ✅ Success · Started 10:33 AM UTC · Completed 10:40 AM UTC

Commit: a8ec1f8 · View workflow run →

- Add TRUNCATION_TOLERANCE=5 to truncation detection to absorb small
  discrepancies from API timing between the paginated issue fetch and
  the repo metadata call, preventing false-positive backlog_truncated
- Replace sed -i placeholder substitution in build_mock_gh with a
  side-file approach — the mock reads the fixture path from .gh-fixture
  at runtime, safe regardless of temp path characters
- Add 3 test cases for tolerance boundary: within tolerance (3),
  at boundary (5), and above boundary (6)

Addresses review feedback on #708
@fullsend-ai-coder

Copy link
Copy Markdown
Contributor Author

🔧 Fix agent — iteration 3 (human-triggered)

Addressed 2 of 4 review findings. Fixed the API timing race condition in truncation detection by adding a 5-item tolerance margin, preventing false-positive backlog_truncated=true. Eliminated sed -i placeholder substitution in test mock with a side-file approach, handling any temp path characters safely. Added 3 boundary test cases. Disagreed with 2 findings: protected-path (informational) and stale-docs (protected path, consistent existing pattern).

Fixed (2):

  1. edge-case: REPO_OPEN_COUNT race condition with paginated fetch (scripts/pre-scribe.sh): Added TRUNCATION_TOLERANCE=5 to the truncation comparison. Instead of flagging truncation on any difference between PAGINATED_TOTAL and REPO_OPEN_COUNT, now computes SHORTFALL and only flags when the shortfall exceeds 5 items. This absorbs typical churn from issues or PRs created/closed between the two API calls, preventing false-positive backlog_truncated=true. Added explanatory comment documenting the race condition and tolerance rationale.
  2. test-robustness: build_mock_gh uses sed -i with | delimiter (scripts/pre-scribe-test.sh): Replaced sed -i placeholder substitution with a side-file approach. The fixture path is written to .gh-fixture via printf, and the mock reads it at runtime using $(cat $(dirname $0)/.gh-fixture). This is safe regardless of characters in the mktemp path. Also added 3 new test cases (cases 6-8) for the truncation tolerance boundary: within tolerance (3 items, not truncated), at boundary (5 items, not truncated), and above boundary (6 items, truncated).

Disagreed (2):

  1. protected-path: PR modifies files under scripts/ protected path: Informational finding about the review process. Human approval is required for protected-path changes. This is not a code issue that the fix agent can address. The PR is linked to issue Scribe: backlog truncation (--limit 1000) causes duplicate new issues for stale open issues #705 and the rationale is documented in the PR description.
  2. stale-docs: agents/scribe.md does not document new metadata fields: agents/ is a protected path. The reviewer notes the existing pattern already omits other pre-existing fields (repo, backlog_issues, etc.), making this consistent. The agent reads the full JSON at runtime, so the metadata fields are available without prompt documentation.

Tests: passed

Strategy change: Iteration 3: implemented concrete code fixes for both remaining actionable findings (tolerance margin for edge-case, side-file for test-robustness) rather than disagreeing as in iteration 2.


Next steps:

  • /fs-review — request a re-review of the changes
  • /fs-fix <your instruction> — run another fix pass with specific guidance
  • Push commits directly — review re-runs automatically on push
    Updated by fullsend fix agent

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 10, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 10:41 AM UTC · Completed 10:55 AM UTC

Commit: 354297e · View workflow run →

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scribe: backlog truncation (--limit 1000) causes duplicate new issues for stale open issues

1 participant