Conversation
* feat(cli): category groups and flat shims using real module Typer - Add category groups (code, backlog, project, spec, govern) with flatten same-name member - Sort commands under backlog/project groups A–Z - Fix flat shims to expose real module Typer so 'specfact sync bridge' and 'specfact plan update-idea' work - Add first-run init, module grouping, OpenSpec change for 0.40.x remove-flat-shims - Bump version to 0.39.0, CHANGELOG and OpenSpec updates Made-with: Cursor * Fix signature * fix: resolve module grouping regressions and stabilize CI tests * fix: keep uncategorized modules flat during grouped registration --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com>
* docs: add module-migration-02-bundle-extraction to CHANGE_ORDER.md * feat: implement module-migration-02 bundle extraction * fix(ci): checkout module bundles repo for test jobs * Fix test failures * fix(modules): load local bundle sources in compatibility aliases * fix: run worktree policy code in tests/CI and silence reexport deprecation - Prefer src/<name>/main.py over app.py when SPECFACT_REPO_ROOT is set so policy init uses worktree templates.py (SPECFACT_POLICY_TEMPLATES_DIR). - Policy engine module-package.yaml: version 0.1.5 and re-signed checksum. - conftest: set SPECFACT_REPO_ROOT, SPECFACT_POLICY_TEMPLATES_DIR; add bundle package roots when specfact-cli-modules present. - Policy engine integration tests: rely on conftest env, clear registry and re-register before invoke so loader uses worktree. - test_reexport_shims: filter deprecation warning for legacy analyze import. Made-with: Cursor * fix: defer specfact_backlog import in shims so CI can register bridges - backlog and policy_engine __init__.py: import specfact_backlog only in __getattr__ (cached), not at module load. Allows loading .src.adapters.* for bridge registration without requiring specfact_backlog installed. - Re-sign backlog and policy_engine module-package.yaml after init changes. - openspec: update module-migration-02 tasks.md. Made-with: Cursor * fix: defer bundle import in all module shims to fix CI collection errors - Apply deferred import (only in __getattr__, cached) to analyze, contract, drift, enforce, generate, import_cmd, migrate, patch_mode, plan, project, repro, sdd, spec, sync, validate. Matches backlog and policy_engine. - Prevents ImportError when tests import specfact_cli.modules.<name>.src.* without specfact_backlog/specfact_govern/specfact_project/specfact_spec installed (e.g. CI). Fixes 78 collection errors. - Re-sign all affected module-package.yaml manifests. Made-with: Cursor * fix(ci): include module shims in hatch cache key so CI uses current code * feat(modules): registry descriptions, --bump-version for publish, tasks and format fixes - Add description to registry index entries in publish-module.py (module search) - Add --bump-version patch|minor|major for bundle re-publish in publish-module.py - Format fixes in validate-modules-repo-sync.py (SIM108, B007) - Mark completed tasks in module-migration-02-bundle-extraction tasks.md - Update test for publish_bundle(bump_version=) signature Made-with: Cursor * Add missing migration tasks to the open change to completely isolate modules into specfact-cli-modules repo. * Add gap analysis and update changes * Update follow-up changes to avoid ambiguities and overlaps * docs: complete migration-02 section-18 parity and 17.8 gate evidence * docs: mark migration-02 import-categorization commit checkpoint done * Update change constraints and blockers for module migration * docs: add migration-05 issue #334 and complete task 17.10.4 * Update change constraints and blockers for module migration --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com>
Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com>
…317) (#341) * Prepare module-migration-03 removal of old built-in modules * feat(core): delete specfact-project module source from core (migration-03) Made-with: Cursor * feat(core): delete specfact-backlog module source from core (migration-03) Made-with: Cursor * feat(core): delete specfact-codebase module source from core (migration-03) Made-with: Cursor * feat(core): delete specfact-spec module source from core (migration-03) Made-with: Cursor * feat(core): delete specfact-govern module source from core (migration-03) Made-with: Cursor * chore(tests): skip tests for removed modules when source absent (migration-03) Add pytest.importorskip() for backlog, plan, sync, enforce, generate, patch_mode, import_cmd so tests are skipped when module source was removed from core. Preserves tests for later move to specfact-cli-modules. Update tasks.md and TDD_EVIDENCE.md for Task 10 completion. Made-with: Cursor * feat(bootstrap): remove flat shims and non-core module registrations (migration-03) - Remove _register_category_groups_and_shims (unconditional category/shim registration). - Trim CORE_MODULE_ORDER to 4 core: init, auth, module-registry, upgrade. - Add @beartype to _mount_installed_category_groups. - Category groups and flat shims only for installed bundles via _mount_installed_category_groups. Made-with: Cursor * docs(openspec): mark Task 11.4 done in tasks.md Made-with: Cursor * feat(cli): conditional category group mount from installed bundles (migration-03) - Add _RootCLIGroup (extends ProgressiveDisclosureGroup) with resolve_command override: unknown commands in KNOWN_BUNDLE_GROUP_OR_SHIM_NAMES show actionable error (not installed + specfact init / specfact module install). - Root app uses cls=_RootCLIGroup. Main help docstring adds init/module install hint for workflow bundles. Made-with: Cursor * docs(openspec): mark Task 12.4 done in tasks.md Made-with: Cursor * feat(init): enforce mandatory bundle selection and profile presets (migration-03) * Add module removal core tests * docs(openspec): record Task 14 module signing gate (migration-03) * feat: complete module-migration-03 core slimming and follow-up alignment (#317) * Fix format error * fix: handle detached HEAD registry branch selection and stabilize migration-03 CI tests --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com>
Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com>
#317) (#343) * Prepare module-migration-03 removal of old built-in modules * feat(core): delete specfact-project module source from core (migration-03) Made-with: Cursor * feat(core): delete specfact-backlog module source from core (migration-03) Made-with: Cursor * feat(core): delete specfact-codebase module source from core (migration-03) Made-with: Cursor * feat(core): delete specfact-spec module source from core (migration-03) Made-with: Cursor * feat(core): delete specfact-govern module source from core (migration-03) Made-with: Cursor * chore(tests): skip tests for removed modules when source absent (migration-03) Add pytest.importorskip() for backlog, plan, sync, enforce, generate, patch_mode, import_cmd so tests are skipped when module source was removed from core. Preserves tests for later move to specfact-cli-modules. Update tasks.md and TDD_EVIDENCE.md for Task 10 completion. Made-with: Cursor * feat(bootstrap): remove flat shims and non-core module registrations (migration-03) - Remove _register_category_groups_and_shims (unconditional category/shim registration). - Trim CORE_MODULE_ORDER to 4 core: init, auth, module-registry, upgrade. - Add @beartype to _mount_installed_category_groups. - Category groups and flat shims only for installed bundles via _mount_installed_category_groups. Made-with: Cursor * docs(openspec): mark Task 11.4 done in tasks.md Made-with: Cursor * feat(cli): conditional category group mount from installed bundles (migration-03) - Add _RootCLIGroup (extends ProgressiveDisclosureGroup) with resolve_command override: unknown commands in KNOWN_BUNDLE_GROUP_OR_SHIM_NAMES show actionable error (not installed + specfact init / specfact module install). - Root app uses cls=_RootCLIGroup. Main help docstring adds init/module install hint for workflow bundles. Made-with: Cursor * docs(openspec): mark Task 12.4 done in tasks.md Made-with: Cursor * feat(init): enforce mandatory bundle selection and profile presets (migration-03) * Add module removal core tests * docs(openspec): record Task 14 module signing gate (migration-03) * feat: complete module-migration-03 core slimming and follow-up alignment (#317) * Fix format error * fix: handle detached HEAD registry branch selection and stabilize migration-03 CI tests * Prepare module-migration-03 removal of old built-in modules * Prepare module-migration-03 removal of old built-in modules * chore(tests): skip tests for removed modules when source absent (migration-03) Add pytest.importorskip() for backlog, plan, sync, enforce, generate, patch_mode, import_cmd so tests are skipped when module source was removed from core. Preserves tests for later move to specfact-cli-modules. Update tasks.md and TDD_EVIDENCE.md for Task 10 completion. Made-with: Cursor * feat(bootstrap): remove flat shims and non-core module registrations (migration-03) - Remove _register_category_groups_and_shims (unconditional category/shim registration). - Trim CORE_MODULE_ORDER to 4 core: init, auth, module-registry, upgrade. - Add @beartype to _mount_installed_category_groups. - Category groups and flat shims only for installed bundles via _mount_installed_category_groups. Made-with: Cursor * docs(openspec): mark Task 11.4 done in tasks.md Made-with: Cursor * feat(cli): conditional category group mount from installed bundles (migration-03) - Add _RootCLIGroup (extends ProgressiveDisclosureGroup) with resolve_command override: unknown commands in KNOWN_BUNDLE_GROUP_OR_SHIM_NAMES show actionable error (not installed + specfact init / specfact module install). - Root app uses cls=_RootCLIGroup. Main help docstring adds init/module install hint for workflow bundles. Made-with: Cursor * docs(openspec): mark Task 12.4 done in tasks.md Made-with: Cursor * feat(init): enforce mandatory bundle selection and profile presets (migration-03) * Add module removal core tests * docs(openspec): record Task 14 module signing gate (migration-03) * feat: complete module-migration-03 core slimming and follow-up alignment (#317) * Fix format error * fix: handle detached HEAD registry branch selection and stabilize migration-03 CI tests * feat(core): remove auth module from core and route auth via backlog (migration-03) * docs(openspec): update migration-03 PR status and tracking * docs(openspec): finalize migration-03 checklist and defer non-blocking gates * Fix remaining auth findings and dependency in core cli --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com>
* feat: remove flat command shims from grouped registry * Finalize change module-migration-04 implementation --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com>
…R merge (#345) * Implement blockers to prepare for module-migration-03 change. * Update migration change * docs(openspec): close migration-05 PR tracking and change order --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com>
* feat(migration-06): core decoupling cleanup - boundary tests and inventory - Add test_core_does_not_import_from_bundle_packages boundary regression test - Update spec with ownership boundary and migration acceptance criteria - Add CORE_DECOUPLING_INVENTORY.md (keep/move/interface classification) - Record TDD evidence in TDD_EVIDENCE.md - Update docs/reference/architecture.md with core vs modules-repo boundary - Update openspec/CHANGE_ORDER.md status No move candidates identified; core already decoupled from bundle packages. Boundary test prevents future core->bundle coupling. Refs #338 Made-with: Cursor * chore(migration-06): mark all tasks complete Made-with: Cursor * feat(migration-06): extend scope - migrate package-specific artifacts per #338 - Add MIGRATION_REMOVAL_PLAN.md with phased removal of MIGRATE-tier code - Add test_core_modules_do_not_import_migrate_tier boundary test - Remove templates.bridge_templates (dead code; only tests used it) - Remove tests/unit/templates/test_bridge_templates.py - Update CORE_DECOUPLING_INVENTORY.md with removal status - Update spec with MIGRATE-tier enforcement and package-specific removal Phase 1 complete. Further MIGRATE-tier removal documented in plan. Refs #338 Made-with: Cursor * test(migration-06): move legacy sync tests out of core --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com>
* test: finalize module-migration-07 core test ownership cleanup * docs: mark module-migration-07 quality and PR tasks complete * test: fix CI isolation failures for project and persona merge * test: narrow migrated skips and restore core registry guardrails * test: stabilize core CI by refining skips and bootstrap checks * test: fix remaining PR failures via targeted core filtering * fix: harden module package checks against import-mode class identity * test: stabilize core slimming integration assertions --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com>
#376) - Create openspec/changes/agile-01-feature-hierarchy/ with proposal.md and tasks.md - Add Epics #256 (Architecture Layer Integration), #257 (AI IDE Integration), and #258 (Integration Governance and Dogfooding) to CHANGE_ORDER.md parent issues table - 25 GitHub Feature issues created (#351-#375), linked to their parent Epics - Feature label created; issue #185 closed (ceremony-cockpit-01, archived 2026-02-18) Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: align core docs and sync pending changes * fix: preserve partial staging in markdown autofix hook --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com>
…551) * chore(openspec): park 21 deferred change proposals Move proposals that are awaiting external signal (paying enterprise customer, third-party publisher, evidence corpus, etc.) from openspec/changes/ into a new openspec/parking-lot/ directory, preserving full content and history. This restores focus on the active core thesis (full-chain traceability for agile DevOps + AI IDEs) without abandoning prior thinking. Each parked proposal has an explicit un-park trigger documented in openspec/parking-lot/README.md. Parked groups: - enterprise-01..04 (4): no paying enterprise customer yet - finops-01..02 (2): no internal LLM workload to optimise yet - knowledge-01..02 (2): insufficient evidence corpus for distillation - marketplace-03..06 (4): no third-party publishers to onboard - security-01..02 (2): no customer-driven security review demand - review-resiliency-01-contracts (1): code-review module gap unproven - profile-02..03 (2): profile-01 not yet shipped - cli-val-01,02,05,06 (4): infrastructure ahead of demand; cli-val-03 and cli-val-04 remain active Active changes drop from 45 to 24. No CI workflows or production code referenced the parked directories; only comment-level references remain in already-shipped marketplace-06 helper scripts. openspec list is clean. Also adds a missing fenced-code language tag to a parked design.md to satisfy the markdownlint pre-commit hook. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(openspec): rewrite CHANGE_ORDER.md to reflect parked roadmap Reduce from 647 to 214 lines and reorganise around five active tracks instead of ten plan-derived addenda. The previous file accumulated historical narrative ("plan-derived addendum 2026-02-15", "addendum 2026-03-22", etc.) that belonged in git history, and listed many changes that no longer exist as folders here (moved to modules repo or already archived). New structure: - Status snapshot: 24 active / 21 parked / 104 archived with paths - Five active tracks (full-chain, AI IDE, profile, CLI reliability, other) - Modify queue: explicit list of proposals needing scope adjustment before implementation begins - Five waves (1: adjust scope, 2: foundations, 3: chain assembly, 4: evidence + AI surface, 5: proof + extensions) with auditable exit gates - Ownership authority table (kept; still load-bearing) - Pointers to parking-lot, archive, and the modules-repo companion plan Stale content removed: old "Implemented" table (51 archived items already in changes/archive/), four separate addendum sections, tables for backlog-scrum/kanban/safe that just said "moved to modules", a GitHub blocked-by relationships table that duplicated each track's own Blocked-by column, and references to changes that don't exist as active folders. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(openspec): fix Modify queue count "Five" -> "Six" PR #551 review caught the prose/table mismatch: the Modify queue intro said "Five active changes" but the table lists six (integration-01, architecture-02, telemetry-01, ai-integration-02, ai-integration-04, openspec-01). The table is the canonical list; all six adjustments are still required before implementation. Other count wording verified consistent: - "five independent tracks" (line 28) refers to Tracks A-E - correct. - Wave 1 references in the wave plan name the queue by reference, not by count. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(openspec): archive marketplace-06 (incorrectly parked, already shipped) Re-validation of parked changes against git history found that marketplace-06-ci-module-signing was substantially implemented in dev (PRs #501, #503, #504, #505 + commit a1dda6d) before the 2026-05-05 parking triage, but its tasks.md still read 0/N done so it was placed in parking-lot/ by mistake. Move the change to openspec/changes/archive/2026-05-06-marketplace-06-ci-module-signing/, mark all tasks [x] in bulk, and add an "Implementation history" banner documenting the actual merging PRs and verified on-disk deliverables (sign-modules-on-approval.yml, git-branch-module-signature-flag.sh, branch-aware verify-module-signatures gating). Update parking-lot/README.md (remove marketplace-06 row) and CHANGE_ORDER.md status snapshot (parked 21 -> 20, archived 104 -> 105). All 20 other core parked changes and all 9 modules-side parked changes were re-validated and have no implementation traces; they remain correctly parked. * fix(openspec): sync specs from archived marketplace-06 via openspec archive The previous commit (8443297) moved marketplace-06-ci-module-signing into the archive directory manually, which skipped the `openspec archive` step that syncs delta specs into main specs. Re-ran the proper flow: 1. Move change back to openspec/changes/marketplace-06-ci-module-signing/ 2. Run `openspec archive marketplace-06-ci-module-signing --yes` That command applied the delta specs to: - openspec/specs/ci-integration/spec.md (3 added) - openspec/specs/ci-module-signing-on-approval/spec.md (3 added, new file) Net effect on this PR is the proper inclusion of those spec updates; the archive folder content from 8443297 is unchanged (banner + checked tasks preserved). --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* Refine telemetry change to active opt-in * Address telemetry opt-in review annotations * Align telemetry payload field names * Clarify telemetry semantic payload contract * Align telemetry sanitizer transition spec * Track modules telemetry docs rollout * Tighten telemetry implementation tasks --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com>
* fix runtime module discovery reliability * fix runtime discovery review findings * fix installed module loader test fixture * fix review feedback on runtime discovery state isolation --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* Add module scope version diagnostics * Fix CI checks for module diagnostics * Address module diagnostics review findings * fix: apply CodeRabbit auto-fixes Fixed 5 file(s) based on 4 unresolved review comments. Co-authored-by: CodeRabbit <noreply@coderabbit.ai> * fix: tighten dependency fast-path identity checks * test: cover registry-id mismatch dependency path * style: run hatch format and apply formatter output * fix: resolve header typing regressions in strict type-check * test: require registry id file for already-satisfied bundle dependency assertion Bundle dependency installs now log at info only when the dependency directory includes .specfact-registry-id matching the marketplace id. Update the test fixture to mirror a normal install so CI matches installer behavior. Co-authored-by: Dom <djm81@users.noreply.github.com> --------- Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: CodeRabbit <noreply@coderabbit.ai> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
|
Strix is installed on this repository, but we could not run this PR security review because this workspace does not have an active plan. If you'd like to continue receiving code reviews, you can add a payment method or manage billing here. |
📝 WalkthroughModule Scope Version Diagnostics and Dependency EnforcementOpenSpec Change: User-Visible Behavior & CLI Surface
Contract/API ImpactNew public types & functions:
Internal module_installer.py changes (helper functions, not public API):
module_packages.py changes:
module_state.py changes:
Testing & Quality Gates
Documentation & Versioning
Additional Changes
WalkthroughThis PR implements module scope version diagnostics and enforces versioned module dependency constraints. It introduces ChangesModule Scope Diagnostics and Versioned Dependency Enforcement
HTTP Adapter Type Safety Hardening
Version Bump and Changelog
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes This PR adds substantial new functionality (versioned dependency enforcement across install/registration, new diagnostic command) with widespread integration across multiple modules. The HTTP adapter type-safety changes, while numerous, are homogeneous boilerplate. The core logic density is high in Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/specfact_cli/registry/module_installer.py (1)
871-911:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winError message for fresh installs suggests "Reinstall" when the issue is marketplace version availability.
Lines 906-911 call
_raise_if_dependency_version_mismatchafter a freshinstall_modulecall. If the marketplace version doesn't satisfy the constraint, the error message incorrectly suggests "Reinstall or upgrade the dependency" when the actual issue is that the available marketplace version doesn't meet the version requirement.Consider using a context-aware message or a separate check for post-install validation that provides more actionable guidance (e.g., "The installed version X does not satisfy the required constraint Y. Check if a compatible version is available in the marketplace.").
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/publish-module.py`:
- Around line 393-403: The current loop coerces non-string dependency entries
(and dict id values) to strings, which allows invalid IDs like "None" or "123"
to be published; change the validation so that for dict entries the "id" field
must be an instance of str and non-empty (use raw_id and raw_dependencies to
locate the check) and for non-dict entries reject any entry that is not a str
with a ValueError instead of coercing it; ensure dependency_ids only ever
receives already-validated, stripped strings and update the error messages to
mention invalid types/empty values.
In `@src/specfact_cli/registry/module_installer.py`:
- Around line 245-260: The current _dependency_version_satisfies catches
InvalidSpecifier/InvalidVersion but logs "Ignoring..." then returns False which
triggers a hard failure downstream; change this to genuinely skip malformed
comparisons by returning True on exception and update the
get_bridge_logger(__name__).debug message in _dependency_version_satisfies to
state that the malformed version/specifier is being skipped (e.g., "Skipping
malformed bundle dependency version comparison...") so behavior and log align;
references: _dependency_version_satisfies and callers like
_raise_if_dependency_version_mismatch.
In `@src/specfact_cli/registry/module_packages.py`:
- Around line 548-585: The registration code
(_versioned_module_dependency_problem) swallows InvalidVersion/InvalidSpecifier
and treats malformed version comparisons as non-blocking; make
module_installer._dependency_version_satisfies mirror that tolerant behavior so
installer and registrar are consistent: catch InvalidVersion and
InvalidSpecifier in _dependency_version_satisfies, log a debug-level message
(similar to get_bridge_logger(...).debug usage in
_versioned_module_dependency_problem) and return True (treat as satisfied)
instead of False/raising, ensuring the function signature and callers remain
unchanged.
In `@src/specfact_cli/registry/module_state.py`:
- Around line 95-101: The current membership check uses a set union
{*module_dependencies, *versioned_dependencies} which requires items in
module_dependencies to be hashable and can raise TypeError for dict/list
entries; change the logic to perform safe string-based comparisons instead:
build a list of stringified module_dependencies (e.g., module_dependencies_str =
[str(dep) for dep in getattr(meta, "module_dependencies", [])]) reuse the
existing versioned_dependencies list, and replace the set-based check with a
safe condition like if module_id in module_dependencies_str or module_id in
versioned_dependencies to append to dependents; reference the symbols
module_dependencies, versioned_dependencies, module_id, meta, dependents, and
name when making the change.
🪄 Autofix (Beta)
❌ Autofix failed (check again to retry)
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: CHILL
Plan: Pro
Run ID: 679026ca-fe14-4468-ade1-6adab329657d
📒 Files selected for processing (37)
CHANGELOG.mddocs/module-system/installing-modules.mddocs/module-system/module-marketplace.mdopenspec/CHANGE_ORDER.mdopenspec/changes/module-scope-version-diagnostics/.openspec.yamlopenspec/changes/module-scope-version-diagnostics/TDD_EVIDENCE.mdopenspec/changes/module-scope-version-diagnostics/design.mdopenspec/changes/module-scope-version-diagnostics/proposal.mdopenspec/changes/module-scope-version-diagnostics/specs/module-installation/spec.mdopenspec/changes/module-scope-version-diagnostics/specs/module-packages/spec.mdopenspec/changes/module-scope-version-diagnostics/specs/module-scope-diagnostics/spec.mdopenspec/changes/module-scope-version-diagnostics/tasks.mdpyproject.tomlscripts/publish-module.pyscripts/verify-modules-signature.pysetup.pysrc/__init__.pysrc/specfact_cli/__init__.pysrc/specfact_cli/adapters/ado.pysrc/specfact_cli/adapters/github.pysrc/specfact_cli/cli.pysrc/specfact_cli/modules/module_registry/module-package.yamlsrc/specfact_cli/modules/module_registry/src/commands.pysrc/specfact_cli/registry/module_installer.pysrc/specfact_cli/registry/module_packages.pysrc/specfact_cli/registry/module_state.pysrc/specfact_cli/sync/bridge_sync.pysrc/specfact_cli/validators/change_proposal_integration.pytests/unit/adapters/test_ado_backlog_adapter.pytests/unit/modules/module_registry/test_commands.pytests/unit/registry/test_module_installer.pytests/unit/scripts/test_publish_module_bundle.pytests/unit/specfact_cli/modules/test_module_upgrade_improvements.pytests/unit/specfact_cli/registry/test_module_dependencies.pytests/unit/specfact_cli/registry/test_module_packages.pytests/unit/specfact_cli/registry/test_versioned_bundle_deps.pytests/unit/validators/test_bundle_dependency_install.py
💤 Files with no reviewable changes (1)
- scripts/verify-modules-signature.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (21)
**/*.py
📄 CodeRabbit inference engine (.cursor/rules/python-github-rules.mdc)
**/*.py: Maintain minimum 80% test coverage, with 100% coverage for critical paths in Python code
Use clear naming and self-documenting code, preferring clear names over comments
Ensure each function/class has a single clear purpose (Single Responsibility Principle)
Extract common patterns to avoid code duplication (DRY principle)
Apply SOLID object-oriented design principles in Python code
Use type hints everywhere in Python code and enable basedpyright strict mode
Use Pydantic models for data validation and serialization in Python
Use async/await for I/O operations in Python code
Use context managers for resource management in Python
Use dataclasses for simple data containers in Python
Enforce maximum line length of 120 characters in Python code
Use 4 spaces for indentation in Python code (no tabs)
Use 2 blank lines between classes and 1 blank line between methods in Python
Organize imports in order: Standard library → Third party → Local in Python files
Use snake_case for variables and functions in Python
Use PascalCase for class names in Python
Use UPPER_SNAKE_CASE for constants in Python
Use leading underscore (_) for private methods in Python classes
Use snake_case for Python file names
Enable basedpyright strict mode with strict type checking configuration in Python
Use Google-style docstrings for functions and classes in Python
Include comprehensive exception handling with specific exception types in Python code
Use logging with structured context (extra parameters) instead of print statements
Use retry logic with tenacity decorators (@retry) for operations that might fail
Use Pydantic BaseSettings for environment-based configuration in Python
Validate user input using Pydantic validators in Python models
Use@lru_cacheand Redis-based caching for expensive calculations in Python
Run code formatting with Black (120 character line length) and isort in Python
Run type checking with basedpyright on all Python files
Run linting with ruff and pylint on all Pyth...
Files:
src/__init__.pysrc/specfact_cli/__init__.pysrc/specfact_cli/cli.pysetup.pytests/unit/specfact_cli/modules/test_module_upgrade_improvements.pytests/unit/specfact_cli/registry/test_versioned_bundle_deps.pytests/unit/scripts/test_publish_module_bundle.pytests/unit/specfact_cli/registry/test_module_packages.pytests/unit/validators/test_bundle_dependency_install.pyscripts/publish-module.pytests/unit/adapters/test_ado_backlog_adapter.pysrc/specfact_cli/validators/change_proposal_integration.pytests/unit/modules/module_registry/test_commands.pysrc/specfact_cli/registry/module_state.pysrc/specfact_cli/sync/bridge_sync.pysrc/specfact_cli/adapters/ado.pytests/unit/specfact_cli/registry/test_module_dependencies.pysrc/specfact_cli/modules/module_registry/src/commands.pytests/unit/registry/test_module_installer.pysrc/specfact_cli/registry/module_packages.pysrc/specfact_cli/adapters/github.pysrc/specfact_cli/registry/module_installer.py
{src/__init__.py,pyproject.toml,setup.py}
📄 CodeRabbit inference engine (.cursor/rules/python-github-rules.mdc)
{src/__init__.py,pyproject.toml,setup.py}: Update src/init.py first as primary source of truth for package version, then pyproject.toml and setup.py
Maintain version synchronization across src/init.py, pyproject.toml, and setup.py
Files:
src/__init__.pypyproject.tomlsetup.py
src/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/spec-fact-cli-rules.mdc)
src/**/*.py: All code changes must be followed by running the full test suite using the smart test system.
All Python files in src/ and tools/ directories must have corresponding test files in tests/ directory. If you modify src/common/logger_setup.py, you MUST have tests/unit/common/test_logger_setup.py. NO EXCEPTIONS - even small changes require tests.
All new Python runtime code files must have corresponding test files created BEFORE committing the code. NO EXCEPTIONS - no code without tests.
Test Coverage Validation: Run hatch run smart-test-unit for modified files, hatch run smart-test-folder for modified directories, and hatch run smart-test-full before committing. ALL TESTS MUST PASS.
All components must support TEST_MODE=true environment variable with test-specific behavior defined as: if os.environ.get('TEST_MODE') == 'true': # test-specific behavior
Use src/common/logger_setup.py for all logging via: from common.logger_setup import get_logger; logger = get_logger(name)
Use src/common/redis_client.py with fallback for Redis operations via: from common.redis_client import get_redis_client; redis_client = get_redis_client()
Type checking must pass with no errors using: mypy .
Test coverage must meet or exceed 80% total coverage. New code must have corresponding tests. Modified code must maintain or improve coverage. Critical paths must have 100% coverage.
Use Pydantic v2 validation for all context and data schemas.Add/update contracts on new or modified public APIs, stateful classes and adapters using
icontractdecorators andbeartyperuntime type checks
src/**/*.py: Meaningful Naming — identifiers reveal intent; avoid abbreviations. Identifiers insrc/must usesnake_case(modules/functions),PascalCase(classes),UPPER_SNAKE_CASE(constants). Avoid single-letter names outside short loop variables.
KISS — keep functions and modules small and single-purpose. Maximum function length: 120 lines (Phase A error threshold). Maximum cyclomati...
Files:
src/__init__.pysrc/specfact_cli/__init__.pysrc/specfact_cli/cli.pysrc/specfact_cli/validators/change_proposal_integration.pysrc/specfact_cli/registry/module_state.pysrc/specfact_cli/sync/bridge_sync.pysrc/specfact_cli/adapters/ado.pysrc/specfact_cli/modules/module_registry/src/commands.pysrc/specfact_cli/registry/module_packages.pysrc/specfact_cli/adapters/github.pysrc/specfact_cli/registry/module_installer.py
@(src|tests)/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/spec-fact-cli-rules.mdc)
Linting must pass with no errors using: pylint src tests
Files:
src/__init__.pysrc/specfact_cli/__init__.pysrc/specfact_cli/cli.pytests/unit/specfact_cli/modules/test_module_upgrade_improvements.pytests/unit/specfact_cli/registry/test_versioned_bundle_deps.pytests/unit/scripts/test_publish_module_bundle.pytests/unit/specfact_cli/registry/test_module_packages.pytests/unit/validators/test_bundle_dependency_install.pytests/unit/adapters/test_ado_backlog_adapter.pysrc/specfact_cli/validators/change_proposal_integration.pytests/unit/modules/module_registry/test_commands.pysrc/specfact_cli/registry/module_state.pysrc/specfact_cli/sync/bridge_sync.pysrc/specfact_cli/adapters/ado.pytests/unit/specfact_cli/registry/test_module_dependencies.pysrc/specfact_cli/modules/module_registry/src/commands.pytests/unit/registry/test_module_installer.pysrc/specfact_cli/registry/module_packages.pysrc/specfact_cli/adapters/github.pysrc/specfact_cli/registry/module_installer.py
{pyproject.toml,setup.py,src/__init__.py}
📄 CodeRabbit inference engine (.cursor/rules/testing-and-build-guide.mdc)
Manually update version numbers in pyproject.toml, setup.py, and src/init.py when making a formal version change
Files:
src/__init__.pypyproject.tomlsetup.py
**/*.{py,pyi}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{py,pyi}: After any code changes, follow these steps in order: (1) Apply linting and formatting to ensure code quality:hatch run format, (2) Type checking:hatch run type-check(basedpyright), (3) Contract-first approach: Runhatch run contract-testfor contract validation, (4) Run full test suite:hatch test --cover -v, (5) Verify all tests pass and contracts are satisfied, (6) Fix any issues and repeat steps until all tests pass
All public APIs must have@icontractdecorators and@beartypetype checking
Use Pydantic models for all data structures with data validation
Only write high-value comments if at all. Avoid talking to the user through comments
Files:
src/__init__.pysrc/specfact_cli/__init__.pysrc/specfact_cli/cli.pysetup.pytests/unit/specfact_cli/modules/test_module_upgrade_improvements.pytests/unit/specfact_cli/registry/test_versioned_bundle_deps.pytests/unit/scripts/test_publish_module_bundle.pytests/unit/specfact_cli/registry/test_module_packages.pytests/unit/validators/test_bundle_dependency_install.pyscripts/publish-module.pytests/unit/adapters/test_ado_backlog_adapter.pysrc/specfact_cli/validators/change_proposal_integration.pytests/unit/modules/module_registry/test_commands.pysrc/specfact_cli/registry/module_state.pysrc/specfact_cli/sync/bridge_sync.pysrc/specfact_cli/adapters/ado.pytests/unit/specfact_cli/registry/test_module_dependencies.pysrc/specfact_cli/modules/module_registry/src/commands.pytests/unit/registry/test_module_installer.pysrc/specfact_cli/registry/module_packages.pysrc/specfact_cli/adapters/github.pysrc/specfact_cli/registry/module_installer.py
**/*.{md,mdc}
📄 CodeRabbit inference engine (.cursor/rules/markdown-rules.mdc)
**/*.{md,mdc}: Do not use more than one consecutive blank line anywhere in the document (MD012: No Multiple Consecutive Blank Lines)
Fenced code blocks should be surrounded by blank lines (MD031: Fenced Code Blocks)
Lists should be surrounded by blank lines (MD032: Lists)
Files must end with a single empty line (MD047: Files Must End With Single Newline)
Lines should not have trailing spaces (MD009: No Trailing Spaces)
Use asterisks (**) for strong emphasis, not underscores (__) (MD050: Strong Style)
Fenced code blocks must have a language specified (MD040: Fenced Code Language)
Headers should increment by one level at a time (MD001: Header Increment)
Headers should be surrounded by blank lines (MD022: Headers Should Be Surrounded By Blank Lines)
Only one top-level header (H1) is allowed per document (MD025: Single H1 Header)
Use consistent list markers, preferring dashes (-) for unordered lists (MD004: List Style)
Nested unordered list items should be indented consistently, typically by 2 spaces (MD007: Unordered List Indentation)
Use exactly one space after the list marker (e.g., -, *, +, 1.) (MD030: Spaces After List Markers)
Use incrementing numbers for ordered lists (MD029: Ordered List Item Prefix)
Enclose bare URLs in angle brackets or format them as links (MD034: Bare URLs)
Don't use spaces immediately inside code spans (MD038: Spaces Inside Code Spans)
Use consistent indentation (usually 2 or 4 spaces) throughout markdown files
Keep line length under 120 characters in markdown files
Use reference-style links for better readability in markdown files
Use a trailing slash for directory paths in markdown files
Ensure proper escaping of special characters in markdown files
Files:
openspec/changes/module-scope-version-diagnostics/tasks.mdopenspec/changes/module-scope-version-diagnostics/specs/module-installation/spec.mdopenspec/CHANGE_ORDER.mdopenspec/changes/module-scope-version-diagnostics/design.mdopenspec/changes/module-scope-version-diagnostics/specs/module-packages/spec.mdopenspec/changes/module-scope-version-diagnostics/proposal.mddocs/module-system/installing-modules.mdopenspec/changes/module-scope-version-diagnostics/specs/module-scope-diagnostics/spec.mdopenspec/changes/module-scope-version-diagnostics/TDD_EVIDENCE.mddocs/module-system/module-marketplace.mdCHANGELOG.md
**/*.md
📄 CodeRabbit inference engine (.cursorrules)
Avoid markdown linting errors (refer to markdown-rules)
Files:
openspec/changes/module-scope-version-diagnostics/tasks.mdopenspec/changes/module-scope-version-diagnostics/specs/module-installation/spec.mdopenspec/CHANGE_ORDER.mdopenspec/changes/module-scope-version-diagnostics/design.mdopenspec/changes/module-scope-version-diagnostics/specs/module-packages/spec.mdopenspec/changes/module-scope-version-diagnostics/proposal.mddocs/module-system/installing-modules.mdopenspec/changes/module-scope-version-diagnostics/specs/module-scope-diagnostics/spec.mdopenspec/changes/module-scope-version-diagnostics/TDD_EVIDENCE.mddocs/module-system/module-marketplace.mdCHANGELOG.md
openspec/changes/**/*.md
📄 CodeRabbit inference engine (.cursorrules)
For
/opsx:archive(Archive change): Include module signing and cleanup in final tasks. Agents MUST runopenspec archive <change-id>from repo root (no manualmvunderopenspec/changes/archive/)
Files:
openspec/changes/module-scope-version-diagnostics/tasks.mdopenspec/changes/module-scope-version-diagnostics/specs/module-installation/spec.mdopenspec/changes/module-scope-version-diagnostics/design.mdopenspec/changes/module-scope-version-diagnostics/specs/module-packages/spec.mdopenspec/changes/module-scope-version-diagnostics/proposal.mdopenspec/changes/module-scope-version-diagnostics/specs/module-scope-diagnostics/spec.mdopenspec/changes/module-scope-version-diagnostics/TDD_EVIDENCE.md
openspec/**/{proposal.md,tasks.md,design.md,spec.md}
📄 CodeRabbit inference engine (.cursor/rules/automatic-openspec-workflow.mdc)
openspec/**/{proposal.md,tasks.md,design.md,spec.md}: Applyopenspec/config.yamlproject context and per-artifact rules (for proposal, specs, design, tasks) when creating or updating any OpenSpec change artifact in the specfact-cli codebase
After implementation, validate the change withopenspec validate <change-id> --strict; fix validation errors in proposal, specs, design, or tasks and re-validate until passing before considering the change complete
Files:
openspec/changes/module-scope-version-diagnostics/tasks.mdopenspec/changes/module-scope-version-diagnostics/specs/module-installation/spec.mdopenspec/changes/module-scope-version-diagnostics/design.mdopenspec/changes/module-scope-version-diagnostics/specs/module-packages/spec.mdopenspec/changes/module-scope-version-diagnostics/proposal.mdopenspec/changes/module-scope-version-diagnostics/specs/module-scope-diagnostics/spec.md
openspec/**/*.md
⚙️ CodeRabbit configuration file
openspec/**/*.md: Treat as specification source of truth: proposal/tasks/spec deltas vs. code behavior,
CHANGE_ORDER consistency, and scenario coverage. Surface drift between OpenSpec and
implementation.
Files:
openspec/changes/module-scope-version-diagnostics/tasks.mdopenspec/changes/module-scope-version-diagnostics/specs/module-installation/spec.mdopenspec/CHANGE_ORDER.mdopenspec/changes/module-scope-version-diagnostics/design.mdopenspec/changes/module-scope-version-diagnostics/specs/module-packages/spec.mdopenspec/changes/module-scope-version-diagnostics/proposal.mdopenspec/changes/module-scope-version-diagnostics/specs/module-scope-diagnostics/spec.mdopenspec/changes/module-scope-version-diagnostics/TDD_EVIDENCE.md
src/specfact_cli/**/*.py
⚙️ CodeRabbit configuration file
src/specfact_cli/**/*.py: Focus on modular CLI architecture: lazy module loading, registry/bootstrap patterns, and
dependency direction. Flag breaking changes to public APIs, Pydantic models, and resource
bundling. Verify@icontract+@beartypeon public surfaces; prefer centralized logging
(get_bridge_logger) over print().
Files:
src/specfact_cli/__init__.pysrc/specfact_cli/cli.pysrc/specfact_cli/validators/change_proposal_integration.pysrc/specfact_cli/registry/module_state.pysrc/specfact_cli/sync/bridge_sync.pysrc/specfact_cli/adapters/ado.pysrc/specfact_cli/modules/module_registry/src/commands.pysrc/specfact_cli/registry/module_packages.pysrc/specfact_cli/adapters/github.pysrc/specfact_cli/registry/module_installer.py
**/*cli*.{py,pyi}
📄 CodeRabbit inference engine (.cursorrules)
Commands should follow typer patterns with rich console output
Files:
src/specfact_cli/cli.py
**/*.yaml
📄 CodeRabbit inference engine (.cursor/rules/spec-fact-cli-rules.mdc)
YAML files must pass linting using: hatch run yaml-lint with relaxed policy.
Files:
src/specfact_cli/modules/module_registry/module-package.yaml
**/*.{yml,yaml}
📄 CodeRabbit inference engine (.cursor/rules/testing-and-build-guide.mdc)
Validate YAML configuration files locally using
hatch run yaml-lintbefore committing
**/*.{yml,yaml}: Format all YAML and workflow files usinghatch run yaml-fix-allbefore committing
Use Prettier to fix whitespace, indentation, and final newline across YAML files
Use yamllint with the repo .yamllint configuration (line-length 140, trailing spaces and final newline enforced) to lint non-workflow YAML files
Files:
src/specfact_cli/modules/module_registry/module-package.yaml
pyproject.toml
📄 CodeRabbit inference engine (.cursorrules)
When updating the version in
pyproject.toml, ensure it's newer than the latest PyPI version. The CI/CD pipeline will automatically publish to PyPI only if the new version is greater than the published version
Files:
pyproject.toml
docs/**/*.md
📄 CodeRabbit inference engine (.cursor/rules/spec-fact-cli-rules.mdc)
Update architecture documentation in docs/ for architecture changes, state machine documentation for FSM modifications, interface documentation for API changes, and configuration guides for configuration changes. DO NOT create internal docs in specfact-cli repo folder that should not be visible to end users; use the respective internal repository instead.
Files:
docs/module-system/installing-modules.mddocs/module-system/module-marketplace.md
⚙️ CodeRabbit configuration file
docs/**/*.md: User-facing accuracy: CLI examples match current behavior; preserve Jekyll front matter;
call out when README/docs index need sync.
Files:
docs/module-system/installing-modules.mddocs/module-system/module-marketplace.md
**/test_*.py
📄 CodeRabbit inference engine (.cursor/rules/python-github-rules.mdc)
**/test_*.py: Write tests first in test-driven development (TDD) using the Red-Green-Refactor cycle
Ensure each test is independent and repeatable with no shared state between tests
Organize Python imports in tests using unittest.mock for Mock and patch
Use setup_method() for test initialization and Arrange-Act-Assert pattern in test files
Use@pytest.mark.asynciodecorator for async test functions in Python
Organize test files in structure: tests/unit/, tests/integration/, tests/e2e/ by module
Files:
tests/unit/specfact_cli/modules/test_module_upgrade_improvements.pytests/unit/specfact_cli/registry/test_versioned_bundle_deps.pytests/unit/scripts/test_publish_module_bundle.pytests/unit/specfact_cli/registry/test_module_packages.pytests/unit/validators/test_bundle_dependency_install.pytests/unit/adapters/test_ado_backlog_adapter.pytests/unit/modules/module_registry/test_commands.pytests/unit/specfact_cli/registry/test_module_dependencies.pytests/unit/registry/test_module_installer.py
tests/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/spec-fact-cli-rules.mdc)
Tests must be meaningful and test actual functionality, cover both success and failure cases, be independent and repeatable, and have clear, descriptive names. NO EXCEPTIONS - no placeholder or empty tests.
tests/**/*.py: Trim low-value unit tests when a contract covers the same assertion (type/shape/raises on negative checks)
Delete tests that only assert input validation, datatype/shape enforcement, or raises on negative conditions now guarded by contracts and runtime typing
Convert repeated edge-case permutations into one Hypothesis property with contracts acting as oraclesSecret redaction via
LoggerSetup.redact_secretsmust be covered by unit tests
Files:
tests/unit/specfact_cli/modules/test_module_upgrade_improvements.pytests/unit/specfact_cli/registry/test_versioned_bundle_deps.pytests/unit/scripts/test_publish_module_bundle.pytests/unit/specfact_cli/registry/test_module_packages.pytests/unit/validators/test_bundle_dependency_install.pytests/unit/adapters/test_ado_backlog_adapter.pytests/unit/modules/module_registry/test_commands.pytests/unit/specfact_cli/registry/test_module_dependencies.pytests/unit/registry/test_module_installer.py
⚙️ CodeRabbit configuration file
tests/**/*.py: Contract-first testing: meaningful scenarios, not redundant assertions already covered by
contracts. Flag flakiness, environment coupling, and missing coverage for changed behavior.
Files:
tests/unit/specfact_cli/modules/test_module_upgrade_improvements.pytests/unit/specfact_cli/registry/test_versioned_bundle_deps.pytests/unit/scripts/test_publish_module_bundle.pytests/unit/specfact_cli/registry/test_module_packages.pytests/unit/validators/test_bundle_dependency_install.pytests/unit/adapters/test_ado_backlog_adapter.pytests/unit/modules/module_registry/test_commands.pytests/unit/specfact_cli/registry/test_module_dependencies.pytests/unit/registry/test_module_installer.py
CHANGELOG.md
📄 CodeRabbit inference engine (.cursor/rules/python-github-rules.mdc)
Include new version entries at the top of CHANGELOG.md when updating versions
Update CHANGELOG.md with all code changes as part of version control requirements.
Update CHANGELOG.md to document all significant changes under Added, Fixed, Changed, or Removed sections when making a version change
Files:
CHANGELOG.md
scripts/**/*.py
⚙️ CodeRabbit configuration file
scripts/**/*.py: Deterministic tooling: subprocess safety, Hatch integration, and parity with documented
quality gates (format, type-check, module signing).
Files:
scripts/publish-module.py
🪛 LanguageTool
openspec/changes/module-scope-version-diagnostics/design.md
[style] ~3-~3: This phrase is redundant. Consider writing “duplicates” or “copies”.
Context: ...e priority, but diagnostics will expose duplicate copies and version drift. Dependency enforceme...
(DUPLICATE_COPY)
openspec/changes/module-scope-version-diagnostics/proposal.md
[style] ~3-~3: To elevate your writing, try using a synonym here.
Context: ...d implicit development source roots are hard to see, and declared module dependency ...
(HARD_TO)
docs/module-system/installing-modules.md
[style] ~124-~124: This phrase is redundant. Consider writing “duplicates” or “copies”.
Context: ...-only and reports effective vs shadowed duplicate copies, exact manifest versions, paths, enable...
(DUPLICATE_COPY)
openspec/changes/module-scope-version-diagnostics/TDD_EVIDENCE.md
[grammar] ~28-~28: Ensure spelling is correct
Context: ... the passing review run. ## Real-World Tmp Smoke - Created a temporary git repo w...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[uncategorized] ~40-~40: The official name of this software platform is spelled with a capital “H”.
Context: ... in src/specfact_cli/adapters/ado.py, src/specfact_cli/adapters/github.py, and `src/specfact_cli/validators/c...
(GITHUB)
docs/module-system/module-marketplace.md
[style] ~59-~59: This phrase is redundant. Consider writing “duplicates” or “copies”.
Context: ...e doctor` additionally reports shadowed duplicate copies, exact manifest versions, paths, enable...
(DUPLICATE_COPY)
🔀 Multi-repo context nold-ai/specfact-cli-modules
[::nold-ai/specfact-cli-modules::] tools/validate_repo_manifests.py:256–275 — repository contains validation logic that expects manifest.bundle_dependencies to be a list and checks referenced module IDs exist in the registry. This aligns with the PR’s stricter parsing/validation of bundle_dependencies.
[::nold-ai/specfact-cli-modules::] .github/workflows/publish-modules.yml:393–394 — the publish workflow copies manifest["bundle_dependencies"] into registry entries; the PR’s scripts/publish-module.py change (normalizing/validating bundle_dependencies before writing registry entries) may affect or be redundant with this workflow behavior.
[::nold-ai/specfact-cli-modules::] registry/index.json — multiple registry entries already include a bundle_dependencies array (some empty, some populated). The PR’s enforcement of versioned bundle dependencies and installer behavior means registry entries and module-package.yaml bundle_dependencies must match expected formats; tests in this repo (below) enforce that.
[::nold-ai/specfact-cli-modules::] tests/unit/test_registry_manifest_bundle_dependencies.py & tests/unit/test_validate_repo_manifests_bundle_deps.py — unit tests in this repo assert registry.bundle_dependencies must be a list and must match each package module-package.yaml bundle_dependencies. The PR’s change to serialize bundle_dependencies as list-of-ids and to reject malformed objects should be compatible but will require registry/package alignment.
[::nold-ai/specfact-cli-modules::] packages/*/module-package.yaml (e.g., packages/specfact-code-review/module-package.yaml, packages/specfact-codebase/module-package.yaml, packages/specfact-project/module-package.yaml) — these manifest files define bundle_dependencies (some empty). The PR’s new handling (including possible version specifiers in bundle_dependencies entries) means manifests in this repo may need to include only allowed shapes (string ids or dicts with id) and, if versioned constraints are used, follow the expected syntax.
[::nold-ai/specfact-cli-modules::] docs/reference/module-security.md — documents module_dependencies_versioned and pip_dependencies_versioned; matches PR additions enforcing versioned dependency checks during registration/installation.
Summary: This repository contains module manifests, registry entries, CI publish workflow, and tests that validate bundle_dependencies shape and alignment between manifests and registry. The PR’s stricter parsing/validation and support for versioned bundle/module dependencies touches the same data and CI paths; ensure manifests and registry.index.json entries conform to the new normalized/list-of-ids shape (and that publish workflow produces matching registry entries). Tests in this repo already assert bundle_dependencies alignment and will be relevant when bumping module-package.yaml entries to include version specifiers.
🔇 Additional comments (34)
pyproject.toml (1)
7-7: LGTM!setup.py (1)
10-10: LGTM!src/__init__.py (1)
6-6: LGTM!src/specfact_cli/__init__.py (1)
48-48: LGTM!src/specfact_cli/modules/module_registry/module-package.yaml (1)
2-2: LGTM!Also applies to: 20-21
CHANGELOG.md (1)
13-47: LGTM!src/specfact_cli/adapters/github.py (1)
564-567: LGTM!Also applies to: 1235-1238, 1501-1504, 1595-1598, 1604-1606, 1639-1642, 1663-1666, 1671-1671, 1681-1684, 1764-1767, 1974-1977, 1992-1994, 2630-2633, 2768-2771, 2983-2986, 2990-2990, 3252-3255
src/specfact_cli/adapters/ado.py (1)
1628-1628: LGTM!Also applies to: 1942-1942, 1956-1956, 1976-1976, 2216-2216, 2673-2673, 3481-3481, 3785-3785, 3805-3805, 3823-3823, 3837-3839
src/specfact_cli/validators/change_proposal_integration.py (1)
19-19: LGTM!Also applies to: 169-169, 191-191
src/specfact_cli/sync/bridge_sync.py (1)
2448-2451: LGTM!Also applies to: 2684-2687
tests/unit/adapters/test_ado_backlog_adapter.py (1)
776-776: LGTM!Also applies to: 785-785
tests/unit/modules/module_registry/test_commands.py (1)
12-12: LGTM!Also applies to: 74-154, 565-565, 573-573
tests/unit/specfact_cli/registry/test_module_dependencies.py (1)
7-7: LGTM!Also applies to: 10-10, 51-145
tests/unit/specfact_cli/registry/test_module_packages.py (1)
658-690: LGTM!tests/unit/registry/test_module_installer.py (1)
143-143: LGTM!Also applies to: 159-203, 205-242
tests/unit/scripts/test_publish_module_bundle.py (1)
105-122: LGTM!Also applies to: 124-152
tests/unit/specfact_cli/registry/test_versioned_bundle_deps.py (1)
13-15: LGTM!Also applies to: 78-95
tests/unit/specfact_cli/modules/test_module_upgrade_improvements.py (1)
259-260: LGTM!tests/unit/validators/test_bundle_dependency_install.py (1)
11-11: LGTM!Also applies to: 146-146
src/specfact_cli/registry/module_installer.py (3)
77-81: LGTM!
192-228: LGTM!
263-275: LGTM!src/specfact_cli/registry/module_packages.py (5)
349-381: LGTM!
503-545: LGTM!
627-627: LGTM!Also applies to: 634-637
657-660: LGTM!Also applies to: 690-695
1619-1619: LGTM!Also applies to: 1634-1636
openspec/changes/module-scope-version-diagnostics/.openspec.yaml (1)
1-2: LGTM!openspec/changes/module-scope-version-diagnostics/specs/module-installation/spec.md (1)
1-21: LGTM!openspec/changes/module-scope-version-diagnostics/specs/module-scope-diagnostics/spec.md (1)
1-21: LGTM!openspec/changes/module-scope-version-diagnostics/specs/module-packages/spec.md (1)
1-21: LGTM!openspec/changes/module-scope-version-diagnostics/TDD_EVIDENCE.md (1)
1-42: LGTM!openspec/CHANGE_ORDER.md (1)
11-11: LGTM!Also applies to: 28-28, 93-93
openspec/changes/module-scope-version-diagnostics/tasks.md (1)
1-25: LGTM!
| for entry in raw_dependencies: | ||
| if isinstance(entry, dict): | ||
| raw_id = entry.get("id") | ||
| if raw_id is None or not str(raw_id).strip(): | ||
| raise ValueError(f"bundle_dependencies object entry must include non-empty 'id'; got {entry!r}") | ||
| dependency_ids.append(str(raw_id).strip()) | ||
| continue | ||
| dependency_id = str(entry).strip() | ||
| if dependency_id: | ||
| dependency_ids.append(dependency_id) | ||
| return dependency_ids |
There was a problem hiding this comment.
Reject non-string bundle dependency entries instead of coercing them
Line 400 coerces arbitrary values to strings. That can publish invalid IDs like "None"/"123" into registry metadata and break dependency enforcement downstream.
Proposed fix
for entry in raw_dependencies:
if isinstance(entry, dict):
raw_id = entry.get("id")
if raw_id is None or not str(raw_id).strip():
raise ValueError(f"bundle_dependencies object entry must include non-empty 'id'; got {entry!r}")
dependency_ids.append(str(raw_id).strip())
continue
- dependency_id = str(entry).strip()
- if dependency_id:
- dependency_ids.append(dependency_id)
+ if not isinstance(entry, str):
+ raise ValueError(
+ "bundle_dependencies entries must be strings or objects with non-empty 'id'; "
+ f"got {type(entry).__name__}: {entry!r}"
+ )
+ dependency_id = entry.strip()
+ if not dependency_id:
+ raise ValueError("bundle_dependencies string entries must be non-empty")
+ dependency_ids.append(dependency_id)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/publish-module.py` around lines 393 - 403, The current loop coerces
non-string dependency entries (and dict id values) to strings, which allows
invalid IDs like "None" or "123" to be published; change the validation so that
for dict entries the "id" field must be an instance of str and non-empty (use
raw_id and raw_dependencies to locate the check) and for non-dict entries reject
any entry that is not a str with a ValueError instead of coercing it; ensure
dependency_ids only ever receives already-validated, stripped strings and update
the error messages to mention invalid types/empty values.
| @beartype | ||
| def _dependency_version_satisfies(installed_version: str, version_specifier: str) -> bool: | ||
| """Return True when installed_version satisfies version_specifier or no specifier is declared.""" | ||
| if not version_specifier: | ||
| return True | ||
| try: | ||
| return Version(installed_version) in SpecifierSet(version_specifier) | ||
| except (InvalidSpecifier, InvalidVersion) as exc: | ||
| get_bridge_logger(__name__).debug( | ||
| "Ignoring malformed bundle dependency version comparison: installed_version=%r, " | ||
| "version_specifier=%r, error=%s", | ||
| installed_version, | ||
| version_specifier, | ||
| exc, | ||
| ) | ||
| return False |
There was a problem hiding this comment.
Log message says "Ignoring" but behavior is to fail.
When InvalidSpecifier or InvalidVersion is caught, the log message says "Ignoring malformed bundle dependency version comparison" yet returns False, which causes _raise_if_dependency_version_mismatch to raise a ValueError. The message implies the check is skipped when it actually causes a hard failure.
Consider returning True to genuinely skip malformed comparisons (matching existing tolerance mentioned in the AI summary), or update the log message to reflect that this will cause a failure.
Option A: Truly ignore malformed comparisons (tolerant)
except (InvalidSpecifier, InvalidVersion) as exc:
get_bridge_logger(__name__).debug(
- "Ignoring malformed bundle dependency version comparison: installed_version=%r, "
+ "Skipping malformed bundle dependency version comparison (treating as satisfied): installed_version=%r, "
"version_specifier=%r, error=%s",
installed_version,
version_specifier,
exc,
)
- return False
+ return TrueOption B: Fix the log message to reflect actual behavior
except (InvalidSpecifier, InvalidVersion) as exc:
- get_bridge_logger(__name__).debug(
- "Ignoring malformed bundle dependency version comparison: installed_version=%r, "
+ get_bridge_logger(__name__).warning(
+ "Malformed bundle dependency version comparison (treating as unsatisfied): installed_version=%r, "
"version_specifier=%r, error=%s",
installed_version,
version_specifier,
exc,
)
return False🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/specfact_cli/registry/module_installer.py` around lines 245 - 260, The
current _dependency_version_satisfies catches InvalidSpecifier/InvalidVersion
but logs "Ignoring..." then returns False which triggers a hard failure
downstream; change this to genuinely skip malformed comparisons by returning
True on exception and update the get_bridge_logger(__name__).debug message in
_dependency_version_satisfies to state that the malformed version/specifier is
being skipped (e.g., "Skipping malformed bundle dependency version
comparison...") so behavior and log align; references:
_dependency_version_satisfies and callers like
_raise_if_dependency_version_mismatch.
| @beartype | ||
| def _versioned_module_dependency_problem( | ||
| dep: Any, | ||
| enabled_map: dict[str, bool], | ||
| module_versions: dict[str, str] | None, | ||
| ) -> str | None: | ||
| """Return the validation problem for one versioned dependency, if any.""" | ||
| dep_name = str(getattr(dep, "name", "")).strip() | ||
| version_specifier = str(getattr(dep, "version_specifier", "") or "").strip() | ||
| if not dep_name: | ||
| return None | ||
| if dep_name not in enabled_map: | ||
| return f"{dep_name} (not found)" | ||
| if not enabled_map[dep_name]: | ||
| return f"{dep_name} (disabled)" | ||
| if not version_specifier: | ||
| return None | ||
| if module_versions is None: | ||
| return None | ||
| if dep_name not in module_versions: | ||
| return f"{dep_name} (requires {version_specifier}, found unknown)" | ||
| found_version = module_versions.get(dep_name) | ||
| if not found_version: | ||
| return f"{dep_name} (requires {version_specifier}, found unknown)" | ||
| try: | ||
| if Version(found_version) not in SpecifierSet(version_specifier): | ||
| return f"{dep_name} (requires {version_specifier}, found {found_version})" | ||
| except (InvalidVersion, InvalidSpecifier) as exc: | ||
| get_bridge_logger(__name__).debug( | ||
| "Ignoring malformed module dependency version comparison: dep_name=%r, " | ||
| "version_specifier=%r, found_version=%r, error=%s", | ||
| dep_name, | ||
| version_specifier, | ||
| found_version, | ||
| exc, | ||
| ) | ||
| return None | ||
| return None |
There was a problem hiding this comment.
Inconsistent handling of malformed versions between installer and registration.
_versioned_module_dependency_problem returns None (no problem, passes validation) when InvalidVersion or InvalidSpecifier is caught (lines 575-584). However, _dependency_version_satisfies in module_installer.py returns False (fails validation) for the same scenario.
This inconsistency means:
- Registration time: A module with a malformed version specifier will pass dependency validation and be registered.
- Install time: The same module will fail with a
ValueErrorwhen installing its bundle dependencies.
Both should behave consistently. Based on the AI summary ("treating malformed specifiers/versions as non-blocking debug logs to match existing tolerance"), returning None/True (tolerant) appears to be the intended behavior. Align module_installer._dependency_version_satisfies to return True on malformed comparisons, or vice versa.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/specfact_cli/registry/module_packages.py` around lines 548 - 585, The
registration code (_versioned_module_dependency_problem) swallows
InvalidVersion/InvalidSpecifier and treats malformed version comparisons as
non-blocking; make module_installer._dependency_version_satisfies mirror that
tolerant behavior so installer and registrar are consistent: catch
InvalidVersion and InvalidSpecifier in _dependency_version_satisfies, log a
debug-level message (similar to get_bridge_logger(...).debug usage in
_versioned_module_dependency_problem) and return True (treat as satisfied)
instead of False/raising, ensuring the function signature and callers remain
unchanged.
| module_dependencies = list(getattr(meta, "module_dependencies", [])) | ||
| if module_id in module_dependencies: | ||
| versioned_dependencies = [ | ||
| str(getattr(dependency, "name", "")) | ||
| for dependency in list(getattr(meta, "module_dependencies_versioned", [])) | ||
| ] | ||
| if module_id in {*module_dependencies, *versioned_dependencies}: | ||
| dependents.append(name) |
There was a problem hiding this comment.
Avoid hash-based membership on raw dependency entries
Line 100 now requires every module_dependencies item to be hashable. If metadata contains an unhashable item (e.g., dict/list), this throws TypeError and breaks dependent detection.
Proposed fix
- module_dependencies = list(getattr(meta, "module_dependencies", []))
- versioned_dependencies = [
- str(getattr(dependency, "name", ""))
- for dependency in list(getattr(meta, "module_dependencies_versioned", []))
- ]
- if module_id in {*module_dependencies, *versioned_dependencies}:
+ module_dependencies = [
+ str(dependency).strip()
+ for dependency in list(getattr(meta, "module_dependencies", []))
+ if str(dependency).strip()
+ ]
+ versioned_dependencies = [
+ str(getattr(dependency, "name", "")).strip()
+ for dependency in list(getattr(meta, "module_dependencies_versioned", []))
+ if str(getattr(dependency, "name", "")).strip()
+ ]
+ if module_id in module_dependencies or module_id in versioned_dependencies:
dependents.append(name)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/specfact_cli/registry/module_state.py` around lines 95 - 101, The current
membership check uses a set union {*module_dependencies,
*versioned_dependencies} which requires items in module_dependencies to be
hashable and can raise TypeError for dict/list entries; change the logic to
perform safe string-based comparisons instead: build a list of stringified
module_dependencies (e.g., module_dependencies_str = [str(dep) for dep in
getattr(meta, "module_dependencies", [])]) reuse the existing
versioned_dependencies list, and replace the set-based check with a safe
condition like if module_id in module_dependencies_str or module_id in
versioned_dependencies to append to dependents; reference the symbols
module_dependencies, versioned_dependencies, module_id, meta, dependents, and
name when making the change.
|
Note Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it. An unexpected error occurred while generating fixes: Repository rule violations found Changes must be made through a pull request. 11 of 11 required status checks are expected. |
Summary
Adds module-scope diagnostics and version mismatch enforcement for project/user scoped SpecFact modules.
specfact module doctorto show effective vs shadowed module copies across project, user, and configured development roots.--skip-checksum-verificationreally performs version-bump-only verification while CI signing handles signatures.Root Cause
Users can work across split repos and monorepos with both project-local and user-scoped modules installed. Discovery priority can make one copy shadow another, while older dependency checks did not consistently enforce declared module version ranges, causing confusing command availability and runtime mismatches.
Tracking
Fixes #565
Parent feature: #353
OpenSpec change:
module-scope-version-diagnosticsValidation
openspec validate module-scope-version-diagnostics --stricthatch run pytest tests/unit/specfact_cli/registry/test_module_dependencies.py tests/unit/registry/test_module_installer.py tests/unit/modules/module_registry/test_commands.py -q(96 passed)basedpyrighton touched implementation/tests (0 errors)hatch run specfact code review run --json --out .specfact/code-review.changed.json --scope changed(0 blocking)1.0.0when tarball requires>=2.0.0500337e5