Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ Before changing code, verify an active OpenSpec change explicitly covers the req
- If missing scope: create or extend a change first (`openspec` workflow)
- Follow strict TDD order: spec delta -> failing tests -> implementation -> passing tests -> quality gates
- Record failing/passing evidence in `openspec/changes/<change-id>/TDD_EVIDENCE.md`
- For GitHub issue setup, parent linking, or blocker lookup, consult `.specfact/backlog/github_hierarchy_cache.md` first. This cache is ephemeral local state and MUST NOT be committed.
- Rerun `python scripts/sync_github_hierarchy_cache.py` whenever the cache is missing or stale, and recreate it as part of OpenSpec and GitHub issue work.

### OpenSpec archive rule (hard requirement)

Expand Down
2 changes: 2 additions & 0 deletions openspec/CHANGE_ORDER.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
| Module | Order | Change folder | GitHub # | Blocked by |
|--------|-------|---------------|----------|------------|
| sync | 01 | sync-01-unified-kernel | [#157](https://github.com/nold-ai/specfact-cli-modules/issues/157) | Parent Feature: [#147](https://github.com/nold-ai/specfact-cli-modules/issues/147); preview/apply safety baseline from `specfact-cli#177` |
| project-runtime | 01 | project-runtime-01-safe-artifact-write-policy | [#177](https://github.com/nold-ai/specfact-cli-modules/issues/177) | Parent Feature: [#161](https://github.com/nold-ai/specfact-cli-modules/issues/161); paired core change [specfact-cli#490](https://github.com/nold-ai/specfact-cli/issues/490); related bug [specfact-cli#487](https://github.com/nold-ai/specfact-cli/issues/487) |

### Cross-layer runtime follow-ups

Expand All @@ -74,6 +75,7 @@ These changes are the modules-side runtime companions to split core governance a
|--------|-------|---------------|----------|------------|
| governance | 01 | governance-01-evidence-output | [#169](https://github.com/nold-ai/specfact-cli-modules/issues/169) | Parent Feature: [#163](https://github.com/nold-ai/specfact-cli-modules/issues/163); core counterpart `specfact-cli#247`; validation runtime `#171` |
| governance | 02 | governance-02-exception-management | [#167](https://github.com/nold-ai/specfact-cli-modules/issues/167) | Parent Feature: [#163](https://github.com/nold-ai/specfact-cli-modules/issues/163); core counterpart `specfact-cli#248`; policy runtime `#158` |
| governance | 03 | governance-03-github-hierarchy-cache | [#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 `governance-02-github-hierarchy-cache` [specfact-cli#491](https://github.com/nold-ai/specfact-cli/issues/491) |
| validation | 02 | validation-02-full-chain-engine | [#171](https://github.com/nold-ai/specfact-cli-modules/issues/171) | Parent Feature: [#163](https://github.com/nold-ai/specfact-cli-modules/issues/163); core counterpart `specfact-cli#241`; runtime inputs from `#164` and `#165`; policy semantics from `#158` |

### Documentation restructure
Expand Down
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).
66 changes: 66 additions & 0 deletions openspec/changes/governance-03-github-hierarchy-cache/design.md
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.
38 changes: 38 additions & 0 deletions openspec/changes/governance-03-github-hierarchy-cache/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Governance: GitHub hierarchy cache (specfact-cli-modules)

## Why
Comment thread
djm81 marked this conversation as resolved.

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
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

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

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## MODIFIED Requirements
# Backlog Sync Spec Delta
## MODIFIED Requirements
🧰 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
Verify each finding against the current code and only fix it if needed.

In
`@openspec/changes/governance-03-github-hierarchy-cache/specs/backlog-sync/spec.md`
at line 1, The file currently begins with an H2 ("## MODIFIED Requirements")
which violates markdownlint MD041; add a single top-level H1 line above it (for
example "# Backlog Sync Requirements" or another appropriate concise title) so
the first line is an H1 and the existing H2 remains unchanged; update the
document header only (no other content changes) to satisfy MD041.


### 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

Comment thread
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
20 changes: 20 additions & 0 deletions openspec/changes/governance-03-github-hierarchy-cache/tasks.md
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.
Loading
Loading