-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add GitHub hierarchy cache sync #179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| schema: spec-driven | ||
| created: 2026-04-09 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| # CHANGE VALIDATION | ||
|
|
||
| - Change: `governance-03-github-hierarchy-cache` | ||
| - Date: 2026-04-09 | ||
| - Command: `openspec validate governance-03-github-hierarchy-cache --strict` | ||
| - Result: PASS | ||
|
|
||
| ## Notes | ||
|
|
||
| - The new capability `github-hierarchy-cache` validates as a net-new spec delta. | ||
| - The modified capability `backlog-sync` remains aligned with the existing spec folder name. | ||
| - The change is apply-ready from an OpenSpec artifact perspective. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| # TDD Evidence | ||
|
|
||
| ## Failing-before implementation | ||
|
|
||
| - Timestamp: `2026-04-09T21:03:37+02:00` | ||
| - Command: `python3 -m pytest tests/unit/scripts/test_sync_github_hierarchy_cache.py -q` | ||
| - Result: FAIL | ||
| - Summary: All three tests failed with `FileNotFoundError` because `scripts/sync_github_hierarchy_cache.py` did not exist yet. | ||
|
|
||
| ## Failing-before path relocation refinement | ||
|
|
||
| - Timestamp: `2026-04-09T21:17:04+02:00` | ||
| - Command: `python3 -m pytest tests/unit/scripts/test_sync_github_hierarchy_cache.py -q` | ||
| - Result: FAIL | ||
| - Summary: The new default-path test failed because the script still targeted `openspec/GITHUB_HIERARCHY_CACHE.md` instead of ignored `.specfact/backlog/` storage. | ||
|
|
||
| ## Passing-after implementation | ||
|
|
||
| - Timestamp: `2026-04-09T21:17:35+02:00` | ||
| - Command: `python3 -m pytest tests/unit/scripts/test_sync_github_hierarchy_cache.py -q` | ||
| - Result: PASS | ||
| - Summary: All five script tests passed after moving the cache into ignored `.specfact/backlog/` storage and keeping the no-op fingerprint path intact. | ||
|
|
||
| ## Additional verification | ||
|
|
||
| - `python3 -m py_compile scripts/sync_github_hierarchy_cache.py` → PASS | ||
| - `python3 scripts/sync_github_hierarchy_cache.py --force` → generated `.specfact/backlog/github_hierarchy_cache.md` | ||
| - Second `python3 scripts/sync_github_hierarchy_cache.py` run → `GitHub hierarchy cache unchanged (13 issues).` | ||
|
|
||
| ## Final scoped quality gates | ||
|
|
||
| Full gate order (per `AGENTS.md` / `CLAUDE.md`). Run from repo root before merge; record PASS/FAIL after each step: | ||
|
|
||
| 1. `hatch run format` → PASS | ||
| 2. `hatch run type-check` → PASS | ||
| 3. `hatch run lint` → PASS | ||
| 4. `hatch run yaml-lint` → PASS | ||
| 5. `hatch run verify-modules-signature --require-signature --payload-from-filesystem --enforce-version-bump` → PASS | ||
| 6. `hatch run contract-test` → PASS | ||
| 7. `hatch run smart-test` → PASS | ||
| 8. `hatch run test` → PASS | ||
| 9. `hatch run specfact code review run --json --out .specfact/code-review.json` → PASS (`overall_verdict` PASS, `ci_exit_code` 0) | ||
|
|
||
| **Scoped exception:** None for this change; the list above is the required sequence. If CI or policy later narrows scope for a hotfix, update this block with an explicit rationale, approver, and approval id/date instead of omitting gates. | ||
|
|
||
| ### `.specfact/code-review.json` (this change) | ||
|
|
||
| - Last refresh: `2026-04-09T21:05:38Z` (UTC), command: `hatch run specfact code review run --json --out .specfact/code-review.json --scope changed` | ||
| - Outcome: PASS. Any low-severity DRY hints on icontract precondition helpers are documented under **Code review note** in `proposal.md` (accepted; do not merge predicates in ways that break icontract binding). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| # Context | ||
|
|
||
| `specfact-cli-modules` now carries its own GitHub planning hierarchy, but parent Feature/Epic resolution is still manual and repeated. The goal is to make hierarchy lookup local and deterministic in the modules repo the same way it will be in core: a generated markdown inventory under ignored `.specfact/backlog/` becomes the first lookup surface, and the sync script only performs a full refresh when the Epic/Feature hierarchy changed. | ||
|
|
||
| This is a governance/runtime support change rather than a bundle feature. The output should stay self-contained in this repo and should not depend on the core repo’s cache file. | ||
|
|
||
| ## Goals / Non-Goals | ||
|
|
||
| **Goals:** | ||
|
|
||
| - Generate a deterministic markdown cache of Epic and Feature issues for this repository. | ||
| - Include enough metadata for issue-parenting work without another GitHub lookup: issue number, title, short summary, labels, parent/child relationships, and issue URLs. | ||
| - Make the sync fast on no-op runs by using a small fingerprint/state check before regenerating markdown. | ||
| - Update repo guidance so contributors use the cache first and rerun sync only when needed. | ||
|
|
||
| **Non-Goals:** | ||
|
|
||
| - Replacing GitHub as the source of truth for modules-side hierarchy. | ||
| - Caching all issue types or full issue bodies. | ||
| - Sharing one cache file across both repos. | ||
| - Adding runtime coupling from bundle packages to GitHub sync logic. | ||
|
|
||
| ## Decisions | ||
|
|
||
| ### Reuse the same script contract as core, but keep files repo-local and ephemeral | ||
|
|
||
| The modules repo will implement the same cache contract as the core repo: sync script, state file, and deterministic markdown output. The generated files live under `.specfact/backlog/` so they remain local, ignored, and easy to regenerate. | ||
|
|
||
| Alternative considered: | ||
|
|
||
| - Import the core script from `specfact-cli`: rejected because governance tooling should work from this repo without special cross-repo bootstrapping. | ||
|
|
||
| ### Use `gh api graphql` for hierarchy metadata | ||
|
|
||
| The script will use `gh api graphql` to retrieve issue type, labels, relationships, and summary fields in a compact way. This keeps the implementation aligned with the core repo and avoids bespoke HTML or REST stitching. | ||
|
|
||
| Alternative considered: | ||
|
|
||
| - `gh issue view/list` fan-out calls: too many calls and weaker relationship support. | ||
|
|
||
| ### Split fingerprint detection from markdown rendering | ||
|
|
||
| The script will compute a fingerprint from Epic/Feature identity plus relevant change signals, compare it with a local state file, and skip markdown regeneration when nothing changed. When the fingerprint differs, it will fetch full data and rewrite the cache deterministically. | ||
|
|
||
| Alternative considered: | ||
|
|
||
| - Always rewrite the cache: simpler, but slower and noisier for routine use. | ||
|
|
||
| ## Risks / Trade-offs | ||
|
|
||
| - [Core/modules drift] → Keep file names, output structure, and tests closely aligned across both repos. | ||
| - [GitHub metadata gaps] → Normalize missing parents, children, and summaries instead of failing on absent optional fields. | ||
| - [Users forget to refresh] → Make rerun conditions explicit in `AGENTS.md` and keep the no-op path cheap. | ||
|
|
||
| ## Migration Plan | ||
|
|
||
| 1. Add the sync script, state handling, markdown renderer, and tests in this repo. | ||
| 2. Generate the initial modules-side cache file under ignored `.specfact/backlog/`. | ||
| 3. Update `AGENTS.md` with cache-first GitHub parenting guidance. | ||
| 4. Run verification and keep the paired core change aligned before implementation closes. | ||
|
|
||
| Rollback removes the script, cache, state file, and governance references without affecting bundle runtime code. | ||
|
|
||
| ## Open Questions | ||
|
|
||
| - Whether a future follow-up should surface the cache in published docs, or keep it strictly as a maintainer artifact. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # Governance: GitHub hierarchy cache (specfact-cli-modules) | ||
|
|
||
| ## Why | ||
|
|
||
| The modules repository now has its own Epic and Feature hierarchy, but contributors still have to query GitHub directly to rediscover parent Features and Epics before syncing OpenSpec changes. That creates unnecessary API traffic and makes cross-repo governance slower and less deterministic than it should be. | ||
|
|
||
| ## What Changes | ||
|
|
||
| - Add a deterministic repo-local hierarchy cache generator for `specfact-cli-modules` Epic and Feature issues. | ||
| - Persist a repo-local markdown hierarchy cache at `.specfact/backlog/github_hierarchy_cache.md` (ignored; not committed) with issue number, title, brief summary, labels, and hierarchy relationships, plus a companion fingerprint/state file `.specfact/backlog/github_hierarchy_cache_state.json` so the sync can exit quickly when Epic and Feature metadata has not changed. | ||
| - Update governance instructions in `AGENTS.md` for modules-side GitHub issue setup to consult the cache first and rerun sync only when needed. | ||
| - Keep the modules-side cache behavior aligned with the paired core change so both repos expose the same planning lookup pattern. | ||
|
|
||
| ## Capabilities | ||
|
|
||
| ### New Capabilities | ||
|
|
||
| - `github-hierarchy-cache`: Deterministic synchronization of GitHub Epic and Feature hierarchy metadata into a repo-local OpenSpec markdown cache for low-cost parent and planning lookups. | ||
|
|
||
| ### Modified Capabilities | ||
|
|
||
| - `backlog-sync`: Modules-side backlog and change-sync workflows must be able to resolve current Epic and Feature planning metadata from the repo-local cache before performing manual GitHub lookups. | ||
|
|
||
| ## Impact | ||
|
|
||
| - Affected code: new script and tests under `scripts/` and `tests/`, plus governance guidance in `AGENTS.md`. | ||
| - Affected workflow: OpenSpec change creation and modules-side GitHub issue parenting become cache-first instead of lookup-first. | ||
| - Cross-repo impact: this change must stay aligned with `specfact-cli` so both repos use the same hierarchy-cache operating model. | ||
|
|
||
| ## Source Tracking | ||
|
|
||
| - GitHub Issue: [#178](https://github.com/nold-ai/specfact-cli-modules/issues/178) | ||
| - Parent Feature: [#163](https://github.com/nold-ai/specfact-cli-modules/issues/163) | ||
| - Paired core (specfact-cli): `governance-02-github-hierarchy-cache` — tracked in `specfact-cli` `openspec/CHANGE_ORDER.md` with [specfact-cli#491](https://github.com/nold-ai/specfact-cli/issues/491) (distinct from the older `governance-02-exception-management` / `#248` row in the same file). | ||
|
|
||
| ## Code review note (SpecFact dogfood) | ||
|
|
||
| Icontract `@require` preconditions on `fetch_hierarchy_issues`, `render_cache_markdown`, and `sync_cache` intentionally use small, similarly shaped predicates (each checks one string field). The code-review module may emit low-severity DRY / duplicate-shape hints for those helpers; that is accepted here because collapsing them would break icontract’s per-parameter argument binding (e.g. `**kwargs` predicates are not supported the same way). | ||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,49 @@ | ||||||||||
| ## MODIFIED Requirements | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a top-level heading to clear markdownlint MD041. Line 1 starts at H2; add a single H1 above it to satisfy first-line-heading. Suggested markdown fix+# Backlog Sync Spec Delta
+
## MODIFIED Requirements📝 Committable suggestion
Suggested change
🧰 Tools🪛 markdownlint-cli2 (0.22.0)[warning] 1-1: First line in a file should be a top-level heading (MD041, first-line-heading, first-line-h1) 🤖 Prompt for AI Agents |
||||||||||
|
|
||||||||||
| ### Requirement: Restore backlog sync command functionality | ||||||||||
| The system SHALL provide `specfact backlog sync` command for bidirectional backlog synchronization, and related governance workflows SHALL be able to resolve current Epic and Feature planning metadata from the repo-local hierarchy cache before performing manual GitHub lookups. | ||||||||||
|
|
||||||||||
| #### Scenario: Sync from OpenSpec to backlog | ||||||||||
|
|
||||||||||
| - **WHEN** the user runs `specfact backlog sync --adapter github --project-id <repo>` | ||||||||||
| - **THEN** OpenSpec changes are exported to GitHub issues | ||||||||||
| - **AND** state mapping preserves status semantics | ||||||||||
|
|
||||||||||
| #### Scenario: Bidirectional sync with cross-adapter | ||||||||||
| - **WHEN** the user runs sync with cross-adapter configuration | ||||||||||
| - **THEN** state is mapped between adapters using canonical status | ||||||||||
| - **AND** lossless round-trip preserves content | ||||||||||
|
|
||||||||||
| #### Scenario: Sync with bundle integration | ||||||||||
| - **WHEN** sync is run within an OpenSpec bundle context | ||||||||||
| - **THEN** synced items update bundle state and source tracking | ||||||||||
|
|
||||||||||
| #### Scenario: Ceremony alias works | ||||||||||
| - **WHEN** the user runs `specfact backlog ceremony sync` | ||||||||||
| - **THEN** the command forwards to `specfact backlog sync` | ||||||||||
|
|
||||||||||
| #### Scenario: Cache-first hierarchy lookup for parent issue assignment | ||||||||||
| - **GIVEN** a contributor needs a parent Feature or Epic while preparing GitHub sync metadata | ||||||||||
| - **WHEN** the local hierarchy cache is present and current | ||||||||||
| - **THEN** the contributor can resolve the parent relationship from the cache without an additional GitHub lookup | ||||||||||
| - **AND** the sync script is rerun only when the cache is stale or missing | ||||||||||
|
|
||||||||||
| ### Requirement: Backlog sync checks for existing external issue mappings before creation | ||||||||||
| The backlog sync system SHALL check for existing issue mappings from external tools (including spec-kit extensions) before creating new backlog issues, to prevent duplicates. | ||||||||||
|
|
||||||||||
| #### Scenario: Backlog sync with spec-kit extension mappings available | ||||||||||
|
|
||||||||||
| - **GIVEN** a project with both SpecFact backlog sync and spec-kit backlog extensions active | ||||||||||
| - **AND** `SpecKitBacklogSync.detect_issue_mappings()` has returned mappings for some tasks | ||||||||||
| - **WHEN** `specfact backlog sync` runs for the project | ||||||||||
| - **THEN** for each task, the sync checks imported issue mappings first | ||||||||||
| - **AND** skips creation for tasks with existing mappings | ||||||||||
| - **AND** creates new issues only for unmapped tasks | ||||||||||
| - **AND** the sync summary reports both skipped (already-mapped) and newly-created issues | ||||||||||
|
|
||||||||||
| #### Scenario: Backlog sync without spec-kit extensions | ||||||||||
|
|
||||||||||
| - **GIVEN** a project without spec-kit or without backlog extensions | ||||||||||
| - **WHEN** `specfact backlog sync` runs | ||||||||||
| - **THEN** the sync creates issues for all tasks as before (no behavior change) | ||||||||||
| - **AND** no spec-kit extension detection is attempted | ||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # ADDED Requirements | ||
|
|
||
| ## Requirement: Repository hierarchy cache sync | ||
|
|
||
|
djm81 marked this conversation as resolved.
|
||
| The repository SHALL provide a deterministic sync mechanism that retrieves GitHub Epic and Feature issues for the current repository and writes a local hierarchy cache under ignored `.specfact/backlog/`. | ||
|
|
||
| ### Scenario: Generate hierarchy cache from GitHub metadata | ||
|
|
||
| - **WHEN** the user runs the hierarchy cache sync script for the repository | ||
| - **THEN** the script retrieves GitHub issues whose Type is `Epic` or `Feature` | ||
| - **AND** writes a markdown cache under ignored `.specfact/backlog/` with each issue's number, title, URL, short summary, labels, and hierarchy relationships | ||
| - **AND** the output ordering is deterministic across repeated runs with unchanged source data | ||
|
|
||
| ### Scenario: Fast exit on unchanged hierarchy state | ||
|
|
||
| - **WHEN** the script detects that the current Epic and Feature hierarchy fingerprint matches the last synced fingerprint | ||
| - **THEN** it exits successfully without regenerating the markdown cache | ||
| - **AND** it reports that no hierarchy update was required | ||
|
|
||
| ## Requirement: Modules governance must use cache-first hierarchy lookup | ||
|
|
||
| Repository governance instructions SHALL direct contributors and agents to consult the local hierarchy cache before performing manual GitHub lookups for Epic or Feature parenting. | ||
|
|
||
| ### Scenario: Cache-first governance guidance | ||
|
|
||
| - **WHEN** a contributor reads `AGENTS.md` for GitHub issue setup guidance | ||
| - **THEN** the instructions tell them to consult the local hierarchy cache first | ||
| - **AND** the instructions define when the sync script must be rerun to refresh stale hierarchy metadata | ||
| - **AND** the instructions state that the cache is local ephemeral state and must not be committed | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| ## 1. Change setup and governance sync | ||
|
|
||
| - [x] 1.1 Create and sync the GitHub issue for `governance-03-github-hierarchy-cache`, attach it to the correct parent Feature, and update `openspec/CHANGE_ORDER.md` plus proposal source tracking. | ||
| - [x] 1.2 Validate the change artifacts and capture the validation report in `openspec/changes/governance-03-github-hierarchy-cache/CHANGE_VALIDATION.md`. | ||
|
|
||
| ## 2. Spec-first test setup | ||
|
|
||
| - [x] 2.1 Add or update tests for hierarchy fingerprinting, deterministic markdown rendering, and fast no-change exit behavior. | ||
| - [x] 2.2 Run the targeted test command, confirm it fails before implementation, and record the failing run in `openspec/changes/governance-03-github-hierarchy-cache/TDD_EVIDENCE.md`. | ||
|
|
||
| ## 3. Implementation | ||
|
|
||
| - [x] 3.1 Implement the repository-local GitHub hierarchy cache sync script and state file handling under `scripts/`. | ||
| - [x] 3.2 Generate the initial `.specfact/backlog/github_hierarchy_cache.md` output and ensure reruns remain deterministic without committing it. | ||
| - [x] 3.3 Update `AGENTS.md` so GitHub issue setup and parent lookup use the cache-first workflow. | ||
|
|
||
| ## 4. Verification | ||
|
|
||
| - [x] 4.1 Re-run the targeted tests and record the passing run in `openspec/changes/governance-03-github-hierarchy-cache/TDD_EVIDENCE.md`. | ||
| - [x] 4.2 Run the required repo quality gates for the touched scope, including code review JSON refresh if stale. |
Uh oh!
There was an error while loading. Please reload this page.