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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ All notable changes to this project will be documented in this file.

---

## [0.55.3] - 2026-08-29

### Fixed

- **Module scope diagnostics:** preserve valid user-scoped module installations
Comment thread
djm81 marked this conversation as resolved.
when a project-local copy takes precedence, and replace routine uninstall
advice with non-destructive origin guidance.
- **Module registry package:** advance the bundled `module-registry` package to
`0.1.35` and refresh its manifest integrity metadata for the updated
diagnostics.

---

## [0.55.2] - 2026-08-27

### Security
Expand Down
2 changes: 1 addition & 1 deletion docs/module-system/installing-modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ Default columns:

With `--show-origin`, an additional `Origin` column is shown (`built-in`, `project`, `user`, `marketplace`, `custom`).

`module doctor` keeps discovery metadata-only and reports effective vs shadowed duplicate copies, exact manifest versions, paths, enabled state, configured development source roots, and recovery commands. Use it when project-scoped modules under `<repo>/.specfact/modules` and user-scoped modules under `~/.specfact/modules` disagree.
`module doctor` keeps discovery metadata-only and reports effective vs shadowed duplicate copies, exact manifest versions, paths, enabled state, configured development source roots, and non-destructive scope guidance. Normal shadowing does not require uninstalling the lower-priority copy. Use it when project-scoped modules under `<repo>/.specfact/modules` and user-scoped modules under `~/.specfact/modules` disagree.

## Show Detailed Module Info

Expand Down
2 changes: 1 addition & 1 deletion docs/module-system/module-marketplace.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ specfact module list --show-origin
specfact module doctor nold-ai/specfact-codebase
```

`module doctor` additionally reports shadowed duplicate copies, exact manifest versions, paths, enabled state, configured development source roots, and recovery commands.
`module doctor` additionally reports shadowed duplicate copies, exact manifest versions, paths, enabled state, configured development source roots, and non-destructive scope guidance. Normal shadowing does not require uninstalling the lower-priority copy.

## Security Model

Expand Down
5 changes: 3 additions & 2 deletions openspec/CHANGE_ORDER.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ active changes should be implemented.

| Bucket | Count | Location |
|---|---:|---|
| **Active** | 20 | [`openspec/changes/`](changes/) |
| **Active** | 21 | [`openspec/changes/`](changes/) |
Comment thread
djm81 marked this conversation as resolved.
| **Parked** | 21 | [`openspec/parking-lot/`](parking-lot/) |
| **Archived** | 115 | [`openspec/changes/archive/`](changes/archive/) |

Expand Down Expand Up @@ -38,7 +38,7 @@ brownfield delivery. The active roadmap should make that thesis stronger:

## Active tracks

The 20 active changes group into three product tracks plus one reliability lane.
The 21 active changes group into three product tracks plus one reliability lane.
Tracks can run in parallel; within a track, follow the order column.

### Track A - Validation Evidence Spine
Expand Down Expand Up @@ -98,6 +98,7 @@ These changes make the CLI itself trustworthy enough to be the validation tool.

| Order | Change | Issue | Positioning | Blocked by |
|---:|---|---|---|---|
| 0 | `module-scope-02-preserve-user-installs` | [#699](https://github.com/nold-ai/specfact-cli/issues/699) | Preserve user-scoped modules when project copies shadow them; remove destructive discovery/doctor guidance | none; paired modules [#452](https://github.com/nold-ai/specfact-cli-modules/issues/452) is coordinated but independently mergeable |
| 1 | `cli-val-03-misuse-safety-proof` | [#281](https://github.com/nold-ai/specfact-cli/issues/281) | Misuse safety proof for user-facing commands | - |
| 2 | `cli-val-04-acceptance-test-runner` | [#282](https://github.com/nold-ai/specfact-cli/issues/282) | Acceptance-test runner for CLI behavior proof | cli-val-03 |
| 3 | `cli-val-05-ci-integration` | [#643](https://github.com/nold-ai/specfact-cli/issues/643) | Fail-closed documentation accountability and CI validation enforcement | cli-val-02, cli-val-03, cli-val-04 |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-08-29
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# TDD Evidence

## Failing Before

- `hatch run pytest tests/unit/registry/test_module_discovery.py::test_project_shadow_warning_is_actionable_and_emitted_once tests/unit/modules/module_registry/test_commands.py::test_doctor_reports_effective_and_shadowed_duplicate_modules -q`
- Result: FAIL before production edits (`2 failed`).
- Discovery still recommended `specfact module uninstall backlog-core --scope
user`, and doctor still printed `Recovery: specfact module uninstall
nold-ai/specfact-codebase --scope user` instead of preservation/no-action
guidance.
- Retained CI red proof: Requirements Evidence run `33274750805` at signed
source commit `b5ad2ea0d5e0ee062906e0c7b2f156330ea1a39f` executed the same two
selectors and produced a bound `observed_maturity: red` artifact with no
reconciliation findings. The workflow's overall failure is expected at this
checkpoint and requires a later final implementation commit.

## Passing After

- `hatch run pytest tests/unit/registry/test_module_discovery.py::test_project_shadow_warning_is_actionable_and_emitted_once tests/unit/modules/module_registry/test_commands.py::test_doctor_reports_effective_and_shadowed_duplicate_modules -q`
- Result: PASS (`2 passed`).
- `hatch run pytest tests/unit/registry/test_module_discovery.py tests/unit/modules/module_registry/test_commands.py -q`
- Initial implementation result: PASS (`67 passed`).
- Discovery precedence, duplicate reporting, doctor output, and explicit uninstall command coverage remain green.

## Review Follow-up

- Review-driven tests were added before the follow-up production edit for
actual effective-source guidance, qualified availability, and user-only
discovery outside the shadowing project.
- Initial focused run: FAIL (`3 failed, 1 passed`). The current doctor always
named project scope and both diagnostics made an unconditional availability
claim. The user-only preservation scenario already passed, so it remains
supplementary regression coverage rather than a retained red-proof selector.
- Retained review red proof: Requirements Evidence run `33277091672` at signed
source commit `daf05baa9303ef914f5659eafe940146d311af25` executed all three
mapped selectors using the final reviewed test bytes and produced a bound
`observed_maturity: red` artifact with no reconciliation findings.
- Passing focused run after the production edit: PASS (`4 passed`).
- Related discovery/doctor files after the review fixes: PASS (`69 passed`).

## Quality Gates

- `hatch run format`: PASS (942 files unchanged).
- `hatch run type-check`: PASS (0 errors; 1,531 existing warnings).
- `hatch run lint`: PASS.
- `openspec validate module-scope-02-preserve-user-installs --strict`: PASS.
- `hatch run yaml-lint`: exit code 0; it reports only pre-existing
line-length/blank-line findings in untouched Requirements R07/R08 evidence.
- `hatch run contract-test` and `hatch run contract-test-contracts`: PASS using
cached results after the full smart-test had refreshed hashes; both report no
further modified contract inputs. The focused contract-sensitive
discovery/doctor files pass, and the independent full suite exercised them.
- Schema-v2 Requirements evidence maps all behavior-changing scenarios to exact
pytest selectors; the staged repository hook is the delivery gate. The
unchanged development-source-root disclosure remains covered by
`tests/unit/modules/module_registry/test_commands.py::test_doctor_reports_configured_development_source_roots`
and is intentionally excluded from the red-proof mapping because it was
already green before this fix.
- Product-owner review evidence is bound to mapping digest
`sha256:fc0ff2c618b508f00943c66a987a14edf5175c730e9b26ac146785aa2045fe68`
and core issue #699 for the required test-authored maturity gate. The
executable plan contains the two original behavior regressions plus the
failing effective-source review scenario; the already-passing user-only
preservation scenario remains supplementary regression coverage.
- The built-in module-registry payload change advances the module-registry
package to `0.1.35` with refreshed integrity metadata, advances all four
canonical core version sources to `0.55.3`, and adds the matching changelog
entry. The PR's `Verify Module Signatures` job passes for that delivered
payload.
- `uv lock` refreshes the frozen project record from core `0.55.2` to `0.55.3`;
`uv sync --locked --all-extras` then passes locally, resolving the first PR CI
setup failures caused by the stale lock.
- Core CI's immutable module fixture is authoritative for generated command
inventory. A local run against the newer paired modules checkout exposed
three later Code Review PR-range options, but those options are intentionally
absent from this core patch's generated artifacts so the frozen-fixture docs
check remains reproducible.
- `hatch run bandit-scan`: PASS (no medium/high findings).
- Semgrep and its baseline gate: PASS (0 current findings, 0 baseline findings).
- Earlier local `hatch run smart-test` / `hatch run test` runs recorded
`3029 passed, 12 skipped, 17 failed` before restoring the immutable fixture
and refreshing the changed module signature.
- Final signed-head PR Orchestrator run `33275273173` executed
`smart-test-full`: PASS (`3050 passed, 8 skipped`) on Python 3.12. Its Python
3.11 compatibility job also passed.
- The exact immutable-fixture full-enforcement Code Review used by CI passes
locally with score 115 and zero findings after resolving all clean-code and
type-safety warnings in the touched legacy files. The newer protected schema
1.6 capsule still reports assurance `UNKNOWN` on this macOS host because its
controller supports Linux; Linux PR CI remains authoritative for that
capsule.
- `git diff --check`: PASS.

## Final Review Closeout

- Signed review-fix payload head
`37138693df6dfa1d9549c78f9f3f00e1f3170c89` passed Requirements Evidence run
`33278069038` and PR Orchestrator run `33278069078`.
- The final orchestrator recorded `3052 passed, 8 skipped` on Python 3.12 and
`3006 passed, 7 skipped` on Python 3.11. Strict local module-signature
verification also passed for the signed `module-registry` `0.1.35` payload.
- Docs Review run `33278069066`, Module Signature Hardening run `33278069032`,
and SpecFact CLI Validation run `33278069156` passed on the same signed head.
- The final GitHub review-thread audit found 20 inline threads, all resolved,
after verifying every requested production, test, documentation, and evidence
correction.
21 changes: 21 additions & 0 deletions openspec/changes/module-scope-02-preserve-user-installs/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## Overview

Preserve the existing deterministic discovery order while correcting the meaning of a shadowed user module. A project copy is effective only for the current repository; the user copy is neither stale nor invalid by default and remains the effective installation elsewhere.

## Decisions

- Keep all discovery roots, precedence, deduplication, and shadowed-entry reporting unchanged.
- Keep the discovery signal user-visible, but describe it as workspace-local precedence and explicitly state that no action is required.
- Replace the doctor recovery command with explanatory shadowing guidance. `module list --show-origin` remains the diagnostic path for inspecting exact sources.
- Do not weaken or remove explicit `specfact module uninstall --scope user`; this defect concerns automatic/routine advice, not intentional lifecycle commands.
- Test both message producers directly so future wording changes cannot reintroduce the destructive recommendation.

## Risks

- Users with a genuinely unwanted duplicate no longer receive a one-line delete command. Mitigation: diagnostics still show both origins and explicit uninstall remains available in lifecycle documentation.
- Warning language could become noisy despite being safe. Mitigation: existing once-per-process deduplication remains unchanged.
- Only one repository could merge, temporarily leaving inconsistent guidance. Mitigation: paired issues and PRs are cross-linked and independently safe to merge.

## Rollback

Revert the diagnostic text and tests. No persisted module state or installation files are changed by this patch.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
## Why

Core module discovery and `specfact module doctor` describe normal
project-over-user shadowing as stale state and recommend uninstalling the
user-scoped copy. Review/bootstrap workflows surface and follow that
recommendation, repeatedly removing `specfact-codebase` and
`specfact-code-review` from the user scope even though those installations are
still needed in other repositories.

## What Changes

- Keep project-over-user precedence unchanged.
- Replace user-scope uninstall recovery advice with non-destructive scope
guidance in module discovery warnings and doctor output.
- State explicitly that the user-scoped copy remains installed, normal
shadowing alone does not require uninstalling it, and availability elsewhere
still depends on module state and higher-priority copies.
- Add regression tests that reject destructive user-scope uninstall
recommendations while preserving origin diagnostics.

## Capabilities

### Modified Capabilities

- `module-scope-diagnostics`: Discovery and doctor diagnostics report shadowing
without treating a valid user installation as cleanup residue.

## Impact

- Affected code: `src/specfact_cli/registry/module_discovery.py` and
`src/specfact_cli/modules/module_registry/src/commands.py`.
- Affected tests: focused module discovery and module doctor unit tests.
- Paired modules delivery: `nold-ai/specfact-cli-modules#454` corrects the
repository bootstrap surfaces that trigger this behavior during review work.
- Compatibility and data impact: none. Discovery order, module state, explicit
uninstall behavior, manifests, and persistent installation data remain
unchanged.

---

## Source Tracking

<!-- source_repo: nold-ai/specfact-cli -->
- **Parent Feature**: [#353](https://github.com/nold-ai/specfact-cli/issues/353)
- **Parent Epic**: [#194](https://github.com/nold-ai/specfact-cli/issues/194)
- **Bug Issue**: [#699](https://github.com/nold-ai/specfact-cli/issues/699)
- **Paired Modules Bug**:
[nold-ai/specfact-cli-modules#452](https://github.com/nold-ai/specfact-cli-modules/issues/452)
- **Issue Relationships**: `#699` is a sub-issue of Feature `#353`; Feature
`#353` is a sub-issue of Epic `#194`.
- **Blocked By**: none
- **Repository**: nold-ai/specfact-cli
- **Last Synced Status**: issue type, labels, assignee, parent, project
assignment, In Progress status, and blocker metadata verified on 2026-08-29
- **Sanitized**: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
schema_version: "2"
requirements:
openspec:module-scope-02-preserve-user-installs:module-scope-diagnostics:module-doctor-reports-effective-and-shadowed-module-copies:
rationale: "Module diagnostics must explain actual source precedence without treating valid user installations as stale."
stakeholder_refs:
- "nold-ai/specfact-cli#699"
- "nold-ai/specfact-cli-modules#452"
touchpoints:
- id: discovery-shadow-warning
kind: source_file
locator: "src/specfact_cli/registry/module_discovery.py"
- id: module-doctor-guidance
kind: source_file
locator: "src/specfact_cli/modules/module_registry/src/commands.py"
verification_cases:
- case_id: MSI-CORE-001
scenario_id: module-doctor-reports-effective-and-shadowed-module-copies
method: test
intent: "Report both copies and preserve the user-scoped installation."
observable: "Doctor reports both origins and paths, preserves the user copy, and emits no uninstall advice."
selector:
runner: pytest
node_id: tests/unit/modules/module_registry/test_commands.py::test_doctor_reports_effective_and_shadowed_duplicate_modules
Comment thread
djm81 marked this conversation as resolved.
- case_id: MSI-CORE-002
scenario_id: module-doctor-reports-effective-and-shadowed-module-copies
method: test
intent: "Keep runtime precedence diagnostics non-destructive."
observable: "Discovery states that the user copy remains installed, qualifies availability, and emits no uninstall advice."
selector:
runner: pytest
node_id: tests/unit/registry/test_module_discovery.py::test_project_shadow_warning_is_actionable_and_emitted_once
- case_id: MSI-CORE-003
scenario_id: module-doctor-reports-effective-and-shadowed-module-copies
method: test
intent: "Name the source that actually shadows the user-scoped copy."
observable: "Doctor identifies built-in precedence without claiming project precedence."
selector:
runner: pytest
node_id: tests/unit/modules/module_registry/test_commands.py::test_doctor_shadowing_guidance_names_builtin_effective_source
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"schema_version": "1",
"decision": "accepted",
"reviewer_id": "djm81",
"reviewer_role": "product-owner",
"recorded_at": "2026-08-29T23:41:00+02:00",
"reference": "https://github.com/nold-ai/specfact-cli/issues/699",
"mapping_digest": "sha256:fc0ff2c618b508f00943c66a987a14edf5175c730e9b26ac146785aa2045fe68"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## MODIFIED Requirements

### Requirement: Module doctor reports effective and shadowed module copies

The system SHALL provide module-scope diagnostics that report module origin, version, path, and shadowing state without importing module command code or treating a valid lower-priority installation as stale by default.

#### Scenario: Duplicate project and user module copies are visible

- **GIVEN** a module id exists in project scope and user scope with different versions
- **WHEN** the user runs `specfact module doctor <module-id>`
- **THEN** the output identifies the project copy as effective
- **AND** the output identifies the user copy as shadowed
- **AND** the output shows both versions and paths
- **AND** the output states that the user-scoped copy remains installed
- **AND** the output states that normal shadowing alone does not require uninstalling it
- **AND** any claim about use outside the current workspace accounts for the module's enabled state and other higher-priority copies
- **AND** the output does not recommend uninstalling the user-scoped copy

#### Scenario: Runtime discovery reports project-over-user precedence

- **GIVEN** a module id exists in project scope and user scope
- **WHEN** runtime discovery selects the project-scoped copy
- **THEN** the diagnostic identifies project scope as effective in the current workspace
- **AND** it states that the user-scoped copy remains installed
- **AND** it does not claim that the user copy is active outside the workspace without accounting for module state and other higher-priority copies
- **AND** it does not recommend uninstalling the user-scoped copy
Comment thread
coderabbitai[bot] marked this conversation as resolved.

#### Scenario: Doctor identifies the actual effective source

- **GIVEN** a user-scoped module is shadowed by a higher-priority copy
- **WHEN** the user runs `specfact module doctor <module-id>`
- **THEN** the guidance identifies the actual effective source
- **AND** it does not describe built-in, marketplace, or custom shadowing as project precedence

#### Scenario: Development source roots are disclosed

- **GIVEN** development source root environment variables are configured
- **WHEN** the user runs `specfact module doctor`
- **THEN** the output lists the configured development source roots that may influence import resolution
Loading
Loading