Skip to content

Release dev → main: governance loading, hierarchy cache, agent rules/docs#183

Open
djm81 wants to merge 17 commits intomainfrom
dev
Open

Release dev → main: governance loading, hierarchy cache, agent rules/docs#183
djm81 wants to merge 17 commits intomainfrom
dev

Conversation

@djm81
Copy link
Copy Markdown
Contributor

@djm81 djm81 commented Apr 12, 2026

Summary

Promote dev to main after merging PR #182 (deterministic agent governance loading). This release train also includes PR #180 (project-runtime OpenSpec recovery) and PR #179 (GitHub hierarchy cache script and governance), plus follow-up fixes on the governance/pre-commit path.

Refs:

Scope

  • Bundle source changes under packages/
  • Registry/manifest changes (registry/index.json, packages/*/module-package.yaml)
  • CI/workflow changes (.github/workflows/*)
  • Documentation changes (docs/*, README.md, AGENTS.md)
  • Security/signing changes (scripts/sign-modules.py, scripts/verify-modules-signature.py)

Note: .github/copilot-instructions.md changed; workflow YAML under .github/workflows/ did not.

Bundle Impact

No bundle or registry changes in origin/main..origin/dev (no packages/ or registry/ diffs). Version lines below are unchanged for this promotion.

  • nold-ai/specfact-project: unchanged
  • nold-ai/specfact-backlog: unchanged
  • nold-ai/specfact-codebase: unchanged
  • nold-ai/specfact-spec: unchanged
  • nold-ai/specfact-govern: unchanged

Validation Evidence

Attach snippets or workflow run links after running the gates below on this branch (or cite green checks from the merged feature PRs).

Required local gates

  • hatch run format
  • hatch run type-check
  • hatch run lint
  • hatch run yaml-lint
  • hatch run check-bundle-imports
  • hatch run contract-test
  • hatch run smart-test (or hatch run test)

Signature + version integrity (required)

  • hatch run verify-modules-signature --require-signature --payload-from-filesystem --enforce-version-bump
  • Changed bundle versions were bumped before signing
  • Manifests re-signed after bundle content changes

No bundle content changed in this range; confirm signature gate still passes on dev before merge.

CI and Branch Protection

  • PR orchestrator jobs expected:
    • verify-module-signatures
    • quality (3.11)
    • quality (3.12)
    • quality (3.13)
  • Branch protection required checks are aligned with the above

Docs / Pages

  • Bundle/module docs updated in this repo (docs/)
  • Pages workflow impact reviewed (docs-pages.yml, if changed)
  • Cross-links from specfact-cli docs updated (if applicable)

Checklist

  • Self-review completed
  • No unrelated files or generated artifacts included
  • Backward-compatibility/rollout notes documented (if needed)

djm81 and others added 17 commits April 9, 2026 22:28
…rarchy-cache

feat: add GitHub hierarchy cache sync
Recovered openspec/changes/project-runtime-01-safe-artifact-write-policy/
from bd07b05 (removed in f174ed0 during review fixes). CHANGE_ORDER.md
already references this change and specfact-cli#490.

Made-with: Cursor
…-openspec

chore(openspec): restore project-runtime-01-safe-artifact-write-policy
Complete OpenSpec change governance-04-deterministic-agent-governance-loading:
- Compact AGENTS.md/CLAUDE.md bootstrap; Cursor/Copilot alias surfaces
- Canonical docs/agent-rules/ INDEX and domain rule files; docs nav
- validate_agent_rule_applies_when.py; pre-commit and hierarchy-cache hardening
- Unit tests for agent rules, applies_when validator, and cache script
- openspec/config.yaml and change artifacts (TDD_EVIDENCE, validation)

Refs: #181, #163, #178; nold-ai/specfact-cli#494
Made-with: Cursor
…tic-agent-governance-loading

feat(governance): deterministic agent governance loading (governance-04)
@djm81 djm81 self-assigned this Apr 12, 2026
@djm81 djm81 added enhancement New feature or request dependencies Pull requests that update a dependency file labels Apr 12, 2026
@djm81 djm81 moved this to In Progress in SpecFact CLI Apr 12, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 12, 2026

📝 Walkthrough

Pull Request Summary: Release dev → main (Governance, Hierarchy Cache, Agent Rules)

Overview

This PR promotes the dev branch to main incorporating three OpenSpec changes: governance-03-github-hierarchy-cache (archived, #178), governance-04-deterministic-agent-governance-loading (active, #181), and project-runtime-01-safe-artifact-write-policy (#177, core companion). No bundle versioning, registry updates, or module surface API changes are included; this is a governance and developer-experience release.

OpenSpec Scenario Coverage

  1. governance-03-github-hierarchy-cache (archived)

    • Introduces deterministic repo-local GitHub Epic/Feature hierarchy cache at .specfact/backlog/github_hierarchy_cache.md with state/fingerprint tracking
    • Implements scripts/sync_github_hierarchy_cache.py for cache-first issue parenting without repeated GitHub lookups
    • Includes specification updates to backlog-sync requiring cache-first hierarchy resolution
    • TDD evidence shows failing-first test discovery, passing contract/smart/quality-gate runs
  2. governance-04-deterministic-agent-governance-loading (in progress)

    • Establishes deterministic bootstrap model: compact AGENTS.mddocs/agent-rules/INDEX.md → applicability-matched rule files
    • Defines YAML frontmatter schema for rule governance (id, always_load, applies_when, priority, blocking, user_interaction_required, stop_conditions, depends_on)
    • Extends github-hierarchy-cache behavior with session-bootstrap cache refresh rules and repo-aware state reuse
    • Coverage includes agent-rule signal validation, worktree/branching policy, OpenSpec/TDD sequencing, quality gates, GitHub change governance, and release/documentation rules
    • Adds new agent-rule specification files (05–80 priority) as always-loaded and conditionally-loaded governance rules
  3. project-runtime-01-safe-artifact-write-policy (modules-side adoption)

    • Modules-specific companion to core profile-04-safe-project-artifact-writes
    • Adds specification requirements for backlog-add and backlog-sync to use safe-write contracts, preserving user artifacts

Module/Command Surface Changes

  • No public API/command changes: src/specfact_cli_modules/ remains pure runtime support
  • New dev-support functions: apply_specfact_workspace_env(repo_root) in dev_bootstrap.py sets SPECFACT_MODULES_REPO and SPECFACT_REPO_ROOT environment defaults, called by test infrastructure and pre-commit hooks
  • New tooling scripts (not exported):
    • scripts/sync_github_hierarchy_cache.py: CLI-driven cache sync with --repo-owner, --repo-name, --output, --state-file, --force options; deterministic fingerprint-based fast-exit
    • scripts/validate_agent_rule_applies_when.py: Governance rule validator for YAML frontmatter applies_when signal canonicity
    • tools/contract_first_smart_test.py: Enhanced with staged-file detection (_contract_test_status()) to conditionally gate contract tests

Cross-Repo Dependency and Dev Environment

  • New runtime dependency: json5>=0.9.28 (supports YAML config parsing)
  • Environment variable contract:
    • SPECFACT_MODULES_REPO set to repo root by default via pyproject.toml and apply_specfact_workspace_env()
    • SPECFACT_REPO_ROOT set when paired core repo can be resolved (sibling checkout or site-packages)
    • Both variables preserved if pre-existing (user override respect)
  • Workspace detection: dev_bootstrap logic updated to call apply_specfact_workspace_env() before core-repo resolution; tests/conftest.py now applies workspace env at import time
  • Paired core changes: expects specfact-cli to provide profile-04-safe-project-artifact-writes core companion; no breaking changes to import contracts

Manifest and Integrity

  • No semver/module-package.yaml changes: Repository module versions remain unchanged
  • Pre-commit configuration restructured:
    • Introduced fail_fast: true
    • Split quality checks into Block 1 (format, YAML, bundle import, lint via subcommand-based pre-commit-quality-checks.sh) and Block 2 (code review + contract tests)
    • Added per-block staged-file filtering and verbose output routing
  • Script execution model: scripts/pre-commit-quality-checks.sh now exposes subcommands (block1-format|block1-yaml|block1-bundle|block1-lint|block2|all) with centralized error output to stderr
  • Code review gate refactoring: scripts/pre_commit_code_review.py now dynamically loads dev_bootstrap, applies workspace env, and ensures report JSON creation before gate exit

Documentation

  • Governance rule structure: New docs/agent-rules/ directory with numbered rule files (INDEX.md at priority 0, non-negotiable checklist at 05, session-bootstrap at 10, repository-context at 20, etc. through 80)
    • All rule files include YAML frontmatter with control fields (id, always_load, applies_when, blocking, priority, dependencies, stop conditions)
    • INDEX.md defines applicability matrix mapping task signals (session-bootstrap, implementation, GitHub work, release, etc.) to required rule files
  • Bootstrap alias surfaces:
    • .cursorrules: Directs tooling to AGENTS.md then docs/agent-rules/INDEX.md
    • .github/copilot-instructions.md: GitHub Copilot governance entry point referencing mandatory bootstrap and docs/agent-rules/
    • AGENTS.md: Reduced from ~150 to ~55 lines; now contains only compact bootstrap checklist and canonical references
    • CLAUDE.md: Alias redirecting to AGENTS.md and docs/agent-rules/ with clean-code compliance categories listed
  • Navigation update: docs/_data/nav.yml adds top-level "Agent Governance" section linking to /contributing/agent-rules/ rule index and individual rule files
  • README clarifications: Specified Block 2 execution for code review gate and clarified pre-commit hook sequencing with explicit file-type filtering
  • Test coverage: New test suite (tests/unit/docs/test_agent_rules_governance.py) validates rule file existence, required YAML frontmatter keys, and INDEX.md bootstrap determinism; tests/unit/scripts/ covers GitHub cache sync determinism, hierarchy fingerprinting, and rule-signal validation

Quality Gate Integration

  • Governance validation now includes:
    • hatch run validate-agent-rule-signals (new script command) to enforce canonical applies_when signal values
    • Unit tests for rule frontmatter schema and applicability matrix coherence
    • Pre-commit hook sequencing explicitly ordered with fail-fast and per-block scoping
    • Contract-test status detection via tools/contract_first_smart_test.py to conditionally run full suite when contract-relevant files are staged

Known Open Items

  • Full-scope SpecFact code review still contains pre-existing findings (934 across modules); changed-scope review passes
  • Module setup is no longer blocking for worktree initialization
  • Checklist notes indicate signature verification and version-bump review steps remain to be completed by PR author
  • Pages workflow and cross-link review documented as pending (README.md external references to modules.specfact.io)

Walkthrough

This PR introduces a deterministic agent governance system by consolidating repository rules into a canonical docs/agent-rules/ index and accompanying rule files, refactors pre-commit hooks into staged blocks, adds a GitHub hierarchy cache sync script for cache-first issue parenting, and includes OpenSpec changes for safe artifact writes and governance loading.

Changes

Cohort / File(s) Summary
Agent Governance Framework
AGENTS.md, CLAUDE.md, .cursorrules, .github/copilot-instructions.md
Converted AGENTS.md from full handbook to compact bootstrap contract; added alias/redirect surfaces (CLAUDE.md, .cursorrules, Copilot instructions) pointing to canonical docs/agent-rules/.
Agent Rules Documentation
docs/agent-rules/INDEX.md, docs/agent-rules/05-non-negotiable-checklist.md, docs/agent-rules/10-session-bootstrap.md, docs/agent-rules/20-repository-context.md, docs/agent-rules/30-worktrees-and-branching.md, docs/agent-rules/40-openspec-and-tdd.md, docs/agent-rules/50-quality-gates-and-review.md, docs/agent-rules/60-github-change-governance.md, docs/agent-rules/70-release-commit-and-docs.md, docs/agent-rules/80-current-guidance-catalog.md
Established deterministic agent rule system with mandatory INDEX and non-negotiable checklist; introduced 8 focused rule documents covering worktrees, OpenSpec/TDD, quality gates, GitHub governance, and release workflows; includes machine-readable YAML frontmatter for applicability gating.
GitHub Hierarchy Cache
scripts/sync_github_hierarchy_cache.py, scripts/validate_agent_rule_applies_when.py
Implemented repo-local cache sync for Epic/Feature hierarchy metadata with fingerprint-based fast-exit and state reuse; added validator for canonical applies_when signals in rule frontmatter.
Pre-commit Restructuring
.pre-commit-config.yaml, scripts/pre-commit-quality-checks.sh, scripts/pre_commit_code_review.py
Split pre-commit into staged blocks (Block 1: format/yaml/bundle/lint; Block 2: code review/contract tests); enabled fail_fast; refactored hook execution to use subcommands; updated code review script with workspace env setup and report path handling.
Bootstrap & Environment
pyproject.toml, src/specfact_cli_modules/dev_bootstrap.py, tests/conftest.py
Added SPECFACT_MODULES_REPO hatch env var; introduced apply_specfact_workspace_env() for deterministic workspace setup; refactored core dependency resolution to include environment initialization.
Documentation & Navigation
README.md, docs/_data/nav.yml, openspec/CHANGE_ORDER.md
Updated README to clarify Block 2 code-review execution; added "Agent Governance" nav section with links to all rule docs; extended CHANGE_ORDER with project-runtime and governance follow-ups.
OpenSpec Governance Changes
openspec/changes/governance-03-github-hierarchy-cache/..., openspec/changes/governance-04-deterministic-agent-governance-loading/..., openspec/changes/project-runtime-01-safe-artifact-write-policy/..., openspec/config.yaml, openspec/specs/github-hierarchy-cache/spec.md, openspec/specs/backlog-sync/spec.md
Archived governance-03 change (GitHub hierarchy cache sync); added governance-04 change (deterministic agent loading with index, rule files, frontmatter validation); added project-runtime-01 change (safe artifact write adoption); updated config to reference canonical agent-rules docs; extended specs for cache-first backlog sync and hierarchy resolution.
Test Suite
tests/__init__.py, tests/unit/docs/test_agent_rules_governance.py, tests/unit/scripts/test_sync_github_hierarchy_cache.py, tests/unit/scripts/test_validate_agent_rule_applies_when.py, tests/unit/scripts/test_pre_commit_code_review.py, tests/unit/test_dev_bootstrap.py, tests/unit/test_pre_commit_quality_parity.py, tests/unit/tools/test_contract_first_smart_test.py
Added test module initialization; introduced comprehensive governance validation tests (frontmatter schema, rule index metadata, canonical signals); added cache sync tests (fingerprint determinism, state reuse, repo mismatch handling); added validator and contract-test-status tests; refactored pre-commit parity tests to enforce hook order/structure; extended dev-bootstrap tests for workspace env setup.
Tool Enhancement
tools/contract_first_smart_test.py
Added staged-file detection and contract-test status command to decide whether contract tests must run based on git-changed surfaces; implemented _contract_test_status() with exit code 1 when git is unavailable or contract-relevant paths touched.

Sequence Diagram(s)

sequenceDiagram
    actor Agent
    participant Bootstrap as Session Bootstrap<br/>(10-session-bootstrap.md)
    participant Index as Rule Index<br/>(INDEX.md)
    participant Cache as GitHub Hierarchy Cache
    participant Rules as Rule Files<br/>(05–80)
    participant Checklist as Non-Negotiable<br/>Checklist

    Agent->>Bootstrap: START: Load AGENTS.md
    Bootstrap->>Bootstrap: Detect repo/worktree/branch
    Bootstrap->>Bootstrap: Reject dev/main unless override
    Bootstrap->>Cache: Check .specfact/backlog/...<br/>freshness
    alt Cache missing or stale
        Bootstrap->>Cache: python scripts/sync_...<br/>_github_hierarchy_cache.py
        Cache->>Cache: Fetch Epic/Feature<br/>via gh api graphql
        Cache->>Cache: Compute fingerprint,<br/>write markdown
    end
    Bootstrap->>Index: Load docs/agent-rules/INDEX.md
    Index->>Index: Verify always-load subset<br/>and precedence
    Index->>Checklist: Load 05-non-negotiable-checklist
    Checklist->>Checklist: Apply mandatory gates<br/>(OpenSpec, TDD, quality)
    Index->>Rules: Map task signal→<br/>required/optional rules
    Rules->>Rules: Load applies_when-matched<br/>rule files (10–80)
    Agent->>Rules: BEGIN implementation<br/>per rule directives
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

This PR spans heterogeneous changes across governance documentation, scripts, configuration, and tests. Key review areas: deterministic rule-loading contracts (INDEX.md, frontmatter schema, canonical signals); cache-sync fingerprinting and state reuse logic; pre-commit block staging and hook ordering; workspace environment setup; and comprehensive test coverage for new validator/cache/governance surfaces. While individual documentation files are straightforward, the interplay between bootstrap sequences, rule applicability, and environment setup requires careful verification of control flow and contract enforcement.

Possibly related issues

Possibly related PRs

Suggested labels

documentation, dependencies, project

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6cd6564cff

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 18 to 22
dependencies = [
"json5>=0.9.28",
"icontract>=2.7.1",
"pytest>=8.4.2",
"pytest-cov>=7.0.0",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Declare beartype in the default hatch environment

The new governance scripts import beartype unconditionally (scripts/sync_github_hierarchy_cache.py and scripts/validate_agent_rule_applies_when.py), but the default Hatch environment dependencies added here do not include beartype. In a fresh checkout (or any environment that has not separately installed specfact-cli), running python scripts/sync_github_hierarchy_cache.py (now required by AGENTS bootstrap) or hatch run validate-agent-rule-signals fails immediately with ModuleNotFoundError: beartype, so the new workflow cannot run as documented.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 25

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
openspec/specs/backlog-sync/spec.md (1)

7-33: ⚠️ Potential issue | 🟠 Major

Pin the hierarchy-cache path contract explicitly in spec text.

repo-local hierarchy cache is currently ambiguous. Cross-repo tooling/tests rely on the canonical files (.specfact/backlog/github_hierarchy_cache.md and state JSON). Please make the path contract explicit here to prevent adapter drift between modules and specfact-cli.

Suggested spec wording update
-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.
+The system SHALL provide `specfact backlog sync` command for bidirectional backlog synchronization, and related governance workflows SHALL resolve current Epic and Feature planning metadata from `.specfact/backlog/github_hierarchy_cache.md` (with deterministic state tracked in `.specfact/backlog/github_hierarchy_cache_state.json`) before performing manual GitHub lookups.

 #### 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
+- **WHEN** `.specfact/backlog/github_hierarchy_cache.md` is present and current
 - **THEN** the contributor can resolve the parent relationship from the cache without an additional GitHub lookup
As per coding guidelines: “`openspec/**/*.md`: Specification truth: proposal/tasks/spec deltas vs. bundle behavior, CHANGE_ORDER, and drift vs. shipped modules or docs.”
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@openspec/specs/backlog-sync/spec.md` around lines 7 - 33, Update the spec
text to explicitly pin the repo-local hierarchy cache path and state file names
so adapters and specfact-cli share a canonical contract: replace ambiguous
instances of "repo-local hierarchy cache" with the explicit paths
`.specfact/backlog/github_hierarchy_cache.md` for the human-readable hierarchy
and the accompanying state JSON (e.g.,
`.specfact/backlog/github_hierarchy_cache.state.json`), and add a short sentence
in the "Cache-first hierarchy lookup for parent issue assignment" scenario
noting that tools MUST read/write those exact files and only fall back to GitHub
when those files are missing or stale; reference the command `specfact backlog
sync` and the alias `specfact backlog ceremony sync` so the change is visible to
consumers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/agent-rules/50-quality-gates-and-review.md`:
- Around line 39-49: The quality gate list omits the bundle-import validation
step; update the "Quality gate order" sequence to include the command hatch run
check-bundle-imports in the proper place (e.g., after yaml-lint or before
verify-modules-signature) so the documented canonical order matches the updated
pre-commit flow and local validation checklist; modify the ordered list under
"Quality gate order" to insert hatch run check-bundle-imports and ensure
surrounding steps (hatch run yaml-lint and hatch run verify-modules-signature)
remain intact.

In `@docs/agent-rules/60-github-change-governance.md`:
- Around line 62-63: Replace the vague “about five minutes” with a precise
freshness rule: treat .specfact/backlog/github_hierarchy_cache.md as stale if
its recorded timestamp (use an explicit field like last_synced_at in the cache
file or the file mtime) is older than 300 seconds (5 * 60) compared to the
current UTC time; update the text and any checks that call python
scripts/sync_github_hierarchy_cache.py to compare UTC now against last_synced_at
(or mtime) using seconds to decide whether to run the sync.

In `@docs/agent-rules/70-release-commit-and-docs.md`:
- Line 45: Update Step 1 so branch-prefix guidance matches the bootstrap rules:
allow branches rooted from origin/dev with prefixes feature/*, bugfix/*,
hotfix/*, or chore/* (and optionally note the expected worktree location under
../specfact-cli-modules-worktrees/) — or explicitly state if restricting to only
feature/hotfix is intentional; modify the Step 1 text (the line "Branch from
`origin/dev` into a feature or hotfix branch.") to enumerate the allowed
prefixes or add the clarification.

In `@openspec/CHANGE_ORDER.md`:
- Line 78: The CHANGE_ORDER.md contains a pending entry for governance-03
(identifier governance-03-github-hierarchy-cache) but this change is archived;
remove the governance-03 row from the Pending table (or move it into an
Archived/Removed section) and update any parent/paired references (e.g., the
Parent Feature link to `#163` and paired specfact-cli#491 mention) so the pending
table reflects only active change artifacts and avoids drift.

In
`@openspec/changes/archive/2026-04-09-governance-03-github-hierarchy-cache/specs/backlog-sync/spec.md`:
- Around line 1-4: Add a top-level heading and ensure blank lines surround each
heading in the spec to satisfy markdown validation: insert a top-level H1 (e.g.,
"Archived Specs" or similar) above the existing "## MODIFIED Requirements", and
add a single blank line before and after each heading such as "## MODIFIED
Requirements" and "### Requirement: Restore backlog sync command functionality"
(and other headings referenced on lines 3, 12, 17, 21, 25, 31) so the `spec.md`
file, which mentions `specfact backlog sync`, has proper spacing and a top-level
heading.

In
`@openspec/changes/governance-04-deterministic-agent-governance-loading/CHANGE_VALIDATION.md`:
- Around line 27-34: Update the validation summary so it does not claim PASS
when the mandatory full review is failing: change the header/result from
"Result: PASS" to indicate PENDING/BLOCKED and add a clear note that
`.specfact/code-review.json` produced 934 findings and the full-review gate must
pass before marking the change validated; keep the existing details about
`.specfact/code-review.changed.json` passing and the commands used (`hatch run
specfact code review run --json --out .specfact/code-review.json` and the
changed-scope command) so readers see both outcomes and the required action to
re-run the full command until the full review passes.

In
`@openspec/changes/governance-04-deterministic-agent-governance-loading/proposal.md`:
- Around line 1-3: Add a top-level Markdown title before the existing "## Why"
heading to satisfy markdownlint and improve document structure; insert a line
like "# Proposal: Deterministic Agent Governance Loading" at the top of the
proposal (keeping the existing "## Why" section intact) so the document begins
with a single H1 heading.

In
`@openspec/changes/governance-04-deterministic-agent-governance-loading/specs/agent-governance-loading/spec.md`:
- Around line 1-14: The spec is missing a top-level heading; open
specs/agent-governance-loading/spec.md and add a top-level H1 heading
"Specification: Agent Governance Loading" above the existing "## ADDED
Requirements" line so the document conforms to markdownlint and matches the
pattern used in proposal.md; ensure the exact heading text is used and placed as
the first non-blank line of the file.

In
`@openspec/changes/governance-04-deterministic-agent-governance-loading/TDD_EVIDENCE.md`:
- Around line 44-47: Summary: The full-repo SpecFact quality gate still fails
(934 findings) causing release promotion to be blocked; either fix findings or
add an approved exception. Fix: run the exact verification command shown (`hatch
run specfact code review run --json --out .specfact/code-review.json --scope
full`) to regenerate `.specfact/code-review.json`, triage and remediate the
reported findings (start with high-severity items such as the legacy
`packages/specfact-backlog/src/specfact_backlog/backlog/commands.py` complexity
issues), or if remediation is infeasible create an explicit, approved exception
record in the release checklist for this PR referencing task `4.2` and attach
the `.specfact/code-review.json` artifact and justification; update the PR
description/checklist to point to the exception and ensure an approver signs off
before merge.

In
`@openspec/changes/project-runtime-01-safe-artifact-write-policy/specs/backlog-add/spec.md`:
- Around line 3-6: The markdown headings are missing required blank lines
(MD022) which breaks markdownlint; update the spec by inserting a single blank
line after the "Requirement: Backlog add local artifact helpers SHALL preserve
user-managed content" heading and another blank line after the "Scenario:
Existing local config is not silently replaced" heading so each heading is
followed by an empty line, ensuring the document adheres to markdownlint rules.

In
`@openspec/changes/project-runtime-01-safe-artifact-write-policy/specs/backlog-sync/spec.md`:
- Around line 1-6: Add a top-level H1 and ensure blank lines surround the
existing headings to satisfy markdownlint (MD041/MD022): insert a single H1 at
the top of the file (for example "Backlog sync requirements" or similar), then
ensure there is a blank line before and after "## ADDED Requirements", and add
blank lines before and after "### Requirement: Backlog sync local export paths
SHALL avoid silent overwrites" and before and after "#### Scenario: Existing
export target produces conflict or safe merge" so each heading has the required
surrounding blank lines.

In `@openspec/changes/project-runtime-01-safe-artifact-write-policy/tasks.md`:
- Around line 23-25: Reorder the checklist so quality gates run in the canonical
sequence: ensure the `hatch run format`, `hatch run type-check`, and `hatch run
lint` remain first, then list `hatch run yaml-lint` followed immediately by
`verify-modules-signature` (add or rename the step to `verify-modules-signature`
if needed), then run `hatch run contract-test`, then the relevant
`smart-test`/`test` coverage, and finally the `.specfact/code-review.json`
review step; move the version bump / re-sign changed manifests remediation (the
current 4.4) to immediately after `verify-modules-signature` so package
version/signature fixes occur before `contract-test`, and keep recording the
final review timestamp in `TDD_EVIDENCE.md` or PR notes as the last action.

In `@openspec/specs/github-hierarchy-cache/spec.md`:
- Around line 3-5: The Purpose section of this spec file (heading "Purpose") is
still "TBD" and must be replaced with a self-contained description of what the
github-hierarchy-cache spec standardizes; update the "Purpose" heading to a
concise summary that explains scope, intended behavior, and how it relates to
archived-change governance-03-github-hierarchy-cache, and ensure the
"Requirements" section references any CHANGE_ORDER, drift/shipping constraints
and the openspec/**/*.md conventions so the spec is complete before merging.

In `@README.md`:
- Line 56: Update the README run-sequence so the standalone final code-review
gate is explicitly listed and matches the pre-commit path: add the command
"hatch run specfact code review run --json --out .specfact/code-review.json" (or
the equivalent "specfact code review run --json --out
.specfact/code-review.json" if already run in a hatch context) into the top “Run
this sequence” block after tests, ensuring the sequence reads: format →
type-check → lint → yaml-lint → verify-modules-signature → contract-test →
smart-test → test → specfact code review; mention the same helper behavior
referenced by pre-commit-quality-checks.sh block2 and
scripts/pre_commit_code_review.py so manual local validation matches the
required governance order.

In `@scripts/pre-commit-quality-checks.sh`:
- Around line 149-169: The run_code_review_gate function only collects staged
Python files via staged_python_files and so skips review for non-Python contract
changes; change it to gather all review-relevant staged paths (not just
*.py/*.pyi) by calling the staged files helper that returns all staged paths
(e.g., staged_files or staged_paths) and filter/include files under packages/,
registry/, scripts/, tools/, tests/, and openspec/changes/* (but exclude any
TDD_EVIDENCE.md) before invoking scripts/pre_commit_code_review.py; ensure the
collected list is passed to scripts/pre_commit_code_review.py the same way
${py_array[@]} currently is and update the info/warn messages to reflect the
broader file set in run_code_review_gate.
- Around line 209-218: The current short-circuit in run_block2() uses
check_safe_change() too broadly and lets edits to tooling/config (e.g.,
pyproject.toml or this pre-commit script) skip the review and contract-test
decision; narrow the safe-change logic so tooling/config files do not trigger
the fast path by updating check_safe_change() usage or its predicate inside
run_block2() to exclude repo metadata that defines the quality pipeline (ensure
changes to pyproject.toml, scripts/pre-commit-quality-checks.sh, and other
pipeline-defining files bypass the safe path), then keep print_block2_overview,
run_code_review_gate and run_contract_tests_visible executing for those changes.

In `@scripts/sync_github_hierarchy_cache.py`:
- Around line 336-348: The fingerprint currently includes updated_at (causing
unnecessary churn) and omits fields that affect rendered output; in
compute_hierarchy_fingerprint replace updated_at with the exact fields used when
rendering the cache (e.g., include issue.url and issue.summary and any other
rendered inputs you write out such as title, labels, parent_number,
child_numbers) and keep deterministic ordering (sorted labels, sorted children
by number) so the hash reflects only rendered-output-relevant data; adjust the
canonical_rows construction in compute_hierarchy_fingerprint/HierarchyIssue
accordingly.
- Around line 98-100: The GraphQL subIssues connection currently uses
subIssues(first: 100) without pageInfo and the code does not handle nested
pagination, causing silent truncation; update the query to request pageInfo {
hasNextPage endCursor } for subIssues and modify the GraphQL-fetching logic that
builds the issue hierarchy (the code handling the subIssues connection /
response) to iterate using endCursor while hasNextPage to fetch all pages,
merging nodes across pages, or alternatively detect hasNextPage and raise a
clear error to prevent silent truncation; ensure the final hierarchy/fingerprint
includes all children and that any error path logs the problematic parent issue
number/URL.

In `@scripts/validate_agent_rule_applies_when.py`:
- Around line 55-59: path.read_text can raise OSError/UnicodeDecodeError and
currently crashes the validator; wrap the call to
path.read_text(encoding="utf-8") in a try/except that catches OSError and
UnicodeDecodeError, append a structured validation entry to the existing errors
list (e.g. f"{path.name}: failed to read file: {err}") and continue the loop,
then only call _parse_frontmatter(text) if read succeeded so parsed handling
remains unchanged.
- Around line 66-68: In validate_agent_rule_applies_when
(scripts/validate_agent_rule_applies_when.py) stop coercing list items to text:
when raw is a list, validate each entry is either a str or None and if any item
has a different type raise a TypeError with a clear message identifying
"applies_when" entries; only after validation build signals as the list of
strings (i.e., keep items as-is, not str(item)) and filter out None. This
replaces the current signals = [str(item) for item in raw if item is not None]
with explicit type checks and an immediate error on malformed types.

In `@src/specfact_cli_modules/dev_bootstrap.py`:
- Around line 58-62: The code uses os.environ.setdefault(...) which preserves
any previously exported SPECFACT_MODULES_REPO / SPECFACT_REPO_ROOT; instead,
always overwrite with the current checkout values: replace
os.environ.setdefault("SPECFACT_MODULES_REPO", str(resolved)) with an assignment
that sets os.environ["SPECFACT_MODULES_REPO"] = str(resolved), and if core is
not None replace os.environ.setdefault("SPECFACT_REPO_ROOT", str(core)) with
os.environ["SPECFACT_REPO_ROOT"] = str(core); locate these changes around the
resolved = repo_root.resolve() and core = resolve_core_repo(repo_root) usage in
dev_bootstrap.py.

In `@tests/unit/docs/test_agent_rules_governance.py`:
- Around line 68-74: The test function
test_agents_references_canonical_rule_docs verifies AGENTS.md contains specific
doc references and section text but the file lacks a trailing newline; open
AGENTS.md and add a single POSIX-compliant newline at EOF (ensure the file ends
with "\n") so the test environment and tools that expect a trailing newline
won't complain when running test_agents_references_canonical_rule_docs.

In `@tests/unit/scripts/test_pre_commit_code_review.py`:
- Around line 89-98: Extract the repeated mocked report payload into a single
shared test fixture/object and reuse it instead of inlining it twice;
specifically create a variable (e.g., sample_review_report =
{"overall_verdict":"FAIL","findings":[{"severity":"error","rule":"e1"},{"severity":"warning","rule":"w1"}]})
near the top of the test module and replace the inline literal passed to
_write_sample_review_report(repo_root, ...) with that variable in all
occurrences so the test_pre_commit_code_review.py assertions stay consistent and
easier to maintain.

In `@tests/unit/scripts/test_sync_github_hierarchy_cache.py`:
- Around line 459-474: Wrap the test body in a try/finally (or use a teardown
fixture) so cleanup always runs: after setting subprocess.run to _no_git via
monkeypatch.setattr and importing the module via _load_script_module(), ensure
_load_script_module.cache_clear() and
sys.modules.pop("sync_github_hierarchy_cache", None) are invoked in a finally
block; this guarantees that the monkeypatched subprocess.run is restored and the
import cache is cleared even if the assertion in
test_default_repo_name_falls_back_when_git_unavailable fails.

In `@tests/unit/tools/test_contract_first_smart_test.py`:
- Around line 44-61: Add a third "happy-path" unit test in
tests/unit/tools/test_contract_first_smart_test.py that patches
cfst_mod._git_staged_names to return a contract-relevant path (e.g.,
"contracts/some_contract.yaml" or any path your code treats as contract-related)
and assert cfst_mod._contract_test_status() == 1; reference the existing tests
for structure and reuse monkeypatch and the cfst_mod fixture, and ensure the new
test name makes intent clear (e.g.,
test_contract_test_status_returns_one_for_relevant_staged).

---

Outside diff comments:
In `@openspec/specs/backlog-sync/spec.md`:
- Around line 7-33: Update the spec text to explicitly pin the repo-local
hierarchy cache path and state file names so adapters and specfact-cli share a
canonical contract: replace ambiguous instances of "repo-local hierarchy cache"
with the explicit paths `.specfact/backlog/github_hierarchy_cache.md` for the
human-readable hierarchy and the accompanying state JSON (e.g.,
`.specfact/backlog/github_hierarchy_cache.state.json`), and add a short sentence
in the "Cache-first hierarchy lookup for parent issue assignment" scenario
noting that tools MUST read/write those exact files and only fall back to GitHub
when those files are missing or stale; reference the command `specfact backlog
sync` and the alias `specfact backlog ceremony sync` so the change is visible to
consumers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4f777531-c9df-4487-8b32-8337cb88bac1

📥 Commits

Reviewing files that changed from the base of the PR and between 5677559 and 6cd6564.

📒 Files selected for processing (61)
  • .cursorrules
  • .github/copilot-instructions.md
  • .pre-commit-config.yaml
  • AGENTS.md
  • CLAUDE.md
  • README.md
  • docs/_data/nav.yml
  • docs/agent-rules/05-non-negotiable-checklist.md
  • docs/agent-rules/10-session-bootstrap.md
  • docs/agent-rules/20-repository-context.md
  • docs/agent-rules/30-worktrees-and-branching.md
  • docs/agent-rules/40-openspec-and-tdd.md
  • docs/agent-rules/50-quality-gates-and-review.md
  • docs/agent-rules/60-github-change-governance.md
  • docs/agent-rules/70-release-commit-and-docs.md
  • docs/agent-rules/80-current-guidance-catalog.md
  • docs/agent-rules/INDEX.md
  • openspec/CHANGE_ORDER.md
  • openspec/changes/archive/2026-04-09-governance-03-github-hierarchy-cache/.openspec.yaml
  • openspec/changes/archive/2026-04-09-governance-03-github-hierarchy-cache/CHANGE_VALIDATION.md
  • openspec/changes/archive/2026-04-09-governance-03-github-hierarchy-cache/TDD_EVIDENCE.md
  • openspec/changes/archive/2026-04-09-governance-03-github-hierarchy-cache/design.md
  • openspec/changes/archive/2026-04-09-governance-03-github-hierarchy-cache/proposal.md
  • openspec/changes/archive/2026-04-09-governance-03-github-hierarchy-cache/specs/backlog-sync/spec.md
  • openspec/changes/archive/2026-04-09-governance-03-github-hierarchy-cache/specs/github-hierarchy-cache/spec.md
  • openspec/changes/archive/2026-04-09-governance-03-github-hierarchy-cache/tasks.md
  • openspec/changes/governance-04-deterministic-agent-governance-loading/.openspec.yaml
  • openspec/changes/governance-04-deterministic-agent-governance-loading/CHANGE_VALIDATION.md
  • openspec/changes/governance-04-deterministic-agent-governance-loading/TDD_EVIDENCE.md
  • openspec/changes/governance-04-deterministic-agent-governance-loading/design.md
  • openspec/changes/governance-04-deterministic-agent-governance-loading/proposal.md
  • openspec/changes/governance-04-deterministic-agent-governance-loading/specs/agent-governance-loading/spec.md
  • openspec/changes/governance-04-deterministic-agent-governance-loading/specs/github-hierarchy-cache/spec.md
  • openspec/changes/governance-04-deterministic-agent-governance-loading/tasks.md
  • openspec/changes/project-runtime-01-safe-artifact-write-policy/.openspec.yaml
  • openspec/changes/project-runtime-01-safe-artifact-write-policy/CHANGE_VALIDATION.md
  • openspec/changes/project-runtime-01-safe-artifact-write-policy/design.md
  • openspec/changes/project-runtime-01-safe-artifact-write-policy/proposal.md
  • openspec/changes/project-runtime-01-safe-artifact-write-policy/specs/backlog-add/spec.md
  • openspec/changes/project-runtime-01-safe-artifact-write-policy/specs/backlog-sync/spec.md
  • openspec/changes/project-runtime-01-safe-artifact-write-policy/specs/runtime-artifact-write-safety/spec.md
  • openspec/changes/project-runtime-01-safe-artifact-write-policy/tasks.md
  • openspec/config.yaml
  • openspec/specs/backlog-sync/spec.md
  • openspec/specs/github-hierarchy-cache/spec.md
  • pyproject.toml
  • scripts/pre-commit-quality-checks.sh
  • scripts/pre_commit_code_review.py
  • scripts/sync_github_hierarchy_cache.py
  • scripts/validate_agent_rule_applies_when.py
  • src/specfact_cli_modules/dev_bootstrap.py
  • tests/__init__.py
  • tests/conftest.py
  • tests/unit/docs/test_agent_rules_governance.py
  • tests/unit/scripts/test_pre_commit_code_review.py
  • tests/unit/scripts/test_sync_github_hierarchy_cache.py
  • tests/unit/scripts/test_validate_agent_rule_applies_when.py
  • tests/unit/test_dev_bootstrap.py
  • tests/unit/test_pre_commit_quality_parity.py
  • tests/unit/tools/test_contract_first_smart_test.py
  • tools/contract_first_smart_test.py

Comment on lines +39 to +49
## Quality gate order

1. `hatch run format`
2. `hatch run type-check`
3. `hatch run lint`
4. `hatch run yaml-lint`
5. `hatch run verify-modules-signature --require-signature --payload-from-filesystem --enforce-version-bump`
6. `hatch run contract-test`
7. `hatch run smart-test`
8. `hatch run test`

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

Document the bundle-import gate in the manual sequence.

This “canonical” gate order skips hatch run check-bundle-imports, even though the updated pre-commit flow and the PR’s required local validation checklist treat bundle import validation as part of the release surface. Leaving it out here will drift the rule page from the actual verification contract.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/agent-rules/50-quality-gates-and-review.md` around lines 39 - 49, The
quality gate list omits the bundle-import validation step; update the "Quality
gate order" sequence to include the command hatch run check-bundle-imports in
the proper place (e.g., after yaml-lint or before verify-modules-signature) so
the documented canonical order matches the updated pre-commit flow and local
validation checklist; modify the ordered list under "Quality gate order" to
insert hatch run check-bundle-imports and ensure surrounding steps (hatch run
yaml-lint and hatch run verify-modules-signature) remain intact.

Comment on lines +62 to +63
1. If `.specfact/backlog/github_hierarchy_cache.md` is missing, or was last updated more than about five minutes ago, run `python scripts/sync_github_hierarchy_cache.py`.
2. Re-read the issue state from GitHub or the refreshed cache-backed workflow and confirm the issue is still `in progress`.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Replace “about five minutes” with an exact freshness rule.

For deterministic governance across modules and core workflows, make this threshold exact (for example, fixed seconds and explicit timestamp source/state field) instead of approximate wording.

Based on learnings: “Refresh .specfact/backlog/github_hierarchy_cache.md … when GitHub hierarchy metadata is missing or stale before parent or blocker work.”

🧰 Tools
🪛 LanguageTool

[uncategorized] ~62-~62: The official name of this software platform is spelled with a capital “H”.
Context: ... a current view of GitHub state: 1. If .specfact/backlog/github_hierarchy_cache.md is missing, or was ...

(GITHUB)


[uncategorized] ~62-~62: The official name of this software platform is spelled with a capital “H”.
Context: ...d more than about five minutes ago, run python scripts/sync_github_hierarchy_cache.py. 2. Re-read the iss...

(GITHUB)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/agent-rules/60-github-change-governance.md` around lines 62 - 63,
Replace the vague “about five minutes” with a precise freshness rule: treat
.specfact/backlog/github_hierarchy_cache.md as stale if its recorded timestamp
(use an explicit field like last_synced_at in the cache file or the file mtime)
is older than 300 seconds (5 * 60) compared to the current UTC time; update the
text and any checks that call python scripts/sync_github_hierarchy_cache.py to
compare UTC now against last_synced_at (or mtime) using seconds to decide
whether to run the sync.


## Registry and publish flow

1. Branch from `origin/dev` into a feature or hotfix branch.
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

Keep the branch-prefix guidance aligned with the bootstrap rules.

Step 1 narrows this to feature or hotfix, but the canonical bootstrap guidance also allows bugfix/* and chore/*. That gives agents conflicting instructions during finalization/release flows unless this restriction is intentional and called out explicitly. Based on learnings "Work belongs on feature/, bugfix/, hotfix/, or chore/ branches, normally in a worktree rooted under ../specfact-cli-modules-worktrees/."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/agent-rules/70-release-commit-and-docs.md` at line 45, Update Step 1 so
branch-prefix guidance matches the bootstrap rules: allow branches rooted from
origin/dev with prefixes feature/*, bugfix/*, hotfix/*, or chore/* (and
optionally note the expected worktree location under
../specfact-cli-modules-worktrees/) — or explicitly state if restricting to only
feature/hotfix is intentional; modify the Step 1 text (the line "Branch from
`origin/dev` into a feature or hotfix branch.") to enumerate the allowed
prefixes or add the clarification.

|--------|-------|---------------|----------|------------|
| 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) |
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 | 🟠 Major

governance-03 should not remain in the Pending table if it is archived.

Line 78 conflicts with the archived change artifacts included in this PR, which creates change-order drift and can mislead dependency planning.

As per coding guidelines: "openspec/**/*.md: Specification truth: proposal/tasks/spec deltas vs. bundle behavior, CHANGE_ORDER, and drift vs. shipped modules or docs."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@openspec/CHANGE_ORDER.md` at line 78, The CHANGE_ORDER.md contains a pending
entry for governance-03 (identifier governance-03-github-hierarchy-cache) but
this change is archived; remove the governance-03 row from the Pending table (or
move it into an Archived/Removed section) and update any parent/paired
references (e.g., the Parent Feature link to `#163` and paired specfact-cli#491
mention) so the pending table reflects only active change artifacts and avoids
drift.

Comment on lines +1 to +4
## MODIFIED Requirements

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

Minor markdown formatting inconsistencies.

Static analysis flagged missing top-level heading (line 1 starts with ## MODIFIED) and missing blank lines around headings (lines 3, 12, 17, 21, 25, 31). Since this is an archived spec, these are cosmetic—consider fixing if the archive format is subject to docs validation.

📝 Optional fix to add top-level heading and blank lines
+# Backlog Sync Specification
+
 ## MODIFIED Requirements
 
 ### 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.
📝 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
### 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.
# Backlog Sync Specification
## MODIFIED Requirements
### 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.
🧰 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)


[warning] 3-3: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@openspec/changes/archive/2026-04-09-governance-03-github-hierarchy-cache/specs/backlog-sync/spec.md`
around lines 1 - 4, Add a top-level heading and ensure blank lines surround each
heading in the spec to satisfy markdown validation: insert a top-level H1 (e.g.,
"Archived Specs" or similar) above the existing "## MODIFIED Requirements", and
add a single blank line before and after each heading such as "## MODIFIED
Requirements" and "### Requirement: Restore backlog sync command functionality"
(and other headings referenced on lines 3, 12, 17, 21, 25, 31) so the `spec.md`
file, which mentions `specfact backlog sync`, has proper spacing and a top-level
heading.

Comment on lines +58 to +62
resolved = repo_root.resolve()
os.environ.setdefault("SPECFACT_MODULES_REPO", str(resolved))
core = resolve_core_repo(repo_root)
if core is not None:
os.environ.setdefault("SPECFACT_REPO_ROOT", str(core))
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 | 🟠 Major

Overwrite the workspace repo env vars here instead of preserving stale exports.

setdefault() lets an old shell-exported SPECFACT_MODULES_REPO / SPECFACT_REPO_ROOT survive, which can point pytest, pre-commit, and the sibling nold-ai/specfact-cli scripts at a different checkout than the one currently being bootstrapped.

💡 Proposed fix
-    os.environ.setdefault("SPECFACT_MODULES_REPO", str(resolved))
+    os.environ["SPECFACT_MODULES_REPO"] = str(resolved)
     core = resolve_core_repo(repo_root)
     if core is not None:
-        os.environ.setdefault("SPECFACT_REPO_ROOT", str(core))
+        os.environ["SPECFACT_REPO_ROOT"] = str(core)
📝 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
resolved = repo_root.resolve()
os.environ.setdefault("SPECFACT_MODULES_REPO", str(resolved))
core = resolve_core_repo(repo_root)
if core is not None:
os.environ.setdefault("SPECFACT_REPO_ROOT", str(core))
resolved = repo_root.resolve()
os.environ["SPECFACT_MODULES_REPO"] = str(resolved)
core = resolve_core_repo(repo_root)
if core is not None:
os.environ["SPECFACT_REPO_ROOT"] = str(core)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/specfact_cli_modules/dev_bootstrap.py` around lines 58 - 62, The code
uses os.environ.setdefault(...) which preserves any previously exported
SPECFACT_MODULES_REPO / SPECFACT_REPO_ROOT; instead, always overwrite with the
current checkout values: replace os.environ.setdefault("SPECFACT_MODULES_REPO",
str(resolved)) with an assignment that sets os.environ["SPECFACT_MODULES_REPO"]
= str(resolved), and if core is not None replace
os.environ.setdefault("SPECFACT_REPO_ROOT", str(core)) with
os.environ["SPECFACT_REPO_ROOT"] = str(core); locate these changes around the
resolved = repo_root.resolve() and core = resolve_core_repo(repo_root) usage in
dev_bootstrap.py.

Comment on lines +68 to +74
def test_agents_references_canonical_rule_docs() -> None:
agents_text = (REPO_ROOT / "AGENTS.md").read_text(encoding="utf-8")

assert "docs/agent-rules/INDEX.md" in agents_text
assert "docs/agent-rules/05-non-negotiable-checklist.md" in agents_text
assert "## Strategic context" in agents_text
assert "Shared design and governance context lives in the paired public `specfact-cli` repository" in agents_text
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

AGENTS.md reference check ensures canonical rule docs are discoverable.

Verifying that AGENTS.md contains references to docs/agent-rules/INDEX.md and docs/agent-rules/05-non-negotiable-checklist.md ensures the compact bootstrap surface points to the canonical governance docs. The section text assertions (## Strategic context, paired repo reference) verify structural integrity.

Minor: Add a trailing newline at end of file for POSIX compliance.

🔧 Add trailing newline
     assert "docs/agent-rules/INDEX.md" in agents_text
     assert "docs/agent-rules/05-non-negotiable-checklist.md" in agents_text
     assert "## Strategic context" in agents_text
     assert "Shared design and governance context lives in the paired public `specfact-cli` repository" in agents_text
+
📝 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
def test_agents_references_canonical_rule_docs() -> None:
agents_text = (REPO_ROOT / "AGENTS.md").read_text(encoding="utf-8")
assert "docs/agent-rules/INDEX.md" in agents_text
assert "docs/agent-rules/05-non-negotiable-checklist.md" in agents_text
assert "## Strategic context" in agents_text
assert "Shared design and governance context lives in the paired public `specfact-cli` repository" in agents_text
def test_agents_references_canonical_rule_docs() -> None:
agents_text = (REPO_ROOT / "AGENTS.md").read_text(encoding="utf-8")
assert "docs/agent-rules/INDEX.md" in agents_text
assert "docs/agent-rules/05-non-negotiable-checklist.md" in agents_text
assert "## Strategic context" in agents_text
assert "Shared design and governance context lives in the paired public `specfact-cli` repository" in agents_text
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/docs/test_agent_rules_governance.py` around lines 68 - 74, The
test function test_agents_references_canonical_rule_docs verifies AGENTS.md
contains specific doc references and section text but the file lacks a trailing
newline; open AGENTS.md and add a single POSIX-compliant newline at EOF (ensure
the file ends with "\n") so the test environment and tools that expect a
trailing newline won't complain when running
test_agents_references_canonical_rule_docs.

Comment on lines +89 to +98
_write_sample_review_report(
repo_root,
{
"overall_verdict": "FAIL",
"findings": [
{"severity": "error", "rule": "e1"},
{"severity": "warning", "rule": "w1"},
],
},
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Deduplicate the mocked report payload to reduce test drift.

This block repeats the same JSON payload used earlier in the test; extracting one shared fixture/object would keep the contract assertions easier to maintain.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/scripts/test_pre_commit_code_review.py` around lines 89 - 98,
Extract the repeated mocked report payload into a single shared test
fixture/object and reuse it instead of inlining it twice; specifically create a
variable (e.g., sample_review_report =
{"overall_verdict":"FAIL","findings":[{"severity":"error","rule":"e1"},{"severity":"warning","rule":"w1"}]})
near the top of the test module and replace the inline literal passed to
_write_sample_review_report(repo_root, ...) with that variable in all
occurrences so the test_pre_commit_code_review.py assertions stay consistent and
easier to maintain.

Comment on lines +459 to +474
def test_default_repo_name_falls_back_when_git_unavailable(monkeypatch: pytest.MonkeyPatch) -> None:
"""If ``git`` is missing, DEFAULT_REPO_NAME must use the checkout directory fallback."""
_load_script_module.cache_clear()
sys.modules.pop("sync_github_hierarchy_cache", None)

def _no_git(*_args: Any, **_kwargs: Any) -> Any:
raise FileNotFoundError("git not found")

monkeypatch.setattr(subprocess, "run", _no_git)
module = _load_script_module()
script_path = Path(__file__).resolve().parents[3] / "scripts" / "sync_github_hierarchy_cache.py"
expected_fallback = script_path.resolve().parents[1].name
assert expected_fallback == module.DEFAULT_REPO_NAME

_load_script_module.cache_clear()
sys.modules.pop("sync_github_hierarchy_cache", None)
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

Test isolation: ensure cache cleanup runs even if assertions fail.

The _load_script_module.cache_clear() at line 473 won't execute if earlier assertions fail, potentially leaving subprocess.run monkeypatched for subsequent tests. Consider using a try/finally or pytest fixture with teardown to guarantee cleanup.

🛡️ Proposed fix using try/finally
 def test_default_repo_name_falls_back_when_git_unavailable(monkeypatch: pytest.MonkeyPatch) -> None:
     """If ``git`` is missing, DEFAULT_REPO_NAME must use the checkout directory fallback."""
     _load_script_module.cache_clear()
     sys.modules.pop("sync_github_hierarchy_cache", None)
 
     def _no_git(*_args: Any, **_kwargs: Any) -> Any:
         raise FileNotFoundError("git not found")
 
     monkeypatch.setattr(subprocess, "run", _no_git)
-    module = _load_script_module()
-    script_path = Path(__file__).resolve().parents[3] / "scripts" / "sync_github_hierarchy_cache.py"
-    expected_fallback = script_path.resolve().parents[1].name
-    assert expected_fallback == module.DEFAULT_REPO_NAME
-
-    _load_script_module.cache_clear()
-    sys.modules.pop("sync_github_hierarchy_cache", None)
+    try:
+        module = _load_script_module()
+        script_path = Path(__file__).resolve().parents[3] / "scripts" / "sync_github_hierarchy_cache.py"
+        expected_fallback = script_path.resolve().parents[1].name
+        assert expected_fallback == module.DEFAULT_REPO_NAME
+    finally:
+        _load_script_module.cache_clear()
+        sys.modules.pop("sync_github_hierarchy_cache", None)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/scripts/test_sync_github_hierarchy_cache.py` around lines 459 -
474, Wrap the test body in a try/finally (or use a teardown fixture) so cleanup
always runs: after setting subprocess.run to _no_git via monkeypatch.setattr and
importing the module via _load_script_module(), ensure
_load_script_module.cache_clear() and
sys.modules.pop("sync_github_hierarchy_cache", None) are invoked in a finally
block; this guarantees that the monkeypatched subprocess.run is restored and the
import cache is cleared even if the assertion in
test_default_repo_name_falls_back_when_git_unavailable fails.

Comment on lines +44 to +61
def test_contract_test_status_returns_one_when_git_fails(monkeypatch: pytest.MonkeyPatch, cfst_mod) -> None:
monkeypatch.setattr(
cfst_mod,
"_git_staged_names",
lambda _root: None,
)
assert cfst_mod._contract_test_status() == 1


def test_contract_test_status_returns_zero_when_only_irrelevant_staged(
monkeypatch: pytest.MonkeyPatch, cfst_mod
) -> None:
monkeypatch.setattr(
cfst_mod,
"_git_staged_names",
lambda _root: ["docs/README.md"],
)
assert cfst_mod._contract_test_status() == 0
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add the happy-path _contract_test_status() assertion.

The new status helper is only covered for “git failed” and “irrelevant staged paths”. We still need the primary branch where _git_staged_names() returns a contract-relevant path and _contract_test_status() must return 1, otherwise Block 2’s trigger path can regress unnoticed.

🧪 Suggested test
 def test_contract_test_status_returns_zero_when_only_irrelevant_staged(
     monkeypatch: pytest.MonkeyPatch, cfst_mod
 ) -> None:
     monkeypatch.setattr(
         cfst_mod,
         "_git_staged_names",
         lambda _root: ["docs/README.md"],
     )
     assert cfst_mod._contract_test_status() == 0
+
+
+def test_contract_test_status_returns_one_when_relevant_files_are_staged(
+    monkeypatch: pytest.MonkeyPatch, cfst_mod
+) -> None:
+    monkeypatch.setattr(
+        cfst_mod,
+        "_git_staged_names",
+        lambda _root: ["registry/index.json"],
+    )
+    assert cfst_mod._contract_test_status() == 1
As per coding guidelines "`tests/**/*.py`: Contract-first and integration tests: migration suites, bundle validation, and flakiness. Ensure changes to adapters or bridges have targeted coverage."
📝 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
def test_contract_test_status_returns_one_when_git_fails(monkeypatch: pytest.MonkeyPatch, cfst_mod) -> None:
monkeypatch.setattr(
cfst_mod,
"_git_staged_names",
lambda _root: None,
)
assert cfst_mod._contract_test_status() == 1
def test_contract_test_status_returns_zero_when_only_irrelevant_staged(
monkeypatch: pytest.MonkeyPatch, cfst_mod
) -> None:
monkeypatch.setattr(
cfst_mod,
"_git_staged_names",
lambda _root: ["docs/README.md"],
)
assert cfst_mod._contract_test_status() == 0
def test_contract_test_status_returns_one_when_git_fails(monkeypatch: pytest.MonkeyPatch, cfst_mod) -> None:
monkeypatch.setattr(
cfst_mod,
"_git_staged_names",
lambda _root: None,
)
assert cfst_mod._contract_test_status() == 1
def test_contract_test_status_returns_zero_when_only_irrelevant_staged(
monkeypatch: pytest.MonkeyPatch, cfst_mod
) -> None:
monkeypatch.setattr(
cfst_mod,
"_git_staged_names",
lambda _root: ["docs/README.md"],
)
assert cfst_mod._contract_test_status() == 0
def test_contract_test_status_returns_one_when_relevant_files_are_staged(
monkeypatch: pytest.MonkeyPatch, cfst_mod
) -> None:
monkeypatch.setattr(
cfst_mod,
"_git_staged_names",
lambda _root: ["registry/index.json"],
)
assert cfst_mod._contract_test_status() == 1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/tools/test_contract_first_smart_test.py` around lines 44 - 61, Add
a third "happy-path" unit test in
tests/unit/tools/test_contract_first_smart_test.py that patches
cfst_mod._git_staged_names to return a contract-relevant path (e.g.,
"contracts/some_contract.yaml" or any path your code treats as contract-related)
and assert cfst_mod._contract_test_status() == 1; reference the existing tests
for structure and reuse monkeypatch and the cfst_mod fixture, and ensure the new
test name makes intent clear (e.g.,
test_contract_test_status_returns_one_for_relevant_staged).

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

Labels

dependencies Pull requests that update a dependency file enhancement New feature or request

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

[Change] governance-04: Deterministic agent governance loading [Change] Local GitHub hierarchy cache for OpenSpec planning

1 participant