Skip to content

chore(vbrief): add issue reconciliation script and close obsoleted issues#357

Merged
MScottAdams merged 2 commits intophase2/vbrief-cutoverfrom
agent1/chore/322-issue-reconciliation
Apr 13, 2026
Merged

chore(vbrief): add issue reconciliation script and close obsoleted issues#357
MScottAdams merged 2 commits intophase2/vbrief-cutoverfrom
agent1/chore/322-issue-reconciliation

Conversation

@MScottAdams
Copy link
Copy Markdown
Collaborator

Closes #322

Summary

Post-cutover GitHub issue reconciliation (Story M, Phase 2 vBRIEF Architecture Cutover).

What changed

  1. scripts/reconcile_issues.py -- Reconciliation script that:

    • Reads all vBRIEF files in lifecycle folders (proposed/, pending/, active/, completed/, cancelled/)
    • Extracts github-issue references from
      eferences arrays (plan-level, item-level, nested subItems)
    • Fetches open GitHub issues via gh CLI
    • Reports: (a) linked issues (vBRIEF provenance), (b) unlinked issues (no vBRIEF), (c) vBRIEFs with no open issue
    • Supports JSON and Markdown output formats
    • Auto-detects repo from git remote
  2. tasks/reconcile.yml -- Registered as ask reconcile:issues (not wired to ask check)

  3. Obsoleted issue closure -- Closed fix: strengthen spec validation gate and rendered artifact freshness #115 (strengthen spec validation gate and rendered artifact freshness) with explanatory comment. Entire scope superseded by:

  4. tests/cli/test_reconcile_issues.py -- 25 tests covering reference extraction, issue number parsing, directory scanning, reconciliation logic, output formatting, and CLI integration

  5. CHANGELOG.md -- Entry under [Unreleased]

Pre-existing test failures (not introduced by this PR)

  • est_valid_scope_vbrief_passes -- vbrief_validate.py temp dir path issue (pre-existing)
  • est_see_also_links_resolve -- broken See also link in deft-directive-swarm/SKILL.md referencing old deft-review-cycle path (pre-existing from skill rename)

Checklist

  • Scope vBRIEF coverage checked (Story M tracked in RFC: vBRIEF-centric document model for Deft Directive #309 epic)
  • Feature branch (not direct to master)
  • ask check -- lint/mypy/tests pass for new code; 2 pre-existing failures unrelated to PR
  • CHANGELOG.md entry under [Unreleased]
  • New source files include corresponding test files
  • Conventional commit format

…sues (#322)

- Create scripts/reconcile_issues.py: scans all vBRIEF lifecycle folders
  for github-issue references, fetches open issues via gh CLI, produces
  structured reconciliation report (linked, unlinked, no-open-issue)
- Register as task reconcile:issues in tasks/reconcile.yml
- Close obsoleted issue #115 (spec validation gate + SPECIFICATION.md
  freshness -- entire scope superseded by vbrief_validate.py and
  SPECIFICATION.md deprecation redirect)
- Add 25 tests in tests/cli/test_reconcile_issues.py covering reference
  extraction, issue parsing, directory scanning, reconciliation logic,
  output formatting, and CLI integration
- Add CHANGELOG.md [Unreleased] entry

Part of #309 (Phase 2 vBRIEF Architecture Cutover)
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 13, 2026

Greptile Summary

Adds scripts/reconcile_issues.py — a vBRIEF-to-GitHub-issue reconciliation tool — along with a Taskfile task, 25 tests, and a CHANGELOG entry (Story M, Phase 2 vBRIEF cutover). Both P1 findings from the prior review (dead None guard on fetch_open_issues, silent 200-issue truncation) have been fully addressed in the follow-up fix commit. Remaining findings are minor P2 robustness items in the script.

Confidence Score: 5/5

Safe to merge — all prior P1 bugs resolved; only minor P2 robustness edge cases remain

Both flagged issues from the previous review cycle (None guard and silent truncation) are fully fixed. The two remaining comments are P2: detect_repo mis-parsing dotted repo names (visible failure mode, not silent data loss) and a TypeError risk on references: null in malformed vBRIEFs (unlikely in practice given framework-generated files). Neither blocks merge.

scripts/reconcile_issues.py — detect_repo regex and null-references robustness

Important Files Changed

Filename Overview
scripts/reconcile_issues.py Core reconciliation script; previous P1 bugs (dead None guard, silent truncation) fully fixed; two minor robustness gaps remain: detect_repo regex truncates dotted repo names, and references: null crashes scan uncaught
tests/cli/test_reconcile_issues.py Good coverage of core paths (extraction, parsing, reconcile logic, formatting, CLI); detect_repo and the fetch-failure code path in main() are untested
tasks/reconcile.yml Clean task definition; correctly uses USER_WORKING_DIR for vbrief path and passes CLI_ARGS through
Taskfile.yml Adds reconcile include with optional: true; no issues
CHANGELOG.md Unreleased entry added per convention; no issues

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A([task reconcile:issues]) --> B[scan_vbrief_dir\nvbrief/proposed,pending,\nactive,completed,cancelled]
    B --> C{parse each\n*.vbrief.json}
    C -->|github-issue refs| D[issue_to_vbriefs\nmap: num → files]
    C -->|skip non-github\nor malformed| C
    A --> E[detect_repo\ngit remote get-url]
    E --> F[fetch_open_issues\ngh issue list --limit 200]
    F -->|None on error| G([exit 1])
    F -->|list of dicts| H[reconcile]
    D --> H
    H --> I{classify each\nopen issue}
    I -->|in issue_to_vbriefs| J[linked]
    I -->|not in map| K[unlinked]
    H --> L{vBRIEF refs\nwith no open issue}
    L --> M[no_open_issue]
    J & K & M --> N[format_json\nor format_markdown]
    N --> O([stdout])
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: scripts/reconcile_issues.py
Line: 388-390

Comment:
**`detect_repo` strips repo names at the first dot**

The second capture group `([^/.]+)` excludes `.` to drop `.git`, but also stops at the first `.` in the repo name itself. For a remote URL like `git@github.com:owner/my.service.git`, this returns `owner/my` instead of `owner/my.service`. The failure mode is either a `gh` CLI error (detectable) or, in the unlikely case that `owner/my` exists, a silent reconciliation run against the wrong repository.

Strip the `.git` suffix explicitly instead of relying on the character class:

```suggestion
    m = re.search(r"github\.com[:/]([^/]+)/([^/]+?)(?:\.git)?$", url.strip())
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: scripts/reconcile_issues.py
Line: 62-75

Comment:
**`references: null` propagates uncaught `TypeError` and crashes the scan**

`plan.get("references", [])` returns the stored `None` when the key is present with a `null` value — the default `[]` is only substituted when the key is *absent*. Iterating over `None` raises `TypeError`. The same pattern appears in `_walk_items` on the `"references"`, `"subItems"`, and `"items"` keys. Because `extract_references_from_vbrief` is called outside the `try/except (JSONDecodeError, OSError)` block in `scan_vbrief_dir`, any `TypeError` propagates uncaught, crashing the entire script rather than silently skipping the offending file.

Use `or []` to coerce `None` to an empty sequence:

```python
for ref in (plan.get("references") or []):
    ...

# and in _walk_items:
for ref in (item.get("references") or []):
    ...
_walk_items(item.get("subItems") or [])
_walk_items(item.get("items") or [])
```

Alternatively, widen the `try/except` in `scan_vbrief_dir` to cover the `extract_references_from_vbrief(data)` call.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "fix: address Greptile review findings (b..." | Re-trigger Greptile

Comment thread scripts/reconcile_issues.py
Comment thread scripts/reconcile_issues.py
- P1: Change fetch_open_issues return type to list[dict] | None;
  return None on all error paths so the dead None guard in main()
  correctly exits with code 1 on gh CLI failures
- P2: Add warning when fetched issue count hits the limit (200),
  signaling potentially incomplete data
- P2: Fix test count in CHANGELOG entry (22 -> 25)
@MScottAdams MScottAdams merged commit 5cd2900 into phase2/vbrief-cutover Apr 13, 2026
2 of 3 checks passed
@MScottAdams MScottAdams deleted the agent1/chore/322-issue-reconciliation branch April 13, 2026 23:56
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