From 7a13c15dba84bfa45a1f13918ac99206c9dd930b Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Tue, 14 Jul 2026 20:19:06 +0200 Subject: [PATCH 1/7] feat(requirements): import OpenSpec requirement evidence --- docs/bundles/requirements/overview.md | 32 ++++- docs/reference/commands.generated.json | 4 +- docs/reference/commands.generated.md | 2 +- llms.txt | 2 +- .../CHANGE_VALIDATION.md | 38 ++++-- .../openspec-01-intent-trace/TDD_EVIDENCE.md | 45 +++++++ .../openspec-01-intent-trace/design.md | 19 +++ .../openspec-01-intent-trace/proposal.md | 11 +- .../specs/requirements-module/spec.md | 19 +++ .../changes/openspec-01-intent-trace/tasks.md | 6 +- .../specfact-requirements/module-package.yaml | 7 +- .../requirements/commands.py | 98 ++++++++++++-- .../requirements/runtime.py | 121 ++++++++++++++++-- registry/index.json | 9 +- .../specfact-requirements-0.2.0.tar.gz | Bin 0 -> 5634 bytes .../specfact-requirements-0.2.0.tar.gz.sha256 | 1 + .../test_command_apps.py | 66 ++++++++++ .../docs/test_bundle_overview_cli_examples.py | 16 +++ .../test_requirements_runtime.py | 113 ++++++++++++++++ 19 files changed, 558 insertions(+), 51 deletions(-) create mode 100644 openspec/changes/openspec-01-intent-trace/TDD_EVIDENCE.md create mode 100644 registry/modules/specfact-requirements-0.2.0.tar.gz create mode 100644 registry/modules/specfact-requirements-0.2.0.tar.gz.sha256 diff --git a/docs/bundles/requirements/overview.md b/docs/bundles/requirements/overview.md index 7a43e94..98c29e9 100644 --- a/docs/bundles/requirements/overview.md +++ b/docs/bundles/requirements/overview.md @@ -18,7 +18,7 @@ planning or product-management system. ## Prerequisites -- SpecFact CLI with core requirements context helpers +- SpecFact CLI 0.52.0 or later - Bundle installed: `specfact module install nold-ai/specfact-requirements` - A project bundle directory, usually created by the [Project](/bundles/project/overview/) bundle - Local JSON or YAML requirement records with source attribution @@ -30,10 +30,10 @@ group. | Command | Purpose | |--------|---------| -| `import` | Import local JSON/YAML requirement records into a project bundle | -| `validate` | Validate attached requirement context against a profile | -| `list` | List attached requirement records, optionally with coverage | -| `coverage` | Print coverage counts for downstream evidence links | +| `import` | Import local records or native OpenSpec/Spec Kit evidence into a project bundle | +| `validate` | Validate attached requirement context against the selected or layered profile | +| `list` | List attached requirement records with optional coverage and core gate counts | +| `coverage` | Print coverage and core gate-finding counts | ## Input shape @@ -69,11 +69,32 @@ Each record follows the core `RequirementInput` model and must include ```bash specfact requirements import --from-file requirements.json --bundle .specfact/projects/shop --format json +specfact requirements import --from-openspec openspec/changes/widget-evidence --bundle .specfact/projects/shop --format json +specfact requirements import --from-speckit specs/001-widget-rendering --bundle .specfact/projects/shop --format json specfact requirements list --bundle .specfact/projects/shop --show-coverage --format json specfact requirements validate --bundle .specfact/projects/shop --profile enterprise --format json specfact requirements coverage --bundle .specfact/projects/shop --format json ``` +For native imports, a source path is optional. `--from-openspec` discovers a +single conventional change below `openspec/changes/`; `--from-speckit` +discovers a single feature below `specs/`. Multiple or missing candidates are a +clear error so the command never guesses. Pass a path whenever the project has +more than one candidate. + +Native imports are read-only and supported only for core's default, +fixture-backed OpenSpec and Spec Kit Markdown profiles. A core +`unsupported-source-schema` diagnostic is returned unchanged, and no partial +requirements sidecar is written. The bundle does not infer upstream tool +versions, fall back to another parser, or add upstream metadata. + +When `--profile` is omitted, validation uses the effective layered core +configuration. Explicit `--profile` still wins. Core findings such as +`scenario-unverified`, `stale-import`, `source-missing`, +`ambiguous-mapping`, and `unsupported-profile-field` remain machine-readable; +the list and coverage commands include their counts without re-evaluating the +gates. + ## Storage The command runtime rehydrates the core `requirements.inputs` extension before @@ -87,6 +108,7 @@ The bundle is read-first and evidence-focused. - It imports and normalizes source-attributed requirement context. - It reports validation findings and coverage gaps. +- It delegates parsing, hashing, compatibility, and gate evaluation to core. - It does not expose authoring templates. - It does not perform bidirectional backlog sync or ceremony automation. diff --git a/docs/reference/commands.generated.json b/docs/reference/commands.generated.json index 21294e5..7583704 100644 --- a/docs/reference/commands.generated.json +++ b/docs/reference/commands.generated.json @@ -1744,7 +1744,9 @@ "options": [ "--bundle", "--format", - "--from-file" + "--from-file", + "--from-openspec", + "--from-speckit" ], "owner_package": "nold-ai/specfact-requirements", "owner_repo": "nold-ai/specfact-cli-modules", diff --git a/docs/reference/commands.generated.md b/docs/reference/commands.generated.md index 315987f..caa71e6 100644 --- a/docs/reference/commands.generated.md +++ b/docs/reference/commands.generated.md @@ -95,7 +95,7 @@ This file is generated from the current module command trees. Do not edit by han | `specfact project version set` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --bundle, --repo, --version; args: - | - | | | `specfact requirements` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --install-completion, --show-completion; args: - | coverage, import, list, validate | | | `specfact requirements coverage` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format; args: - | - | | -| `specfact requirements import` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --from-file; args: - | - | | +| `specfact requirements import` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --from-file, --from-openspec, --from-speckit; args: - | - | | | `specfact requirements list` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --show-coverage; args: - | - | | | `specfact requirements validate` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --profile; args: - | - | | | `specfact spec` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | --install-completion, --show-completion; args: - | backward-compat, generate-tests, mock, validate | | diff --git a/llms.txt b/llms.txt index 2cd332d..69d403c 100644 --- a/llms.txt +++ b/llms.txt @@ -99,7 +99,7 @@ This file is generated from the current module command trees. Do not edit by han | `specfact project version set` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --bundle, --repo, --version; args: - | - | | | `specfact requirements` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --install-completion, --show-completion; args: - | coverage, import, list, validate | | | `specfact requirements coverage` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format; args: - | - | | -| `specfact requirements import` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --from-file; args: - | - | | +| `specfact requirements import` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --from-file, --from-openspec, --from-speckit; args: - | - | | | `specfact requirements list` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --show-coverage; args: - | - | | | `specfact requirements validate` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --profile; args: - | - | | | `specfact spec` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | --install-completion, --show-completion; args: - | backward-compat, generate-tests, mock, validate | | diff --git a/openspec/changes/openspec-01-intent-trace/CHANGE_VALIDATION.md b/openspec/changes/openspec-01-intent-trace/CHANGE_VALIDATION.md index 1b2db9c..a290c4c 100644 --- a/openspec/changes/openspec-01-intent-trace/CHANGE_VALIDATION.md +++ b/openspec/changes/openspec-01-intent-trace/CHANGE_VALIDATION.md @@ -1,12 +1,34 @@ # Change Validation Report: openspec-01-intent-trace -**Status**: STALE — revalidation required before implementation. +**Status**: VALIDATED — 2026-07-14 (Europe/Berlin) -The previous report (2026-03-05) validated the retired `## Intent Trace` -authoring scope. The change was rescoped on 2026-07-13 to import-first -requirement evidence runtime for native OpenSpec and Spec Kit artifacts (see -`proposal.md`, Rescope section, and core counterpart nold-ai/specfact-cli#350). +## Scope and dependency check -Re-run the change validation workflow against the rescoped proposal and -replace this file with the new report before starting implementation -(tracked as task 1.3 in `tasks.md`). +- The modules change remains a thin command runtime: it delegates native + OpenSpec and Spec Kit imports to core, and does not parse, hash, enrich, or + write upstream artifacts. +- Core counterpart `nold-ai/specfact-cli#350` shipped in merged PR + `nold-ai/specfact-cli#646` on 2026-07-13. Its exported helpers are + `import_openspec_change`, `import_speckit_feature`, and + `validate_requirement_context` with optional profile resolution. +- The module requires core `>=0.52.0,<1.0.0`; the validated local core is + `0.52.2`. +- Core's `unsupported-source-schema` and `unsupported-profile-field` outcomes + remain core-owned and are passed through by the module without fallback + parsing, metadata enrichment, or partial persistence. + +## Change validity evidence + +`openspec validate openspec-01-intent-trace --strict` passed on 2026-07-14. + +The active delta covers the command flags, conservative auto-detection, +sidecar merge behavior, profile delegation, core diagnostic pass-through, and +read-only upstream behavior. No scope change is required beyond the existing +delta updates that record the core compatibility outcomes. + +## Implementation constraints + +1. Add or update scenario-mapped tests before runtime code. +2. Record failing-before and passing-after evidence in `TDD_EVIDENCE.md`. +3. Bump the additive module release and align manifest compatibility metadata. +4. Re-sign the changed module manifest and run the full quality gate sequence. diff --git a/openspec/changes/openspec-01-intent-trace/TDD_EVIDENCE.md b/openspec/changes/openspec-01-intent-trace/TDD_EVIDENCE.md new file mode 100644 index 0000000..1c3bba2 --- /dev/null +++ b/openspec/changes/openspec-01-intent-trace/TDD_EVIDENCE.md @@ -0,0 +1,45 @@ +# TDD Evidence: openspec-01-intent-trace + +## Failing-before + +- Date: 2026-07-14 (Europe/Berlin) +- Command: + + ```bash + hatch run test tests/unit/specfact_requirements/test_requirements_runtime.py tests/integration/specfact_requirements/test_command_apps.py + ``` + +- Result: failed during collection, as expected before runtime implementation. +- Evidence: `ImportError: cannot import name 'import_openspec_change_to_bundle' from 'specfact_requirements.requirements.runtime'`. + +The new tests cover OpenSpec and Spec Kit import delegation, read-only source +behavior, no partial persistence for core `unsupported-source-schema`, +layered-profile delegation, core gate-count presentation, and CLI explicit and +auto-detected OpenSpec sources. + +## Passing-after + +- Date: 2026-07-14 (Europe/Berlin) +- Command: + + ```bash + hatch run pytest tests/unit/specfact_requirements/test_requirements_runtime.py tests/integration/specfact_requirements/test_command_apps.py -q + ``` + +- Result: `17 passed`. +- The passing suite proves core-delegated OpenSpec and Spec Kit imports, + read-only source handling, fail-closed schema rejection without a sidecar, + layered-profile delegation, core gate-count presentation, and command-level + explicit and auto-detected OpenSpec import behavior. + +## Final quality gates + +- `hatch run type-check -- packages/specfact-requirements/src tests/unit/specfact_requirements tests/integration/specfact_requirements` — passed with 0 errors. +- `hatch run lint` — passed. +- `hatch run yaml-lint` — passed. +- `hatch run check-bundle-imports` — passed. +- `hatch run verify-modules-signature --payload-from-filesystem --enforce-version-bump --allow-missing-public-key` — passed for all manifests. +- `hatch run contract-test` — passed (28 tests). +- `hatch run smart-test` — passed (878 tests). +- `hatch run test` — passed (878 tests, 2 third-party deprecation warnings). +- `hatch run specfact code review run --enforcement changed --bug-hunt --json --out .specfact/code-review.json` — passed with exit code 0. diff --git a/openspec/changes/openspec-01-intent-trace/design.md b/openspec/changes/openspec-01-intent-trace/design.md index 8e90142..b1c6747 100644 --- a/openspec/changes/openspec-01-intent-trace/design.md +++ b/openspec/changes/openspec-01-intent-trace/design.md @@ -55,6 +55,25 @@ naming the expected layouts, never a guess. **Rationale**: Deterministic behavior over convenience heuristics; misdetected sources would poison evidence. +### D4: Preserve core required-field findings unchanged + +**Decision**: The runtime delegates profile resolution and completeness +evaluation to core, including the evidence-compatible aliases (`id`, `title`, +`acceptance`, and `trace_links`) and `unsupported-profile-field` advisories. +It renders those findings without translating, filtering, or supplementing +them with module-owned metadata. +**Rationale**: The module must remain a thin command adapter. Adding owner, +risk, or exception fields here would make the module an authoring surface and +break the core import-first contract. + +### D5: Preserve core compatibility failures unchanged + +**Decision**: The runtime surfaces `unsupported-source-schema` returned by the +core adapter and does not persist records from that import result. +**Rationale**: Source-profile detection, version policy, fallback parsing, and +partial-import prevention belong to core #350. Reimplementing any of them in +the module would create divergent compatibility behavior. + ## Risks / Trade-offs - **[Risk] Core/module version skew** — flags exist but core helpers are old. diff --git a/openspec/changes/openspec-01-intent-trace/proposal.md b/openspec/changes/openspec-01-intent-trace/proposal.md index da945a1..00722ef 100644 --- a/openspec/changes/openspec-01-intent-trace/proposal.md +++ b/openspec/changes/openspec-01-intent-trace/proposal.md @@ -37,11 +37,18 @@ proposal (nold-ai/specfact-cli#350) for contract details. and Spec Kit `specs/`) relative to the project root. - **EXTEND**: `requirements validate` surfaces the core gate findings (`scenario-unverified`, `stale-import`, `source-missing`, - `ambiguous-mapping`) with profile-driven severity and non-zero exit on + `ambiguous-mapping`, `unsupported-source-schema`) with profile-driven severity and non-zero exit on failure; `list`/`coverage` output includes gate-relevant counts. - **EXTEND**: When `--profile` is omitted, the effective profile resolves from the layered configuration shipped by `profile-01-config-layering` instead of a hardcoded `startup` default; an explicit flag always wins. +- **EXTEND**: Preserve the core adapter's evidence-compatible required-field + mapping (`id`, `title`, `acceptance`, and `trace_links`) and surface its + `unsupported-profile-field` advisories unchanged. The module does not add + owner, risk, or exception metadata to imported records. +- **EXTEND**: Surface core `unsupported-source-schema` errors unchanged and do + not persist any partial import when core rejects an untested OpenSpec schema + or a customized Spec Kit template profile. - **UNCHANGED**: `--from-file` remains for generic records; existing sidecar persistence and merge semantics are reused as-is. @@ -60,5 +67,5 @@ proposal (nold-ai/specfact-cli#350) for contract details. - **GitHub Issue**: #168 - **Issue URL**: - **Core Counterpart**: nold-ai/specfact-cli#350 -- **Last Synced Status**: proposed +- **Last Synced Status**: open / Todo (aligned 2026-07-13) - **Sanitized**: false diff --git a/openspec/changes/openspec-01-intent-trace/specs/requirements-module/spec.md b/openspec/changes/openspec-01-intent-trace/specs/requirements-module/spec.md index 48de3a0..3b7acb9 100644 --- a/openspec/changes/openspec-01-intent-trace/specs/requirements-module/spec.md +++ b/openspec/changes/openspec-01-intent-trace/specs/requirements-module/spec.md @@ -38,6 +38,25 @@ logic of its own and SHALL never write into upstream artifact directories. - **THEN** the report lists each gate finding with its category and affected requirement IDs - **AND** the command exits non-zero when the profile treats any finding as an error. +#### Scenario: Runtime preserves core required-field advisories + +- **GIVEN** core validation returns an `unsupported-profile-field` advisory + for a profile field not represented by `RequirementInput` +- **WHEN** `specfact requirements validate` renders the validation report +- **THEN** the advisory is present in the machine-readable and human-readable + output unchanged +- **AND** the module does not add owner, risk, or exception metadata to the + imported record. + +#### Scenario: Runtime blocks unsupported source profiles + +- **GIVEN** an OpenSpec schema or Spec Kit template profile rejected by the + core adapter with `unsupported-source-schema` +- **WHEN** an import command delegates to core +- **THEN** the command surfaces that diagnostic unchanged +- **AND** it does not create or persist partial requirement records +- **AND** it does not attempt version detection or fallback parsing. + #### Scenario: Runtime never writes upstream - **GIVEN** import and validation runs against OpenSpec and Spec Kit sources diff --git a/openspec/changes/openspec-01-intent-trace/tasks.md b/openspec/changes/openspec-01-intent-trace/tasks.md index 839377c..3cab694 100644 --- a/openspec/changes/openspec-01-intent-trace/tasks.md +++ b/openspec/changes/openspec-01-intent-trace/tasks.md @@ -17,7 +17,8 @@ evidence in `TDD_EVIDENCE.md`. - [ ] 2.1 Finalize the `requirements-module` spec delta and cross-check scenario completeness. - [ ] 2.2 Add tests: `--from-openspec`/`--from-speckit` import against fixtures, auto-detection success and clear-error cases, gate findings surfaced in `validate` with non-zero exit, and upstream directories untouched after runs. -- [ ] 2.2b Add tests: omitted `--profile` resolves the effective profile from layered configuration instead of a hardcoded `startup` default; explicit `--profile` overrides. +- [ ] 2.2b Add tests: omitted `--profile` resolves the effective profile from layered configuration instead of a hardcoded `startup` default; explicit `--profile` overrides; core's four supported aliases and `unsupported-profile-field` advisories pass through unchanged. +- [ ] 2.2c Add tests: core `unsupported-source-schema` diagnostics surface unchanged and produce no partial sidecar persistence. - [ ] 2.3 Run targeted tests, capture failing-first output in `TDD_EVIDENCE.md`. ## 3. Implementation @@ -25,7 +26,8 @@ evidence in `TDD_EVIDENCE.md`. - [ ] 3.1 Extend `packages/specfact-requirements/.../commands.py` import command with `--from-openspec [PATH]` and `--from-speckit [PATH]` options. - [ ] 3.2 Extend `runtime.py` with thin delegation to the new core normalizers via the existing `_load_requirements_module` pattern, including `RequirementsCoreUnavailableError` messaging. - [ ] 3.3 Surface gate findings in `validate` output and gate-relevant counts in `list`/`coverage`. -- [ ] 3.3b Change the `validate` command's profile default from hardcoded `startup` to core layered-config resolution when the flag is omitted (delegated to the core helper; no config parsing in the module). +- [ ] 3.3b Change the `validate` command's profile default from hardcoded `startup` to core layered-config resolution when the flag is omitted, and render core required-field advisories unchanged (delegated to the core helper; no config parsing or metadata enrichment in the module). +- [ ] 3.3c Surface core `unsupported-source-schema` results without fallback parsing or partial persistence. - [ ] 3.4 Contract decorators (`@beartype`, `@require`, `@ensure`) on all new public APIs. ## 4. Validation and documentation diff --git a/packages/specfact-requirements/module-package.yaml b/packages/specfact-requirements/module-package.yaml index e465cb2..dc34207 100644 --- a/packages/specfact-requirements/module-package.yaml +++ b/packages/specfact-requirements/module-package.yaml @@ -1,5 +1,5 @@ name: nold-ai/specfact-requirements -version: 0.1.5 +version: 0.2.1 commands: - requirements tier: official @@ -14,10 +14,9 @@ pip_dependencies: - pydantic - pyyaml - typer -core_compatibility: '>=0.50.0,<1.0.0' +core_compatibility: '>=0.52.0,<1.0.0' description: Official SpecFact requirements evidence runtime bundle package. category: project bundle_group_command: requirements integrity: - checksum: sha256:d200aaecff7760ee660dd984d70d417b56960879385ebd745ddf48f08cee1b0d - signature: 3cXSjTAnhQHUcvDsM4pYwp8OxJ/gAvNtZD3H0zCMqOyuHW5axSeCJcpGDqjno1YLAq+v4B1PL5HYuJkAUeZQAQ== + checksum: sha256:53ea098fe96803931e2865badd810b3386e1113fc3ad834dc77a56b975ba3691 diff --git a/packages/specfact-requirements/src/specfact_requirements/requirements/commands.py b/packages/specfact-requirements/src/specfact_requirements/requirements/commands.py index 2064958..c1e392a 100644 --- a/packages/specfact-requirements/src/specfact_requirements/requirements/commands.py +++ b/packages/specfact-requirements/src/specfact_requirements/requirements/commands.py @@ -12,10 +12,15 @@ from icontract import ensure, require from specfact_requirements.requirements.runtime import ( + auto_detect_openspec_change, + auto_detect_speckit_feature, + import_native_requirements_to_bundle, import_requirements_file_to_bundle, + import_result_has_errors, inspect_requirements_bundle_coverage, is_requirement_context_profile_supported, list_requirements_with_coverage, + requirements_gate_finding_counts, validate_requirements_bundle, ) @@ -49,27 +54,83 @@ def _emit_payload(payload: dict[str, Any], output_format: OutputFormat) -> None: typer.echo(f"{key}: {value}") -@app.command("import", help="Import local requirement records into a project bundle.") -@beartype -@require(lambda from_file: from_file.is_file(), "from_file must exist") +def _selected_import_source(from_file: Path | None, from_openspec: bool, from_speckit: bool) -> str: + selected = [ + name + for name, enabled in ( + ("file", from_file is not None), + ("openspec", from_openspec), + ("speckit", from_speckit), + ) + if enabled + ] + if len(selected) != 1: + raise typer.BadParameter("choose exactly one of --from-file, --from-openspec, or --from-speckit") + return selected[0] + + +def _optional_source_path(ctx: typer.Context, source_name: str) -> Path | None: + if source_name == "file" and ctx.args: + raise typer.BadParameter("--from-file does not accept a positional source path") + if len(ctx.args) > 1: + raise typer.BadParameter("provide at most one source path") + return Path(ctx.args[0]) if ctx.args else None + + +@app.command( + "import", + help="Import local, OpenSpec, or Spec Kit requirement evidence into a project bundle.", + context_settings={"allow_extra_args": True}, +) @require(lambda bundle: bundle.is_dir(), "bundle must exist") @require(_format_supported, "output format must be supported") @ensure(lambda result: result is None) def import_command( - from_file: Annotated[ - Path, - typer.Option( - "--from-file", exists=True, file_okay=True, dir_okay=False, readable=True, help="JSON/YAML records." - ), - ], + ctx: typer.Context, bundle: Annotated[ Path, typer.Option("--bundle", exists=True, file_okay=False, dir_okay=True, readable=True, writable=True), ], + from_file: Annotated[ + Path | None, + typer.Option( + "--from-file", exists=True, file_okay=True, dir_okay=False, readable=True, help="JSON/YAML records." + ), + ] = None, + from_openspec: Annotated[ + bool, + typer.Option( + "--from-openspec", help="Import one OpenSpec change; an optional positional path overrides auto-detection." + ), + ] = False, + from_speckit: Annotated[ + bool, + typer.Option( + "--from-speckit", help="Import one Spec Kit feature; an optional positional path overrides auto-detection." + ), + ] = False, output_format: Annotated[OutputFormat, typer.Option("--format", help="Output format.")] = OutputFormat.TEXT, ) -> None: - """Import local requirement records into a project bundle.""" - result = import_requirements_file_to_bundle(from_file, bundle) + """Import one source of requirement evidence into a project bundle.""" + source_name = _selected_import_source(from_file, from_openspec, from_speckit) + source_path = _optional_source_path(ctx, source_name) + if source_name == "file": + if from_file is None: + raise typer.BadParameter("--from-file requires a path") + result = import_requirements_file_to_bundle(from_file, bundle) + else: + source_dir = source_path + if source_dir is None: + source_dir = ( + auto_detect_openspec_change(Path.cwd()) + if source_name == "openspec" + else auto_detect_speckit_feature(Path.cwd()) + ) + result = import_native_requirements_to_bundle( + source_name, + source_dir, + bundle, + ) _emit_payload( { "imported": len(result.requirements), @@ -77,12 +138,17 @@ def import_command( }, output_format, ) + if import_result_has_errors(result): + raise typer.Exit(1) @app.command("validate", help="Validate requirement context evidence usefulness.") @beartype @require(lambda bundle: bundle.is_dir(), "bundle must exist") -@require(is_requirement_context_profile_supported, "profile must be a known requirement context profile") +@require( + lambda profile: profile is None or is_requirement_context_profile_supported(profile), + "profile must be a known requirement context profile when provided", +) @require(_format_supported, "output format must be supported") @ensure(lambda result: result is None) def validate_command( @@ -90,7 +156,9 @@ def validate_command( Path, typer.Option("--bundle", exists=True, file_okay=False, dir_okay=True, readable=True), ], - profile: Annotated[str, typer.Option("--profile", help="Validation profile.")] = "startup", + profile: Annotated[ + str | None, typer.Option("--profile", help="Validation profile; omit to use layered configuration.") + ] = None, output_format: Annotated[OutputFormat, typer.Option("--format", help="Output format.")] = OutputFormat.TEXT, ) -> None: """Validate requirement context evidence usefulness.""" @@ -131,4 +199,6 @@ def coverage_command( ) -> None: """Inspect requirement context coverage.""" coverage = inspect_requirements_bundle_coverage(bundle) - _emit_payload(coverage.model_dump(mode="json"), output_format) + payload = coverage.model_dump(mode="json") + payload["gate_finding_counts"] = requirements_gate_finding_counts(bundle) + _emit_payload(payload, output_format) diff --git a/packages/specfact-requirements/src/specfact_requirements/requirements/runtime.py b/packages/specfact-requirements/src/specfact_requirements/requirements/runtime.py index 0d140d5..804966a 100644 --- a/packages/specfact-requirements/src/specfact_requirements/requirements/runtime.py +++ b/packages/specfact-requirements/src/specfact_requirements/requirements/runtime.py @@ -20,6 +20,11 @@ _REQUIREMENTS_INPUTS_DIR = "requirements" _REQUIREMENTS_MODELS_MODULE = "specfact_cli.models.requirements" _REQUIREMENTS_CONTEXT_MODULE = "specfact_cli.requirements.context" +_REQUIREMENTS_PUBLIC_MODULE = "specfact_cli.requirements" +_NATIVE_IMPORT_HELPERS = { + "openspec": "import_openspec_change", + "speckit": "import_speckit_feature", +} class RequirementsCoreUnavailableError(RuntimeError): @@ -32,7 +37,7 @@ def _load_requirements_module(module_name: str, purpose: str) -> Any: except ImportError as exc: msg = ( f"specfact-requirements requires the paired specfact-cli {purpose} " - "from core change requirements-02-module-commands" + "from core change #350 (specfact-cli >=0.52.0)" ) raise RequirementsCoreUnavailableError(msg) from exc @@ -49,6 +54,30 @@ def _has_attributes(result: Any, *attributes: str) -> bool: return all(hasattr(result, attribute) for attribute in attributes) +def _diagnostic_is_error(diagnostic: Any) -> bool: + return str(getattr(diagnostic, "severity", "")) == "error" + + +@beartype +@require( + lambda import_result: all(hasattr(import_result, attribute) for attribute in ("requirements", "diagnostics")), + "import_result must expose requirements and diagnostics", +) +@ensure(lambda result: isinstance(result, bool)) +def import_result_has_errors(import_result: Any) -> bool: + """Return whether a core import result contains an error diagnostic.""" + return any(_diagnostic_is_error(diagnostic) for diagnostic in import_result.diagnostics) + + +def _core_import_helper(helper_name: str) -> Any: + core_requirements = _load_requirements_module(_REQUIREMENTS_PUBLIC_MODULE, "native requirement import helpers") + helper = getattr(core_requirements, helper_name, None) + if callable(helper): + return helper + msg = f"specfact-requirements requires specfact-cli >=0.52.0; missing core helper '{helper_name}' from change #350" + raise RequirementsCoreUnavailableError(msg) + + def _profile_aliases(profiles: frozenset[str]) -> frozenset[str]: aliases = set(profiles) aliases.update(profile.replace("_", "-") for profile in profiles) @@ -129,6 +158,15 @@ def _write_requirements_sidecar(bundle_dir: Path, records: Sequence[Any]) -> Non temporary_sidecar.unlink() +def _persist_imported_requirements(bundle_dir: Path, imported: Sequence[Any]) -> None: + context_helpers = _load_requirements_module(_REQUIREMENTS_CONTEXT_MODULE, "requirements context helpers") + bundle = _load_bundle_with_requirements(bundle_dir) + merged = merge_requirement_inputs(context_helpers.load_requirements_from_bundle(bundle), imported) + context_helpers.attach_requirements_to_bundle(bundle, merged) + save_project_bundle(bundle, bundle_dir, atomic=True) + _write_requirements_sidecar(bundle_dir, merged) + + @beartype @require(lambda source_file: source_file.is_file(), "source_file must exist") @ensure(_records_are_supported, "all loaded records must be RequirementInput or mapping values") @@ -175,23 +213,87 @@ def import_requirements_file_to_bundle(source_file: Path, bundle_dir: Path) -> A records = load_requirement_records(source_file) context_helpers = _load_requirements_module(_REQUIREMENTS_CONTEXT_MODULE, "requirements context helpers") result = context_helpers.normalize_requirement_records(records, source_locator=source_file.as_posix()) - bundle = _load_bundle_with_requirements(bundle_dir) - merged = merge_requirement_inputs(context_helpers.load_requirements_from_bundle(bundle), result.requirements) - context_helpers.attach_requirements_to_bundle(bundle, merged) - save_project_bundle(bundle, bundle_dir, atomic=True) - _write_requirements_sidecar(bundle_dir, merged) + _persist_imported_requirements(bundle_dir, result.requirements) return result @beartype +@require(lambda source_kind: source_kind in _NATIVE_IMPORT_HELPERS, "source_kind must be openspec or speckit") +@require(lambda source_dir: source_dir.is_dir(), "source_dir must exist") @require(lambda bundle_dir: bundle_dir.is_dir(), "bundle_dir must exist") -@require(is_requirement_context_profile_supported, "profile must be a known requirement context profile") +@ensure(lambda result: _has_attributes(result, "requirements", "diagnostics")) +def import_native_requirements_to_bundle(source_kind: str, source_dir: Path, bundle_dir: Path) -> Any: + """Delegate a native source import to core and persist only valid records.""" + result = _core_import_helper(_NATIVE_IMPORT_HELPERS[source_kind])(source_dir) + if not import_result_has_errors(result): + _persist_imported_requirements(bundle_dir, result.requirements) + return result + + +def _sole_source(candidates: list[Path], expected_layout: str) -> Path: + if len(candidates) == 1: + return candidates[0] + if not candidates: + raise ValueError(f"No import source found; expected {expected_layout}.") + names = ", ".join(candidate.name for candidate in candidates) + raise ValueError(f"Multiple import sources found ({names}); pass an explicit path instead of {expected_layout}.") + + +@beartype +@require(lambda project_root: project_root.is_dir(), "project_root must exist") +@ensure(lambda result: result.is_dir()) +def auto_detect_openspec_change(project_root: Path) -> Path: + """Return the single conventional OpenSpec change source below a project root.""" + changes_dir = project_root / "openspec" / "changes" + candidates = [path for path in sorted(changes_dir.iterdir()) if path.is_dir()] if changes_dir.is_dir() else [] + return _sole_source(candidates, "openspec/changes/") + + +@beartype +@require(lambda project_root: project_root.is_dir(), "project_root must exist") +@ensure(lambda result: result.is_dir()) +def auto_detect_speckit_feature(project_root: Path) -> Path: + """Return the single conventional Spec Kit feature source below a project root.""" + specs_dir = project_root / "specs" + candidates = ( + [path for path in sorted(specs_dir.iterdir()) if path.is_dir() and (path / "spec.md").is_file()] + if specs_dir.is_dir() + else [] + ) + return _sole_source(candidates, "specs//") + + +@beartype +@require(lambda bundle_dir: bundle_dir.is_dir(), "bundle_dir must exist") +@require( + lambda profile: profile is None or is_requirement_context_profile_supported(profile), + "profile must be a known requirement context profile when provided", +) @ensure(lambda result: isinstance(result, ValidationReport)) -def validate_requirements_bundle(bundle_dir: Path, *, profile: str = "startup") -> ValidationReport: +def validate_requirements_bundle(bundle_dir: Path, *, profile: str | None = None) -> ValidationReport: """Validate requirement context evidence usefulness for a bundle.""" bundle = _load_bundle_with_requirements(bundle_dir) context_helpers = _load_requirements_module(_REQUIREMENTS_CONTEXT_MODULE, "requirements context helpers") - return context_helpers.validate_requirement_context(bundle, profile=normalize_requirement_context_profile(profile)) + normalized_profile = normalize_requirement_context_profile(profile) if profile is not None else None + return context_helpers.validate_requirement_context(bundle, profile=normalized_profile, project_root=Path.cwd()) + + +@beartype +@require(lambda bundle_dir: bundle_dir.is_dir(), "bundle_dir must exist") +@require( + lambda profile: profile is None or is_requirement_context_profile_supported(profile), + "profile must be a known requirement context profile when provided", +) +@ensure(lambda result: all(isinstance(code, str) and isinstance(count, int) for code, count in result.items())) +def requirements_gate_finding_counts(bundle_dir: Path, *, profile: str | None = None) -> dict[str, int]: + """Count core validation findings without reimplementing their gate logic.""" + report = validate_requirements_bundle(bundle_dir, profile=profile) + counts: dict[str, int] = {} + for violation in report.violations: + code = violation.get("code") + if isinstance(code, str): + counts[code] = counts.get(code, 0) + 1 + return counts @beartype @@ -225,4 +327,5 @@ def list_requirements_with_coverage(bundle_dir: Path, *, show_coverage: bool = F } if show_coverage: payload["coverage"] = context_helpers.inspect_requirement_context_coverage(requirements).model_dump(mode="json") + payload["gate_finding_counts"] = requirements_gate_finding_counts(bundle_dir) return payload diff --git a/registry/index.json b/registry/index.json index 9844978..ec608dd 100644 --- a/registry/index.json +++ b/registry/index.json @@ -94,9 +94,9 @@ }, { "id": "nold-ai/specfact-requirements", - "latest_version": "0.1.5", - "download_url": "modules/specfact-requirements-0.1.5.tar.gz", - "checksum_sha256": "fd3f684be7d8ba76c16296c00e44f7ab05dbddf00b90bb716d5b9882bbc6745c", + "latest_version": "0.2.0", + "download_url": "modules/specfact-requirements-0.2.0.tar.gz", + "checksum_sha256": "981fff6c7ffe80607c7b6c21e059cc82ff6849737361463cf9595a5dccf17625", "tier": "official", "publisher": { "name": "nold-ai", @@ -105,7 +105,8 @@ "bundle_dependencies": [ "nold-ai/specfact-project" ], - "description": "Official SpecFact requirements evidence runtime bundle package." + "description": "Official SpecFact requirements evidence runtime bundle package.", + "core_compatibility": ">=0.52.0,<1.0.0" } ] } diff --git a/registry/modules/specfact-requirements-0.2.0.tar.gz b/registry/modules/specfact-requirements-0.2.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..9dd43faad6c97a4694563a5ae555cf9101a537bb GIT binary patch literal 5634 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 literal 0 HcmV?d00001 diff --git a/registry/modules/specfact-requirements-0.2.0.tar.gz.sha256 b/registry/modules/specfact-requirements-0.2.0.tar.gz.sha256 new file mode 100644 index 0000000..1a7a389 --- /dev/null +++ b/registry/modules/specfact-requirements-0.2.0.tar.gz.sha256 @@ -0,0 +1 @@ +981fff6c7ffe80607c7b6c21e059cc82ff6849737361463cf9595a5dccf17625 diff --git a/tests/integration/specfact_requirements/test_command_apps.py b/tests/integration/specfact_requirements/test_command_apps.py index 320e592..5f97921 100644 --- a/tests/integration/specfact_requirements/test_command_apps.py +++ b/tests/integration/specfact_requirements/test_command_apps.py @@ -49,6 +49,28 @@ def _source_file(tmp_path: Path) -> Path: return source +def _openspec_change(project_root: Path) -> Path: + change_dir = project_root / "openspec" / "changes" / "widget-evidence" + spec_path = change_dir / "specs" / "widgets" / "spec.md" + spec_path.parent.mkdir(parents=True) + spec_path.write_text( + """## ADDED Requirements + +### Requirement: Widget rendering + +The system SHALL render a widget. + +#### Scenario: Render a valid widget + +- **GIVEN** a valid widget request +- **WHEN** rendering runs +- **THEN** the widget is returned +""", + encoding="utf-8", + ) + return change_dir + + @pytest.mark.integration def test_command_module_exposes_typer_app() -> None: assert app is not None @@ -119,3 +141,47 @@ def test_requirements_help_exposes_no_author_command() -> None: assert "validate" in result.output assert "coverage" in result.output assert "author" not in result.output + + +@pytest.mark.integration +def test_requirements_import_openspec_accepts_explicit_and_auto_detected_sources( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + project_root = tmp_path / "project" + change_dir = _openspec_change(project_root) + explicit_bundle = _bundle_dir(tmp_path / "explicit") + + explicit_result = runner.invoke( + app, + ["import", "--from-openspec", str(change_dir), "--bundle", str(explicit_bundle), "--format", "json"], + ) + + assert explicit_result.exit_code == 0, explicit_result.output + assert json.loads(explicit_result.output)["imported"] == 1 + + auto_bundle = _bundle_dir(tmp_path / "auto") + monkeypatch.chdir(project_root) + auto_result = runner.invoke( + app, + ["import", "--from-openspec", "--bundle", str(auto_bundle), "--format", "json"], + ) + + assert auto_result.exit_code == 0, auto_result.output + assert json.loads(auto_result.output)["imported"] == 1 + + +@pytest.mark.integration +def test_requirements_import_surfaces_core_schema_rejection_without_persistence(tmp_path: Path) -> None: + project_root = tmp_path / "project" + change_dir = _openspec_change(project_root) + (project_root / "openspec" / "config.yaml").write_text("schema: company-custom\n", encoding="utf-8") + bundle_dir = _bundle_dir(tmp_path) + + result = runner.invoke( + app, + ["import", "--from-openspec", str(change_dir), "--bundle", str(bundle_dir), "--format", "json"], + ) + + assert result.exit_code == 1 + assert json.loads(result.output)["diagnostics"][0]["code"] == "unsupported-source-schema" + assert not (bundle_dir / "reports" / "requirements" / "inputs.yaml").exists() diff --git a/tests/unit/docs/test_bundle_overview_cli_examples.py b/tests/unit/docs/test_bundle_overview_cli_examples.py index aa3ce5c..63b8f87 100644 --- a/tests/unit/docs/test_bundle_overview_cli_examples.py +++ b/tests/unit/docs/test_bundle_overview_cli_examples.py @@ -60,6 +60,22 @@ "import", "--help", ], + ( + "specfact requirements import --from-openspec openspec/changes/widget-evidence " + "--bundle .specfact/projects/shop --format json" + ): [ + "requirements", + "import", + "--help", + ], + ( + "specfact requirements import --from-speckit specs/001-widget-rendering " + "--bundle .specfact/projects/shop --format json" + ): [ + "requirements", + "import", + "--help", + ], "specfact requirements list --bundle .specfact/projects/shop --show-coverage --format json": [ "requirements", "list", diff --git a/tests/unit/specfact_requirements/test_requirements_runtime.py b/tests/unit/specfact_requirements/test_requirements_runtime.py index 1059228..373462f 100644 --- a/tests/unit/specfact_requirements/test_requirements_runtime.py +++ b/tests/unit/specfact_requirements/test_requirements_runtime.py @@ -15,8 +15,10 @@ from specfact_requirements.requirements import runtime as requirements_runtime from specfact_requirements.requirements.runtime import ( RequirementsCoreUnavailableError, + import_native_requirements_to_bundle, import_requirements_file_to_bundle, list_requirements_with_coverage, + requirements_gate_finding_counts, validate_requirements_bundle, ) @@ -46,6 +48,55 @@ def _bundle_dir(tmp_path: Path) -> Path: return bundle_dir +def _openspec_change(project_root: Path) -> Path: + change_dir = project_root / "openspec" / "changes" / "widget-evidence" + spec_path = change_dir / "specs" / "widgets" / "spec.md" + spec_path.parent.mkdir(parents=True) + (change_dir / "proposal.md").write_text("# Change: Widget evidence\n", encoding="utf-8") + (change_dir / "tasks.md").write_text("# Tasks: Widget evidence\n", encoding="utf-8") + spec_path.write_text( + """## ADDED Requirements + +### Requirement: Widget rendering + +The system SHALL render a widget. + +#### Scenario: Render a valid widget + +- **GIVEN** a valid widget request +- **WHEN** rendering runs +- **THEN** the widget is returned +""", + encoding="utf-8", + ) + return change_dir + + +def _speckit_feature(project_root: Path) -> Path: + feature_dir = project_root / "specs" / "001-widget-rendering" + feature_dir.mkdir(parents=True) + (feature_dir / "spec.md").write_text( + """# Feature Specification: Widget rendering + +## User Scenarios & Testing + +### User Story 1 - Render widgets (Priority: P1) + +As a user, I want widgets rendered so that I can see them. + +**Acceptance Scenarios**: + +1. **Given** a valid widget request, **When** rendering runs, **Then** the widget is returned + +## Requirements + +- **FR-001**: System MUST render a widget +""", + encoding="utf-8", + ) + return feature_dir + + def _block_runtime_import(module_name: str) -> Callable[[str], ModuleType]: def blocked_import(name: str) -> ModuleType: if name == module_name: @@ -156,3 +207,65 @@ def test_list_requirements_with_coverage_is_machine_readable(tmp_path: Path) -> assert listing["requirements"][0]["title"] == "Requirement context is imported as validation evidence" assert listing["coverage"]["total_requirements"] == 1 assert listing["coverage"]["with_test_links"] == 1 + + +def test_import_openspec_change_persists_core_records_without_mutating_source(tmp_path: Path) -> None: + project_root = tmp_path / "project" + change_dir = _openspec_change(project_root) + before = {path.relative_to(change_dir): path.read_bytes() for path in change_dir.rglob("*") if path.is_file()} + bundle_dir = _bundle_dir(project_root) + + result = import_native_requirements_to_bundle("openspec", change_dir, bundle_dir) + + assert [record.requirement_id for record in result.requirements] == [ + "openspec:widget-evidence:widgets:widget-rendering" + ] + assert result.diagnostics == [] + assert list_requirements_with_coverage(bundle_dir)["requirements"][0]["requirement_id"] == ( + "openspec:widget-evidence:widgets:widget-rendering" + ) + after = {path.relative_to(change_dir): path.read_bytes() for path in change_dir.rglob("*") if path.is_file()} + assert after == before + + +def test_import_speckit_feature_persists_core_records(tmp_path: Path) -> None: + project_root = tmp_path / "project" + feature_dir = _speckit_feature(project_root) + bundle_dir = _bundle_dir(project_root) + + result = import_native_requirements_to_bundle("speckit", feature_dir, bundle_dir) + + assert [record.requirement_id for record in result.requirements] == ["speckit:001-widget-rendering:render-a-widget"] + assert result.diagnostics == [] + + +def test_import_rejected_by_core_does_not_persist_partial_sidecar(tmp_path: Path) -> None: + project_root = tmp_path / "project" + change_dir = _openspec_change(project_root) + (project_root / "openspec" / "config.yaml").write_text("schema: company-custom\n", encoding="utf-8") + bundle_dir = _bundle_dir(project_root) + + result = import_native_requirements_to_bundle("openspec", change_dir, bundle_dir) + + assert result.requirements == [] + assert [diagnostic.code for diagnostic in result.diagnostics] == ["unsupported-source-schema"] + assert not (bundle_dir / "reports" / "requirements" / "inputs.yaml").exists() + + +def test_profile_resolution_and_gate_counts_delegate_to_core(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: + project_root = tmp_path / "project" + change_dir = _openspec_change(project_root) + bundle_dir = _bundle_dir(project_root) + import_native_requirements_to_bundle("openspec", change_dir, bundle_dir) + config_dir = project_root / ".specfact" + config_dir.mkdir() + (config_dir / "config.yaml").write_text("profile: enterprise\n", encoding="utf-8") + monkeypatch.chdir(project_root) + + configured_report = validate_requirements_bundle(bundle_dir) + explicit_report = validate_requirements_bundle(bundle_dir, profile="solo") + gate_counts = requirements_gate_finding_counts(bundle_dir) + + assert configured_report.status == "failed" + assert explicit_report.status == "warnings" + assert gate_counts["scenario-unverified"] == 1 From c659c6a01bf69e8ce8e5e4e92db46c6eae8aa59f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 18:24:21 +0000 Subject: [PATCH 2/7] chore(modules): ci sign changed modules --- packages/specfact-requirements/module-package.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/specfact-requirements/module-package.yaml b/packages/specfact-requirements/module-package.yaml index dc34207..c8ffb5c 100644 --- a/packages/specfact-requirements/module-package.yaml +++ b/packages/specfact-requirements/module-package.yaml @@ -20,3 +20,4 @@ category: project bundle_group_command: requirements integrity: checksum: sha256:53ea098fe96803931e2865badd810b3386e1113fc3ad834dc77a56b975ba3691 + signature: zWMYnfmu6chrDW/47e5JdC+EctQibfqeOGXWjyOVLrTgtTkLh27tdqLEK4yG+veyVdSz28SiNi3qjNA2PBhNDw== From 2d4b987534da87e18c262403533e83b4cd8081cd Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Tue, 14 Jul 2026 20:30:08 +0200 Subject: [PATCH 3/7] fix(docs): update concurrent-ruby security patch --- docs/Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 783241a..82206bd 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -5,7 +5,7 @@ GEM public_suffix (>= 2.0.2, < 8.0) base64 (0.3.0) colorator (1.1.0) - concurrent-ruby (1.3.6) + concurrent-ruby (1.3.7) csv (3.3.5) em-websocket (0.5.3) eventmachine (>= 0.12.9) From 8714cf5710c5cf531b6ee40d897dc2de2209c0fd Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Tue, 14 Jul 2026 20:53:58 +0200 Subject: [PATCH 4/7] fix(requirements): address import review findings --- docs/bundles/requirements/overview.md | 2 +- docs/reference/commands.generated.json | 191 ++++++++++++++++-- docs/reference/commands.generated.md | 44 ++-- llms.txt | 44 ++-- .../openspec-01-intent-trace/TDD_EVIDENCE.md | 44 +++- .../openspec-01-intent-trace/design.md | 9 +- .../openspec-01-intent-trace/proposal.md | 4 +- .../specs/requirements-module/spec.md | 8 +- .../changes/openspec-01-intent-trace/tasks.md | 10 +- .../specfact-code-review/module-package.yaml | 5 +- .../tools/radon_runner.py | 17 +- .../specfact-requirements/module-package.yaml | 5 +- .../requirements/commands.py | 32 +-- .../requirements/runtime.py | 6 +- registry/index.json | 12 +- .../specfact-code-review-0.47.49.tar.gz | Bin 0 -> 62417 bytes ...specfact-code-review-0.47.49.tar.gz.sha256 | 1 + .../specfact-requirements-0.2.0.tar.gz | Bin 5634 -> 0 bytes .../specfact-requirements-0.2.0.tar.gz.sha256 | 1 - .../specfact-requirements-0.2.3.tar.gz | Bin 0 -> 5697 bytes .../specfact-requirements-0.2.3.tar.gz.sha256 | 1 + scripts/generate-command-overview.py | 12 +- .../test_command_apps.py | 64 ++++++ .../unit/docs/test_llms_overview_freshness.py | 10 + .../tools/test_radon_runner.py | 8 +- .../test_requirements_runtime.py | 11 + 26 files changed, 399 insertions(+), 142 deletions(-) create mode 100644 registry/modules/specfact-code-review-0.47.49.tar.gz create mode 100644 registry/modules/specfact-code-review-0.47.49.tar.gz.sha256 delete mode 100644 registry/modules/specfact-requirements-0.2.0.tar.gz delete mode 100644 registry/modules/specfact-requirements-0.2.0.tar.gz.sha256 create mode 100644 registry/modules/specfact-requirements-0.2.3.tar.gz create mode 100644 registry/modules/specfact-requirements-0.2.3.tar.gz.sha256 diff --git a/docs/bundles/requirements/overview.md b/docs/bundles/requirements/overview.md index 98c29e9..4d7076e 100644 --- a/docs/bundles/requirements/overview.md +++ b/docs/bundles/requirements/overview.md @@ -18,7 +18,7 @@ planning or product-management system. ## Prerequisites -- SpecFact CLI 0.52.0 or later +- SpecFact CLI `>=0.52.0,<1.0.0` - Bundle installed: `specfact module install nold-ai/specfact-requirements` - A project bundle directory, usually created by the [Project](/bundles/project/overview/) bundle - Local JSON or YAML requirement records with source attribution diff --git a/docs/reference/commands.generated.json b/docs/reference/commands.generated.json index 7583704..8a7d726 100644 --- a/docs/reference/commands.generated.json +++ b/docs/reference/commands.generated.json @@ -190,7 +190,13 @@ ] }, { - "arguments": [], + "arguments": [ + { + "name": "ADAPTER", + "nargs": 1, + "required": true + } + ], "bare_invocation": "executes", "command": "specfact backlog ceremony flow", "deprecated": false, @@ -206,7 +212,13 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "ADAPTER", + "nargs": 1, + "required": true + } + ], "bare_invocation": "executes", "command": "specfact backlog ceremony pi-summary", "deprecated": false, @@ -222,7 +234,13 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "ADAPTER", + "nargs": 1, + "required": true + } + ], "bare_invocation": "executes", "command": "specfact backlog ceremony planning", "deprecated": false, @@ -238,7 +256,13 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "ADAPTER", + "nargs": 1, + "required": true + } + ], "bare_invocation": "executes", "command": "specfact backlog ceremony refinement", "deprecated": false, @@ -252,7 +276,13 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "ADAPTER", + "nargs": 1, + "required": true + } + ], "bare_invocation": "executes", "command": "specfact backlog ceremony standup", "deprecated": false, @@ -268,7 +298,13 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "ADAPTER", + "nargs": 1, + "required": true + } + ], "bare_invocation": "executes", "command": "specfact backlog daily", "deprecated": false, @@ -359,7 +395,13 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "ITEM_ID", + "nargs": 1, + "required": true + } + ], "bare_invocation": "executes", "command": "specfact backlog delta impact", "deprecated": false, @@ -396,7 +438,13 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "ADAPTER_ARG", + "nargs": 1, + "required": false + } + ], "bare_invocation": "executes", "command": "specfact backlog delta status", "deprecated": false, @@ -500,7 +548,13 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "ADAPTER", + "nargs": 1, + "required": true + } + ], "bare_invocation": "executes", "command": "specfact backlog refine", "deprecated": false, @@ -665,7 +719,13 @@ ] }, { - "arguments": [], + "arguments": [ + { + "name": "BUNDLE", + "nargs": 1, + "required": false + } + ], "bare_invocation": "executes", "command": "specfact code drift detect", "deprecated": false, @@ -683,7 +743,13 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "BUNDLE", + "nargs": 1, + "required": false + } + ], "bare_invocation": "executes", "command": "specfact code import", "deprecated": false, @@ -737,7 +803,13 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "BUNDLE", + "nargs": 1, + "required": false + } + ], "bare_invocation": "executes", "command": "specfact code import from-code", "deprecated": false, @@ -975,7 +1047,13 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "FILES", + "nargs": -1, + "required": false + } + ], "bare_invocation": "executes", "command": "specfact code review review run", "deprecated": false, @@ -1043,7 +1121,18 @@ ] }, { - "arguments": [], + "arguments": [ + { + "name": "BUNDLE_NAME", + "nargs": 1, + "required": true + }, + { + "name": "REPO_PATH", + "nargs": 1, + "required": true + } + ], "bare_invocation": "executes", "command": "specfact code validate sidecar init", "deprecated": false, @@ -1057,7 +1146,18 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "BUNDLE_NAME", + "nargs": 1, + "required": true + }, + { + "name": "REPO_PATH", + "nargs": 1, + "required": true + } + ], "bare_invocation": "executes", "command": "specfact code validate sidecar run", "deprecated": false, @@ -1113,7 +1213,13 @@ ] }, { - "arguments": [], + "arguments": [ + { + "name": "BUNDLE", + "nargs": 1, + "required": false + } + ], "bare_invocation": "executes", "command": "specfact govern enforce sdd", "deprecated": false, @@ -1164,7 +1270,13 @@ ] }, { - "arguments": [], + "arguments": [ + { + "name": "PATCH_FILE", + "nargs": 1, + "required": true + } + ], "bare_invocation": "executes", "command": "specfact govern patch apply", "deprecated": false, @@ -1566,7 +1678,13 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "BUNDLE", + "nargs": 1, + "required": false + } + ], "bare_invocation": "executes", "command": "specfact project sync intelligent", "deprecated": false, @@ -1735,7 +1853,13 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "SOURCE_PATH", + "nargs": 1, + "required": false + } + ], "bare_invocation": "executes", "command": "specfact requirements import", "deprecated": false, @@ -1813,7 +1937,18 @@ ] }, { - "arguments": [], + "arguments": [ + { + "name": "OLD_SPEC", + "nargs": 1, + "required": true + }, + { + "name": "NEW_SPEC", + "nargs": 1, + "required": true + } + ], "bare_invocation": "executes", "command": "specfact spec backward-compat", "deprecated": false, @@ -1827,7 +1962,13 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "SPEC_PATH", + "nargs": 1, + "required": false + } + ], "bare_invocation": "executes", "command": "specfact spec generate-tests", "deprecated": false, @@ -1867,7 +2008,13 @@ "subcommands": [] }, { - "arguments": [], + "arguments": [ + { + "name": "SPEC_PATH", + "nargs": 1, + "required": false + } + ], "bare_invocation": "executes", "command": "specfact spec validate", "deprecated": false, diff --git a/docs/reference/commands.generated.md b/docs/reference/commands.generated.md index caa71e6..44291b6 100644 --- a/docs/reference/commands.generated.md +++ b/docs/reference/commands.generated.md @@ -21,32 +21,32 @@ This file is generated from the current module command trees. Do not edit by han | `specfact backlog auth github` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --base-url, --client-id, --scopes; args: - | - | | | `specfact backlog auth status` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | -; args: - | - | | | `specfact backlog ceremony` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | -; args: - | flow, pi-summary, planning, refinement, standup | | -| `specfact backlog ceremony flow` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: - | - | | -| `specfact backlog ceremony pi-summary` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: - | - | | -| `specfact backlog ceremony planning` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: - | - | | -| `specfact backlog ceremony refinement` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | -; args: - | - | | -| `specfact backlog ceremony standup` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: - | - | | -| `specfact backlog daily` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --ado-org, --ado-project, --ado-team, --ado-token, --annotations, --assignee, --blockers, --blockers-first, --comments, --copilot-export, --first-comments, --first-issues, --github-token, --id, --interactive, --iteration, --labels, --last-comments, --last-issues, --limit, --mode, --no-show-unassigned, --patch, --post, --release, --repo-name, --repo-owner, --search, --show-unassigned, --sprint, --state, --suggest-next, --summarize, --summarize-to, --tags, --today, --unassigned-only, --yesterday; args: - | - | | +| `specfact backlog ceremony flow` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: ADAPTER (required) | - | | +| `specfact backlog ceremony pi-summary` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: ADAPTER (required) | - | | +| `specfact backlog ceremony planning` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: ADAPTER (required) | - | | +| `specfact backlog ceremony refinement` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | -; args: ADAPTER (required) | - | | +| `specfact backlog ceremony standup` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: ADAPTER (required) | - | | +| `specfact backlog daily` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --ado-org, --ado-project, --ado-team, --ado-token, --annotations, --assignee, --blockers, --blockers-first, --comments, --copilot-export, --first-comments, --first-issues, --github-token, --id, --interactive, --iteration, --labels, --last-comments, --last-issues, --limit, --mode, --no-show-unassigned, --patch, --post, --release, --repo-name, --repo-owner, --search, --show-unassigned, --sprint, --state, --suggest-next, --summarize, --summarize-to, --tags, --today, --unassigned-only, --yesterday; args: ADAPTER (required) | - | | | `specfact backlog delta` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | -; args: - | cost-estimate, impact, rollback-analysis, status | | | `specfact backlog delta cost-estimate` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --baseline-file, --project-id, --template; args: - | - | | -| `specfact backlog delta impact` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --project-id, --template; args: - | - | | +| `specfact backlog delta impact` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --project-id, --template; args: ITEM_ID (required) | - | | | `specfact backlog delta rollback-analysis` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --baseline-file, --project-id, --template; args: - | - | | -| `specfact backlog delta status` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --baseline-file, --project-id, --repo-name, --repo-owner, --since, --template; args: - | - | | +| `specfact backlog delta status` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --baseline-file, --project-id, --repo-name, --repo-owner, --since, --template; args: ADAPTER_ARG | - | | | `specfact backlog diff` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --baseline-file, --project-id, --template; args: - | - | | | `specfact backlog init-config` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --force; args: - | - | | | `specfact backlog map-fields` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --ado-base-url, --ado-framework, --ado-org, --ado-project, --ado-token, --github-project-id, --github-project-v2-id, --github-type-field-id, --github-type-option, --non-interactive, --provider, --reset; args: - | - | | | `specfact backlog promote` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --item-id, --project-id, --template, --to-status; args: - | - | | -| `specfact backlog refine` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --ado-org, --ado-project, --ado-team, --ado-token, --assignee, --auto-accept-high-confidence, --auto-bundle, --bundle, --check-dor, --custom-field-mapping, --export-to-tmp, --first-comments, --first-issues, --framework, --github-token, --id, --ignore-refined, --import-from-tmp, --iteration, --labels, --last-comments, --last-issues, --limit, --no-ignore-refined, --no-preview, --openspec-comment, --persona, --preview, --release, --repo-name, --repo-owner, --search, --sprint, --state, --tags, --template, --tmp-file, --write; args: - | - | | +| `specfact backlog refine` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --ado-org, --ado-project, --ado-team, --ado-token, --assignee, --auto-accept-high-confidence, --auto-bundle, --bundle, --check-dor, --custom-field-mapping, --export-to-tmp, --first-comments, --first-issues, --framework, --github-token, --id, --ignore-refined, --import-from-tmp, --iteration, --labels, --last-comments, --last-issues, --limit, --no-ignore-refined, --no-preview, --openspec-comment, --persona, --preview, --release, --repo-name, --repo-owner, --search, --sprint, --state, --tags, --template, --tmp-file, --write; args: ADAPTER (required) | - | | | `specfact backlog sync` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --baseline-file, --force-baseline-overwrite, --output-format, --project-id, --template; args: - | - | | | `specfact backlog verify-readiness` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --project-id, --target-items, --template; args: - | - | | | `specfact code` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --install-completion, --show-completion; args: - | analyze, drift, import, repro, validate | | | `specfact code analyze` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | -; args: - | contracts | | | `specfact code analyze contracts` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --bundle, --repo; args: - | - | | | `specfact code drift` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | -; args: - | detect | | -| `specfact code drift detect` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --format, --out, --repo; args: - | - | | -| `specfact code import` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --confidence, --enrich-for-speckit, --enrichment, --entry-point, --exclude-tests, --force, --include-tests, --key-format, --no-enrich-for-speckit, --no-revalidate-features, --repo, --report, --revalidate-features, --shadow-only; args: - | from-bridge, from-code | | +| `specfact code drift detect` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --format, --out, --repo; args: BUNDLE | - | | +| `specfact code import` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --confidence, --enrich-for-speckit, --enrichment, --entry-point, --exclude-tests, --force, --include-tests, --key-format, --no-enrich-for-speckit, --no-revalidate-features, --repo, --report, --revalidate-features, --shadow-only; args: BUNDLE | from-bridge, from-code | | | `specfact code import from-bridge` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --adapter, --dry-run, --force, --out-branch, --repo, --report, --write; args: - | - | | -| `specfact code import from-code` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --confidence, --enrich-for-speckit, --enrichment, --entry-point, --exclude-tests, --force, --include-tests, --key-format, --no-enrich-for-speckit, --no-revalidate-features, --repo, --report, --revalidate-features, --shadow-only; args: - | - | | +| `specfact code import from-code` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --confidence, --enrich-for-speckit, --enrichment, --entry-point, --exclude-tests, --force, --include-tests, --key-format, --no-enrich-for-speckit, --no-revalidate-features, --repo, --report, --revalidate-features, --shadow-only; args: BUNDLE | - | | | `specfact code repro` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --budget, --crosshair-per-path-timeout, --crosshair-required, --fail-fast, --fix, --out, --repo, --sidecar, --sidecar-bundle, --verbose; args: - | setup | | | `specfact code repro setup` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --install-crosshair, --repo; args: - | - | | | `specfact code review` | nold-ai/specfact-code-review | `specfact module install nold-ai/specfact-code-review` | --install-completion, --show-completion; args: - | review | | @@ -59,17 +59,17 @@ This file is generated from the current module command trees. Do not edit by han | `specfact code review review rules init` | nold-ai/specfact-code-review | `specfact module install nold-ai/specfact-code-review` | --ide; args: - | - | | | `specfact code review review rules show` | nold-ai/specfact-code-review | `specfact module install nold-ai/specfact-code-review` | -; args: - | - | | | `specfact code review review rules update` | nold-ai/specfact-code-review | `specfact module install nold-ai/specfact-code-review` | --ide; args: - | - | | -| `specfact code review review run` | nold-ai/specfact-code-review | `specfact module install nold-ai/specfact-code-review` | --bug-hunt, --enforcement, --exclude-tests, --fix, --focus, --include-noise, --include-tests, --instructions, --interactive, --json, --level, --mode, --no-tests, --out, --path, --preview-fixes, --scope, --score-only, --suppress-noise, --with-mutation; args: - | - | | +| `specfact code review review run` | nold-ai/specfact-code-review | `specfact module install nold-ai/specfact-code-review` | --bug-hunt, --enforcement, --exclude-tests, --fix, --focus, --include-noise, --include-tests, --instructions, --interactive, --json, --level, --mode, --no-tests, --out, --path, --preview-fixes, --scope, --score-only, --suppress-noise, --with-mutation; args: FILES | - | | | `specfact code validate` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | -; args: - | sidecar | | | `specfact code validate sidecar` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | -; args: - | init, run | | -| `specfact code validate sidecar init` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | -; args: - | - | | -| `specfact code validate sidecar run` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --no-run-crosshair, --no-run-specmatic, --run-crosshair, --run-specmatic; args: - | - | | +| `specfact code validate sidecar init` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | -; args: BUNDLE_NAME (required), REPO_PATH (required) | - | | +| `specfact code validate sidecar run` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --no-run-crosshair, --no-run-specmatic, --run-crosshair, --run-specmatic; args: BUNDLE_NAME (required), REPO_PATH (required) | - | | | `specfact govern` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | --install-completion, --show-completion; args: - | enforce, patch | | | `specfact govern enforce` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | -; args: - | sdd, stage | | -| `specfact govern enforce sdd` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | --no-interactive, --out, --output-format, --sdd; args: - | - | | +| `specfact govern enforce sdd` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | --no-interactive, --out, --output-format, --sdd; args: BUNDLE | - | | | `specfact govern enforce stage` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | --preset; args: - | - | | | `specfact govern patch` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | -; args: - | apply | | -| `specfact govern patch apply` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | --dry-run, --write, --yes; args: - | - | | +| `specfact govern patch apply` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | --dry-run, --write, --yes; args: PATCH_FILE (required) | - | | | `specfact project` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --install-completion, --show-completion; args: - | devops-flow, export, export-roadmap, health-check, import, init-personas, link-backlog, lock, locks, merge, regenerate, resolve-conflict, snapshot, sync, unlock, version | | | `specfact project devops-flow` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --action, --bundle, --no-interactive, --project-name, --repo, --stage, --verbose; args: - | - | | | `specfact project export` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --bundle, --list-personas, --no-interactive, --out, --output, --output-dir, --persona, --repo, --stdout, --template; args: - | - | | @@ -86,7 +86,7 @@ This file is generated from the current module command trees. Do not edit by han | `specfact project snapshot` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --bundle, --no-interactive, --output, --project-name, --repo; args: - | - | | | `specfact project sync` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | -; args: - | bridge, intelligent, repository | | | `specfact project sync bridge` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --adapter, --add-progress-comment, --ado-base-url, --ado-org, --ado-project, --ado-token, --ado-work-item-type, --all, --backlog-ids, --backlog-ids-file, --bidirectional, --bundle, --change-ids, --code-repo, --ensure-compliance, --export-to-tmp, --external-base-path, --feature, --github-token, --import-from-tmp, --include-archived, --interactive, --interval, --mode, --no-add-progress-comment, --no-gh-cli, --no-include-archived, --no-sanitize, --no-track-code-changes, --no-update-existing, --overwrite, --repo, --repo-name, --repo-owner, --sanitize, --target-repo, --tmp-file, --track-code-changes, --update-existing, --use-gh-cli, --watch; args: - | - | | -| `specfact project sync intelligent` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --code-to-spec, --repo, --spec-to-code, --tests, --watch; args: - | - | | +| `specfact project sync intelligent` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --code-to-spec, --repo, --spec-to-code, --tests, --watch; args: BUNDLE | - | | | `specfact project sync repository` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --confidence, --interval, --repo, --target, --watch; args: - | - | | | `specfact project unlock` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --bundle, --no-interactive, --repo, --section; args: - | - | | | `specfact project version` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | -; args: - | bump, check, set | | @@ -95,11 +95,11 @@ This file is generated from the current module command trees. Do not edit by han | `specfact project version set` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --bundle, --repo, --version; args: - | - | | | `specfact requirements` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --install-completion, --show-completion; args: - | coverage, import, list, validate | | | `specfact requirements coverage` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format; args: - | - | | -| `specfact requirements import` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --from-file, --from-openspec, --from-speckit; args: - | - | | +| `specfact requirements import` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --from-file, --from-openspec, --from-speckit; args: SOURCE_PATH | - | | | `specfact requirements list` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --show-coverage; args: - | - | | | `specfact requirements validate` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --profile; args: - | - | | | `specfact spec` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | --install-completion, --show-completion; args: - | backward-compat, generate-tests, mock, validate | | -| `specfact spec backward-compat` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | -; args: - | - | | -| `specfact spec generate-tests` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | --bundle, --force, --out, --output; args: - | - | | +| `specfact spec backward-compat` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | -; args: OLD_SPEC (required), NEW_SPEC (required) | - | | +| `specfact spec generate-tests` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | --bundle, --force, --out, --output; args: SPEC_PATH | - | | | `specfact spec mock` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | --bundle, --examples, --no-interactive, --port, --spec, --strict; args: - | - | | -| `specfact spec validate` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | --bundle, --force, --no-interactive, --previous; args: - | - | | +| `specfact spec validate` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | --bundle, --force, --no-interactive, --previous; args: SPEC_PATH | - | | diff --git a/llms.txt b/llms.txt index 69d403c..f213369 100644 --- a/llms.txt +++ b/llms.txt @@ -25,32 +25,32 @@ This file is generated from the current module command trees. Do not edit by han | `specfact backlog auth github` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --base-url, --client-id, --scopes; args: - | - | | | `specfact backlog auth status` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | -; args: - | - | | | `specfact backlog ceremony` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | -; args: - | flow, pi-summary, planning, refinement, standup | | -| `specfact backlog ceremony flow` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: - | - | | -| `specfact backlog ceremony pi-summary` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: - | - | | -| `specfact backlog ceremony planning` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: - | - | | -| `specfact backlog ceremony refinement` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | -; args: - | - | | -| `specfact backlog ceremony standup` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: - | - | | -| `specfact backlog daily` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --ado-org, --ado-project, --ado-team, --ado-token, --annotations, --assignee, --blockers, --blockers-first, --comments, --copilot-export, --first-comments, --first-issues, --github-token, --id, --interactive, --iteration, --labels, --last-comments, --last-issues, --limit, --mode, --no-show-unassigned, --patch, --post, --release, --repo-name, --repo-owner, --search, --show-unassigned, --sprint, --state, --suggest-next, --summarize, --summarize-to, --tags, --today, --unassigned-only, --yesterday; args: - | - | | +| `specfact backlog ceremony flow` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: ADAPTER (required) | - | | +| `specfact backlog ceremony pi-summary` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: ADAPTER (required) | - | | +| `specfact backlog ceremony planning` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: ADAPTER (required) | - | | +| `specfact backlog ceremony refinement` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | -; args: ADAPTER (required) | - | | +| `specfact backlog ceremony standup` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --mode; args: ADAPTER (required) | - | | +| `specfact backlog daily` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --ado-org, --ado-project, --ado-team, --ado-token, --annotations, --assignee, --blockers, --blockers-first, --comments, --copilot-export, --first-comments, --first-issues, --github-token, --id, --interactive, --iteration, --labels, --last-comments, --last-issues, --limit, --mode, --no-show-unassigned, --patch, --post, --release, --repo-name, --repo-owner, --search, --show-unassigned, --sprint, --state, --suggest-next, --summarize, --summarize-to, --tags, --today, --unassigned-only, --yesterday; args: ADAPTER (required) | - | | | `specfact backlog delta` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | -; args: - | cost-estimate, impact, rollback-analysis, status | | | `specfact backlog delta cost-estimate` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --baseline-file, --project-id, --template; args: - | - | | -| `specfact backlog delta impact` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --project-id, --template; args: - | - | | +| `specfact backlog delta impact` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --project-id, --template; args: ITEM_ID (required) | - | | | `specfact backlog delta rollback-analysis` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --baseline-file, --project-id, --template; args: - | - | | -| `specfact backlog delta status` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --baseline-file, --project-id, --repo-name, --repo-owner, --since, --template; args: - | - | | +| `specfact backlog delta status` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --baseline-file, --project-id, --repo-name, --repo-owner, --since, --template; args: ADAPTER_ARG | - | | | `specfact backlog diff` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --baseline-file, --project-id, --template; args: - | - | | | `specfact backlog init-config` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --force; args: - | - | | | `specfact backlog map-fields` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --ado-base-url, --ado-framework, --ado-org, --ado-project, --ado-token, --github-project-id, --github-project-v2-id, --github-type-field-id, --github-type-option, --non-interactive, --provider, --reset; args: - | - | | | `specfact backlog promote` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --item-id, --project-id, --template, --to-status; args: - | - | | -| `specfact backlog refine` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --ado-org, --ado-project, --ado-team, --ado-token, --assignee, --auto-accept-high-confidence, --auto-bundle, --bundle, --check-dor, --custom-field-mapping, --export-to-tmp, --first-comments, --first-issues, --framework, --github-token, --id, --ignore-refined, --import-from-tmp, --iteration, --labels, --last-comments, --last-issues, --limit, --no-ignore-refined, --no-preview, --openspec-comment, --persona, --preview, --release, --repo-name, --repo-owner, --search, --sprint, --state, --tags, --template, --tmp-file, --write; args: - | - | | +| `specfact backlog refine` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --ado-org, --ado-project, --ado-team, --ado-token, --assignee, --auto-accept-high-confidence, --auto-bundle, --bundle, --check-dor, --custom-field-mapping, --export-to-tmp, --first-comments, --first-issues, --framework, --github-token, --id, --ignore-refined, --import-from-tmp, --iteration, --labels, --last-comments, --last-issues, --limit, --no-ignore-refined, --no-preview, --openspec-comment, --persona, --preview, --release, --repo-name, --repo-owner, --search, --sprint, --state, --tags, --template, --tmp-file, --write; args: ADAPTER (required) | - | | | `specfact backlog sync` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --baseline-file, --force-baseline-overwrite, --output-format, --project-id, --template; args: - | - | | | `specfact backlog verify-readiness` | nold-ai/specfact-backlog | `specfact module install nold-ai/specfact-backlog` | --adapter, --project-id, --target-items, --template; args: - | - | | | `specfact code` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --install-completion, --show-completion; args: - | analyze, drift, import, repro, validate | | | `specfact code analyze` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | -; args: - | contracts | | | `specfact code analyze contracts` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --bundle, --repo; args: - | - | | | `specfact code drift` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | -; args: - | detect | | -| `specfact code drift detect` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --format, --out, --repo; args: - | - | | -| `specfact code import` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --confidence, --enrich-for-speckit, --enrichment, --entry-point, --exclude-tests, --force, --include-tests, --key-format, --no-enrich-for-speckit, --no-revalidate-features, --repo, --report, --revalidate-features, --shadow-only; args: - | from-bridge, from-code | | +| `specfact code drift detect` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --format, --out, --repo; args: BUNDLE | - | | +| `specfact code import` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --confidence, --enrich-for-speckit, --enrichment, --entry-point, --exclude-tests, --force, --include-tests, --key-format, --no-enrich-for-speckit, --no-revalidate-features, --repo, --report, --revalidate-features, --shadow-only; args: BUNDLE | from-bridge, from-code | | | `specfact code import from-bridge` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --adapter, --dry-run, --force, --out-branch, --repo, --report, --write; args: - | - | | -| `specfact code import from-code` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --confidence, --enrich-for-speckit, --enrichment, --entry-point, --exclude-tests, --force, --include-tests, --key-format, --no-enrich-for-speckit, --no-revalidate-features, --repo, --report, --revalidate-features, --shadow-only; args: - | - | | +| `specfact code import from-code` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --confidence, --enrich-for-speckit, --enrichment, --entry-point, --exclude-tests, --force, --include-tests, --key-format, --no-enrich-for-speckit, --no-revalidate-features, --repo, --report, --revalidate-features, --shadow-only; args: BUNDLE | - | | | `specfact code repro` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --budget, --crosshair-per-path-timeout, --crosshair-required, --fail-fast, --fix, --out, --repo, --sidecar, --sidecar-bundle, --verbose; args: - | setup | | | `specfact code repro setup` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --install-crosshair, --repo; args: - | - | | | `specfact code review` | nold-ai/specfact-code-review | `specfact module install nold-ai/specfact-code-review` | --install-completion, --show-completion; args: - | review | | @@ -63,17 +63,17 @@ This file is generated from the current module command trees. Do not edit by han | `specfact code review review rules init` | nold-ai/specfact-code-review | `specfact module install nold-ai/specfact-code-review` | --ide; args: - | - | | | `specfact code review review rules show` | nold-ai/specfact-code-review | `specfact module install nold-ai/specfact-code-review` | -; args: - | - | | | `specfact code review review rules update` | nold-ai/specfact-code-review | `specfact module install nold-ai/specfact-code-review` | --ide; args: - | - | | -| `specfact code review review run` | nold-ai/specfact-code-review | `specfact module install nold-ai/specfact-code-review` | --bug-hunt, --enforcement, --exclude-tests, --fix, --focus, --include-noise, --include-tests, --instructions, --interactive, --json, --level, --mode, --no-tests, --out, --path, --preview-fixes, --scope, --score-only, --suppress-noise, --with-mutation; args: - | - | | +| `specfact code review review run` | nold-ai/specfact-code-review | `specfact module install nold-ai/specfact-code-review` | --bug-hunt, --enforcement, --exclude-tests, --fix, --focus, --include-noise, --include-tests, --instructions, --interactive, --json, --level, --mode, --no-tests, --out, --path, --preview-fixes, --scope, --score-only, --suppress-noise, --with-mutation; args: FILES | - | | | `specfact code validate` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | -; args: - | sidecar | | | `specfact code validate sidecar` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | -; args: - | init, run | | -| `specfact code validate sidecar init` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | -; args: - | - | | -| `specfact code validate sidecar run` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --no-run-crosshair, --no-run-specmatic, --run-crosshair, --run-specmatic; args: - | - | | +| `specfact code validate sidecar init` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | -; args: BUNDLE_NAME (required), REPO_PATH (required) | - | | +| `specfact code validate sidecar run` | nold-ai/specfact-codebase | `specfact module install nold-ai/specfact-codebase` | --no-run-crosshair, --no-run-specmatic, --run-crosshair, --run-specmatic; args: BUNDLE_NAME (required), REPO_PATH (required) | - | | | `specfact govern` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | --install-completion, --show-completion; args: - | enforce, patch | | | `specfact govern enforce` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | -; args: - | sdd, stage | | -| `specfact govern enforce sdd` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | --no-interactive, --out, --output-format, --sdd; args: - | - | | +| `specfact govern enforce sdd` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | --no-interactive, --out, --output-format, --sdd; args: BUNDLE | - | | | `specfact govern enforce stage` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | --preset; args: - | - | | | `specfact govern patch` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | -; args: - | apply | | -| `specfact govern patch apply` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | --dry-run, --write, --yes; args: - | - | | +| `specfact govern patch apply` | nold-ai/specfact-govern | `specfact module install nold-ai/specfact-govern` | --dry-run, --write, --yes; args: PATCH_FILE (required) | - | | | `specfact project` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --install-completion, --show-completion; args: - | devops-flow, export, export-roadmap, health-check, import, init-personas, link-backlog, lock, locks, merge, regenerate, resolve-conflict, snapshot, sync, unlock, version | | | `specfact project devops-flow` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --action, --bundle, --no-interactive, --project-name, --repo, --stage, --verbose; args: - | - | | | `specfact project export` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --bundle, --list-personas, --no-interactive, --out, --output, --output-dir, --persona, --repo, --stdout, --template; args: - | - | | @@ -90,7 +90,7 @@ This file is generated from the current module command trees. Do not edit by han | `specfact project snapshot` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --bundle, --no-interactive, --output, --project-name, --repo; args: - | - | | | `specfact project sync` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | -; args: - | bridge, intelligent, repository | | | `specfact project sync bridge` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --adapter, --add-progress-comment, --ado-base-url, --ado-org, --ado-project, --ado-token, --ado-work-item-type, --all, --backlog-ids, --backlog-ids-file, --bidirectional, --bundle, --change-ids, --code-repo, --ensure-compliance, --export-to-tmp, --external-base-path, --feature, --github-token, --import-from-tmp, --include-archived, --interactive, --interval, --mode, --no-add-progress-comment, --no-gh-cli, --no-include-archived, --no-sanitize, --no-track-code-changes, --no-update-existing, --overwrite, --repo, --repo-name, --repo-owner, --sanitize, --target-repo, --tmp-file, --track-code-changes, --update-existing, --use-gh-cli, --watch; args: - | - | | -| `specfact project sync intelligent` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --code-to-spec, --repo, --spec-to-code, --tests, --watch; args: - | - | | +| `specfact project sync intelligent` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --code-to-spec, --repo, --spec-to-code, --tests, --watch; args: BUNDLE | - | | | `specfact project sync repository` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --confidence, --interval, --repo, --target, --watch; args: - | - | | | `specfact project unlock` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --bundle, --no-interactive, --repo, --section; args: - | - | | | `specfact project version` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | -; args: - | bump, check, set | | @@ -99,11 +99,11 @@ This file is generated from the current module command trees. Do not edit by han | `specfact project version set` | nold-ai/specfact-project | `specfact module install nold-ai/specfact-project` | --bundle, --repo, --version; args: - | - | | | `specfact requirements` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --install-completion, --show-completion; args: - | coverage, import, list, validate | | | `specfact requirements coverage` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format; args: - | - | | -| `specfact requirements import` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --from-file, --from-openspec, --from-speckit; args: - | - | | +| `specfact requirements import` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --from-file, --from-openspec, --from-speckit; args: SOURCE_PATH | - | | | `specfact requirements list` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --show-coverage; args: - | - | | | `specfact requirements validate` | nold-ai/specfact-requirements | `specfact module install nold-ai/specfact-requirements` | --bundle, --format, --profile; args: - | - | | | `specfact spec` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | --install-completion, --show-completion; args: - | backward-compat, generate-tests, mock, validate | | -| `specfact spec backward-compat` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | -; args: - | - | | -| `specfact spec generate-tests` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | --bundle, --force, --out, --output; args: - | - | | +| `specfact spec backward-compat` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | -; args: OLD_SPEC (required), NEW_SPEC (required) | - | | +| `specfact spec generate-tests` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | --bundle, --force, --out, --output; args: SPEC_PATH | - | | | `specfact spec mock` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | --bundle, --examples, --no-interactive, --port, --spec, --strict; args: - | - | | -| `specfact spec validate` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | --bundle, --force, --no-interactive, --previous; args: - | - | | +| `specfact spec validate` | nold-ai/specfact-spec | `specfact module install nold-ai/specfact-spec` | --bundle, --force, --no-interactive, --previous; args: SPEC_PATH | - | | diff --git a/openspec/changes/openspec-01-intent-trace/TDD_EVIDENCE.md b/openspec/changes/openspec-01-intent-trace/TDD_EVIDENCE.md index 1c3bba2..1c1d014 100644 --- a/openspec/changes/openspec-01-intent-trace/TDD_EVIDENCE.md +++ b/openspec/changes/openspec-01-intent-trace/TDD_EVIDENCE.md @@ -10,7 +10,7 @@ ``` - Result: failed during collection, as expected before runtime implementation. -- Evidence: `ImportError: cannot import name 'import_openspec_change_to_bundle' from 'specfact_requirements.requirements.runtime'`. +- Evidence: `ImportError: cannot import name 'import_native_requirements_to_bundle' from 'specfact_requirements.requirements.runtime'`. The new tests cover OpenSpec and Spec Kit import delegation, read-only source behavior, no partial persistence for core `unsupported-source-schema`, @@ -26,20 +26,52 @@ auto-detected OpenSpec sources. hatch run pytest tests/unit/specfact_requirements/test_requirements_runtime.py tests/integration/specfact_requirements/test_command_apps.py -q ``` -- Result: `17 passed`. +- Result: `21 passed`. - The passing suite proves core-delegated OpenSpec and Spec Kit imports, read-only source handling, fail-closed schema rejection without a sidecar, layered-profile delegation, core gate-count presentation, and command-level explicit and auto-detected OpenSpec import behavior. +## Review-regression evidence + +- Date: 2026-07-14 (Europe/Berlin) +- Command: + + ```bash + hatch run pytest tests/unit/specfact_requirements/test_requirements_runtime.py tests/integration/specfact_requirements/test_command_apps.py -q + ``` + +- Failing-before result: 4 failures. OpenSpec auto-detection treated + `openspec/changes/archive/` as an import candidate; the CLI did not expose an + optional positional source path; and a regular-file source raised a runtime + contract violation instead of a CLI usage error. +- Passing-after result: `21 passed` after archive exclusion, typed optional + source-path parsing, explicit Spec Kit CLI coverage, and generated-command + metadata support were added. + +## Code-review regression evidence + +- Date: 2026-07-14 (Europe/Berlin) +- Command: + + ```bash + hatch run pytest tests/unit/specfact_code_review/tools/test_radon_runner.py -q + ``` + +- Failing-before result: `1 failed, 7 passed`; a Typer command without a + `ctx` parameter still produced `kiss.parameter-count.warning`. +- Passing-after result: `8 passed`; decorated Typer commands are exempt from + the parameter-count rule regardless of whether they accept a context. + ## Final quality gates -- `hatch run type-check -- packages/specfact-requirements/src tests/unit/specfact_requirements tests/integration/specfact_requirements` — passed with 0 errors. +- `hatch run type-check -- packages/specfact-requirements/src/specfact_requirements/requirements packages/specfact-code-review/src/specfact_code_review/tools/radon_runner.py tests/unit/specfact_requirements tests/integration/specfact_requirements/test_command_apps.py tests/unit/specfact_code_review/tools/test_radon_runner.py` — passed with 0 errors. - `hatch run lint` — passed. - `hatch run yaml-lint` — passed. - `hatch run check-bundle-imports` — passed. - `hatch run verify-modules-signature --payload-from-filesystem --enforce-version-bump --allow-missing-public-key` — passed for all manifests. - `hatch run contract-test` — passed (28 tests). -- `hatch run smart-test` — passed (878 tests). -- `hatch run test` — passed (878 tests, 2 third-party deprecation warnings). -- `hatch run specfact code review run --enforcement changed --bug-hunt --json --out .specfact/code-review.json` — passed with exit code 0. +- `hatch run smart-test` — passed (883 tests). +- `hatch run test` — passed (883 tests, 2 third-party deprecation warnings). +- `openspec validate openspec-01-intent-trace --strict` — passed. +- `hatch run specfact code review run --enforcement changed --bug-hunt --json --out /private/tmp/specfact-code-review-final.json` — passed with no findings. diff --git a/openspec/changes/openspec-01-intent-trace/design.md b/openspec/changes/openspec-01-intent-trace/design.md index b1c6747..9e22bd0 100644 --- a/openspec/changes/openspec-01-intent-trace/design.md +++ b/openspec/changes/openspec-01-intent-trace/design.md @@ -48,10 +48,11 @@ error instead of an ImportError traceback. ### D3: Auto-detection stays conservative -**Decision**: When the source path is omitted, detect only conventional -layouts (`openspec/changes/` for OpenSpec; Spec Kit `specs/` feature folders) -relative to the current project root. Ambiguity or absence is a clear error -naming the expected layouts, never a guess. +**Decision**: When the source path is omitted, detect only conventional active +layouts (`openspec/changes/`, excluding its `archive/` directory, for OpenSpec; +Spec Kit `specs/` feature folders) relative to the current project root. +Ambiguity or absence is a clear error naming the expected layouts, never a +guess. **Rationale**: Deterministic behavior over convenience heuristics; misdetected sources would poison evidence. diff --git a/openspec/changes/openspec-01-intent-trace/proposal.md b/openspec/changes/openspec-01-intent-trace/proposal.md index 00722ef..8e3458f 100644 --- a/openspec/changes/openspec-01-intent-trace/proposal.md +++ b/openspec/changes/openspec-01-intent-trace/proposal.md @@ -37,8 +37,8 @@ proposal (nold-ai/specfact-cli#350) for contract details. and Spec Kit `specs/`) relative to the project root. - **EXTEND**: `requirements validate` surfaces the core gate findings (`scenario-unverified`, `stale-import`, `source-missing`, - `ambiguous-mapping`, `unsupported-source-schema`) with profile-driven severity and non-zero exit on - failure; `list`/`coverage` output includes gate-relevant counts. + `ambiguous-mapping`) with profile-driven severity and non-zero exit on failure; + `list`/`coverage` output includes gate-relevant counts. - **EXTEND**: When `--profile` is omitted, the effective profile resolves from the layered configuration shipped by `profile-01-config-layering` instead of a hardcoded `startup` default; an explicit flag always wins. diff --git a/openspec/changes/openspec-01-intent-trace/specs/requirements-module/spec.md b/openspec/changes/openspec-01-intent-trace/specs/requirements-module/spec.md index 3b7acb9..81bb814 100644 --- a/openspec/changes/openspec-01-intent-trace/specs/requirements-module/spec.md +++ b/openspec/changes/openspec-01-intent-trace/specs/requirements-module/spec.md @@ -23,11 +23,13 @@ logic of its own and SHALL never write into upstream artifact directories. - **THEN** the core adapter normalizes the artifacts into requirement records - **AND** merged records persist to the bundle requirements sidecar. -#### Scenario: Omitted source paths auto-detect conventional layouts +#### Scenario: Omitted source paths auto-detect active conventional layouts -- **GIVEN** a project root containing an `openspec/changes/` directory +- **GIVEN** a project root containing one active OpenSpec change and an + `openspec/changes/archive/` directory - **WHEN** `specfact requirements import --from-openspec` runs without an explicit path -- **THEN** the conventional layout is detected and imported +- **THEN** the active conventional change layout is detected and imported +- **AND** the archive directory is not considered an import source - **AND** a clear error names the expected layouts when detection finds no source. #### Scenario: Validate surfaces gate findings with CI-usable exit codes diff --git a/openspec/changes/openspec-01-intent-trace/tasks.md b/openspec/changes/openspec-01-intent-trace/tasks.md index 3cab694..f46ff15 100644 --- a/openspec/changes/openspec-01-intent-trace/tasks.md +++ b/openspec/changes/openspec-01-intent-trace/tasks.md @@ -23,11 +23,11 @@ evidence in `TDD_EVIDENCE.md`. ## 3. Implementation -- [ ] 3.1 Extend `packages/specfact-requirements/.../commands.py` import command with `--from-openspec [PATH]` and `--from-speckit [PATH]` options. -- [ ] 3.2 Extend `runtime.py` with thin delegation to the new core normalizers via the existing `_load_requirements_module` pattern, including `RequirementsCoreUnavailableError` messaging. -- [ ] 3.3 Surface gate findings in `validate` output and gate-relevant counts in `list`/`coverage`. -- [ ] 3.3b Change the `validate` command's profile default from hardcoded `startup` to core layered-config resolution when the flag is omitted, and render core required-field advisories unchanged (delegated to the core helper; no config parsing or metadata enrichment in the module). -- [ ] 3.3c Surface core `unsupported-source-schema` results without fallback parsing or partial persistence. +- [x] 3.1 Extend `packages/specfact-requirements/.../commands.py` import command with `--from-openspec [PATH]` and `--from-speckit [PATH]` options. +- [x] 3.2 Extend `runtime.py` with thin delegation to the new core normalizers via the existing `_load_requirements_module` pattern, including `RequirementsCoreUnavailableError` messaging. +- [x] 3.3 Surface gate findings in `validate` output and gate-relevant counts in `list`/`coverage`. +- [x] 3.3b Change the `validate` command's profile default from hardcoded `startup` to core layered-config resolution when the flag is omitted, and render core required-field advisories unchanged (delegated to the core helper; no config parsing or metadata enrichment in the module). +- [x] 3.3c Surface core `unsupported-source-schema` results without fallback parsing or partial persistence. - [ ] 3.4 Contract decorators (`@beartype`, `@require`, `@ensure`) on all new public APIs. ## 4. Validation and documentation diff --git a/packages/specfact-code-review/module-package.yaml b/packages/specfact-code-review/module-package.yaml index 0e62afe..335552a 100644 --- a/packages/specfact-code-review/module-package.yaml +++ b/packages/specfact-code-review/module-package.yaml @@ -1,5 +1,5 @@ name: nold-ai/specfact-code-review -version: 0.47.48 +version: 0.47.49 commands: - code tier: official @@ -23,5 +23,4 @@ description: Official SpecFact code review bundle package. category: codebase bundle_group_command: code integrity: - checksum: sha256:666caa2524a6c569dbecc9450ef690035960de5232e6547904edd813bede2745 - signature: Yn9yF3FxljA4nzTnN8XtWph9v/K6jeg8mAkeBN/yDjx5sCeyKDQ9DWCHJhLtMeNbfW1cQESdAlC+P2KFx1fgCw== + checksum: sha256:6c227ffad4fb8c1c97c5c5d648883de6f544d6abcb07ed749b0c8310ccbd8590 diff --git a/packages/specfact-code-review/src/specfact_code_review/tools/radon_runner.py b/packages/specfact-code-review/src/specfact_code_review/tools/radon_runner.py index 7955dba..af623cd 100644 --- a/packages/specfact-code-review/src/specfact_code_review/tools/radon_runner.py +++ b/packages/specfact-code-review/src/specfact_code_review/tools/radon_runner.py @@ -167,12 +167,6 @@ def _kiss_nesting_findings( def _typer_cli_entrypoint_exempt(function_node: ast.FunctionDef | ast.AsyncFunctionDef, file_path: Path) -> bool: """Typer command callbacks legitimately take many injected options; skip parameter-count KISS on them.""" - args0 = function_node.args.args - if not args0: - return False - first = args0[0] - if first.arg != "ctx": - return False normalized = str(file_path).replace("\\", "/") # Stable path suffix: matches in-repo and user-scoped installs (~/.specfact/modules/.../src/...). # Typer CLI handler `run(ctx: Context, ...)` in review.commands injects many option parameters by @@ -180,16 +174,7 @@ def _typer_cli_entrypoint_exempt(function_node: ast.FunctionDef | ast.AsyncFunct # elsewhere still get complexity checks. if function_node.name == "run" and normalized.endswith("specfact_code_review/review/commands.py"): return True - if not _has_typer_command_decorator(function_node): - return False - ann = first.annotation - if ann is None: - return False - try: - rendered = ast.unparse(ann) - except AttributeError: - return False - return rendered.endswith("Context") + return _has_typer_command_decorator(function_node) def _decorator_name_parts(decorator: ast.expr) -> tuple[str, ...]: diff --git a/packages/specfact-requirements/module-package.yaml b/packages/specfact-requirements/module-package.yaml index c8ffb5c..97d3b72 100644 --- a/packages/specfact-requirements/module-package.yaml +++ b/packages/specfact-requirements/module-package.yaml @@ -1,5 +1,5 @@ name: nold-ai/specfact-requirements -version: 0.2.1 +version: 0.2.3 commands: - requirements tier: official @@ -19,5 +19,4 @@ description: Official SpecFact requirements evidence runtime bundle package. category: project bundle_group_command: requirements integrity: - checksum: sha256:53ea098fe96803931e2865badd810b3386e1113fc3ad834dc77a56b975ba3691 - signature: zWMYnfmu6chrDW/47e5JdC+EctQibfqeOGXWjyOVLrTgtTkLh27tdqLEK4yG+veyVdSz28SiNi3qjNA2PBhNDw== + checksum: sha256:02ae009efbaba529ba0b4abc14a0ca11c0d08d6451dff094236ce3e850f046a7 diff --git a/packages/specfact-requirements/src/specfact_requirements/requirements/commands.py b/packages/specfact-requirements/src/specfact_requirements/requirements/commands.py index c1e392a..a4af029 100644 --- a/packages/specfact-requirements/src/specfact_requirements/requirements/commands.py +++ b/packages/specfact-requirements/src/specfact_requirements/requirements/commands.py @@ -9,6 +9,7 @@ import typer from beartype import beartype +from click import Context from icontract import ensure, require from specfact_requirements.requirements.runtime import ( @@ -69,28 +70,27 @@ def _selected_import_source(from_file: Path | None, from_openspec: bool, from_sp return selected[0] -def _optional_source_path(ctx: typer.Context, source_name: str) -> Path | None: - if source_name == "file" and ctx.args: - raise typer.BadParameter("--from-file does not accept a positional source path") - if len(ctx.args) > 1: - raise typer.BadParameter("provide at most one source path") - return Path(ctx.args[0]) if ctx.args else None - - -@app.command( - "import", - help="Import local, OpenSpec, or Spec Kit requirement evidence into a project bundle.", - context_settings={"allow_extra_args": True}, -) +@app.command("import", help="Import local, OpenSpec, or Spec Kit requirement evidence into a project bundle.") +@beartype @require(lambda bundle: bundle.is_dir(), "bundle must exist") @require(_format_supported, "output format must be supported") @ensure(lambda result: result is None) def import_command( - ctx: typer.Context, + ctx: Context, bundle: Annotated[ Path, typer.Option("--bundle", exists=True, file_okay=False, dir_okay=True, readable=True, writable=True), ], + source_path: Annotated[ + Path | None, + typer.Argument( + exists=True, + file_okay=False, + dir_okay=True, + readable=True, + help="Optional OpenSpec change or Spec Kit feature directory.", + ), + ] = None, from_file: Annotated[ Path | None, typer.Option( @@ -112,9 +112,11 @@ def import_command( output_format: Annotated[OutputFormat, typer.Option("--format", help="Output format.")] = OutputFormat.TEXT, ) -> None: """Import one source of requirement evidence into a project bundle.""" + del ctx # Typer injects the Click context so the command remains compatible with context-aware tooling. source_name = _selected_import_source(from_file, from_openspec, from_speckit) - source_path = _optional_source_path(ctx, source_name) if source_name == "file": + if source_path is not None: + raise typer.BadParameter("--from-file does not accept a positional source path") if from_file is None: raise typer.BadParameter("--from-file requires a path") result = import_requirements_file_to_bundle(from_file, bundle) diff --git a/packages/specfact-requirements/src/specfact_requirements/requirements/runtime.py b/packages/specfact-requirements/src/specfact_requirements/requirements/runtime.py index 804966a..0cffe6e 100644 --- a/packages/specfact-requirements/src/specfact_requirements/requirements/runtime.py +++ b/packages/specfact-requirements/src/specfact_requirements/requirements/runtime.py @@ -245,7 +245,11 @@ def _sole_source(candidates: list[Path], expected_layout: str) -> Path: def auto_detect_openspec_change(project_root: Path) -> Path: """Return the single conventional OpenSpec change source below a project root.""" changes_dir = project_root / "openspec" / "changes" - candidates = [path for path in sorted(changes_dir.iterdir()) if path.is_dir()] if changes_dir.is_dir() else [] + candidates = ( + [path for path in sorted(changes_dir.iterdir()) if path.is_dir() and path.name != "archive"] + if changes_dir.is_dir() + else [] + ) return _sole_source(candidates, "openspec/changes/") diff --git a/registry/index.json b/registry/index.json index ec608dd..030cacb 100644 --- a/registry/index.json +++ b/registry/index.json @@ -78,9 +78,9 @@ }, { "id": "nold-ai/specfact-code-review", - "latest_version": "0.47.48", - "download_url": "modules/specfact-code-review-0.47.48.tar.gz", - "checksum_sha256": "dc41ee6a479bbc07f74670ff99f995ae75246da0ad94678957b8efbde1717501", + "latest_version": "0.47.49", + "download_url": "modules/specfact-code-review-0.47.49.tar.gz", + "checksum_sha256": "fb87c809d36770cd661e18a473fe0f41f3d930b51b2248c04315b37d6319c162", "core_compatibility": ">=0.44.0,<1.0.0", "tier": "official", "publisher": { @@ -94,9 +94,9 @@ }, { "id": "nold-ai/specfact-requirements", - "latest_version": "0.2.0", - "download_url": "modules/specfact-requirements-0.2.0.tar.gz", - "checksum_sha256": "981fff6c7ffe80607c7b6c21e059cc82ff6849737361463cf9595a5dccf17625", + "latest_version": "0.2.3", + "download_url": "modules/specfact-requirements-0.2.3.tar.gz", + "checksum_sha256": "98e343595ef4b2a63e8f5375a7f546774c3c3aee918a0f24370a52ba3369e4c6", "tier": "official", "publisher": { "name": "nold-ai", diff --git a/registry/modules/specfact-code-review-0.47.49.tar.gz b/registry/modules/specfact-code-review-0.47.49.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..7339cbcac548ba387f4368a1f4373757ad756fbf GIT binary patch literal 62417 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 literal 0 HcmV?d00001 diff --git a/registry/modules/specfact-code-review-0.47.49.tar.gz.sha256 b/registry/modules/specfact-code-review-0.47.49.tar.gz.sha256 new file mode 100644 index 0000000..2f8fae4 --- /dev/null +++ b/registry/modules/specfact-code-review-0.47.49.tar.gz.sha256 @@ -0,0 +1 @@ +fb87c809d36770cd661e18a473fe0f41f3d930b51b2248c04315b37d6319c162 diff --git a/registry/modules/specfact-requirements-0.2.0.tar.gz b/registry/modules/specfact-requirements-0.2.0.tar.gz deleted file mode 100644 index 9dd43faad6c97a4694563a5ae555cf9101a537bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5634 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 diff --git a/registry/modules/specfact-requirements-0.2.0.tar.gz.sha256 b/registry/modules/specfact-requirements-0.2.0.tar.gz.sha256 deleted file mode 100644 index 1a7a389..0000000 --- a/registry/modules/specfact-requirements-0.2.0.tar.gz.sha256 +++ /dev/null @@ -1 +0,0 @@ -981fff6c7ffe80607c7b6c21e059cc82ff6849737361463cf9595a5dccf17625 diff --git a/registry/modules/specfact-requirements-0.2.3.tar.gz b/registry/modules/specfact-requirements-0.2.3.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..bf100e18124d57617985f016528f1f5645c9d86b GIT binary patch literal 5697 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 literal 0 HcmV?d00001 diff --git a/registry/modules/specfact-requirements-0.2.3.tar.gz.sha256 b/registry/modules/specfact-requirements-0.2.3.tar.gz.sha256 new file mode 100644 index 0000000..8a8ecea --- /dev/null +++ b/registry/modules/specfact-requirements-0.2.3.tar.gz.sha256 @@ -0,0 +1 @@ +98e343595ef4b2a63e8f5375a7f546774c3c3aee918a0f24370a52ba3369e4c6 diff --git a/scripts/generate-command-overview.py b/scripts/generate-command-overview.py index e8419bd..65d867f 100644 --- a/scripts/generate-command-overview.py +++ b/scripts/generate-command-overview.py @@ -154,8 +154,8 @@ def validate_official_mount_inventory() -> None: def _command_options(command: click.Command) -> list[str]: options: set[str] = set() for param in command.params: - if hasattr(param, "opts"): - secondary_opts = getattr(param, "secondary_opts", ()) + if isinstance(param, click.Option): + secondary_opts = param.secondary_opts options.update(opt for opt in [*param.opts, *secondary_opts] if opt.startswith("--")) return sorted(options) @@ -163,7 +163,7 @@ def _command_options(command: click.Command) -> list[str]: def _command_arguments(command: click.Command) -> list[dict[str, Any]]: arguments: list[dict[str, Any]] = [] for param in command.params: - if not hasattr(param, "opts") and hasattr(param, "human_readable_name"): + if isinstance(param, click.Argument): arguments.append( { "name": param.human_readable_name, @@ -208,10 +208,10 @@ def _has_bare_business_parameters(command: click.Command) -> bool: "--show-completion", } for param in command.params: - if not hasattr(param, "opts") and hasattr(param, "human_readable_name"): + if isinstance(param, click.Argument): return True - if hasattr(param, "opts"): - opts = set(param.opts) | set(getattr(param, "secondary_opts", ())) + if isinstance(param, click.Option): + opts = set(param.opts) | set(param.secondary_opts) if opts and opts.isdisjoint(ignored_options): return True return False diff --git a/tests/integration/specfact_requirements/test_command_apps.py b/tests/integration/specfact_requirements/test_command_apps.py index 5f97921..4eefe7a 100644 --- a/tests/integration/specfact_requirements/test_command_apps.py +++ b/tests/integration/specfact_requirements/test_command_apps.py @@ -71,6 +71,31 @@ def _openspec_change(project_root: Path) -> Path: return change_dir +def _speckit_feature(project_root: Path) -> Path: + feature_dir = project_root / "specs" / "001-widget-rendering" + feature_dir.mkdir(parents=True) + (feature_dir / "spec.md").write_text( + """# Feature Specification: Widget rendering + +## User Scenarios & Testing + +### User Story 1 - Render widgets (Priority: P1) + +As a user, I want widgets rendered so that I can see them. + +**Acceptance Scenarios**: + +1. **Given** a valid widget request, **When** rendering runs, **Then** the widget is returned + +## Requirements + +- **FR-001**: System MUST render a widget +""", + encoding="utf-8", + ) + return feature_dir + + @pytest.mark.integration def test_command_module_exposes_typer_app() -> None: assert app is not None @@ -143,6 +168,14 @@ def test_requirements_help_exposes_no_author_command() -> None: assert "author" not in result.output +@pytest.mark.integration +def test_requirements_import_help_exposes_optional_native_source_path() -> None: + result = runner.invoke(app, ["import", "--help"]) + + assert result.exit_code == 0 + assert "[SOURCE_PATH]" in result.output + + @pytest.mark.integration def test_requirements_import_openspec_accepts_explicit_and_auto_detected_sources( tmp_path: Path, monkeypatch: pytest.MonkeyPatch @@ -160,6 +193,7 @@ def test_requirements_import_openspec_accepts_explicit_and_auto_detected_sources assert json.loads(explicit_result.output)["imported"] == 1 auto_bundle = _bundle_dir(tmp_path / "auto") + (project_root / "openspec" / "changes" / "archive" / "2026-07-14-widget-evidence").mkdir(parents=True) monkeypatch.chdir(project_root) auto_result = runner.invoke( app, @@ -170,6 +204,36 @@ def test_requirements_import_openspec_accepts_explicit_and_auto_detected_sources assert json.loads(auto_result.output)["imported"] == 1 +@pytest.mark.integration +def test_requirements_import_speckit_accepts_explicit_source(tmp_path: Path) -> None: + project_root = tmp_path / "project" + feature_dir = _speckit_feature(project_root) + bundle_dir = _bundle_dir(tmp_path) + + result = runner.invoke( + app, + ["import", "--from-speckit", str(feature_dir), "--bundle", str(bundle_dir), "--format", "json"], + ) + + assert result.exit_code == 0, result.output + assert json.loads(result.output)["imported"] == 1 + + +@pytest.mark.integration +def test_requirements_import_rejects_non_directory_native_source_path(tmp_path: Path) -> None: + bundle_dir = _bundle_dir(tmp_path) + source_file = tmp_path / "source.md" + source_file.write_text("not a source directory\n", encoding="utf-8") + + result = runner.invoke( + app, + ["import", "--from-openspec", str(source_file), "--bundle", str(bundle_dir), "--format", "json"], + ) + + assert result.exit_code == 2 + assert "Invalid value" in result.output + + @pytest.mark.integration def test_requirements_import_surfaces_core_schema_rejection_without_persistence(tmp_path: Path) -> None: project_root = tmp_path / "project" diff --git a/tests/unit/docs/test_llms_overview_freshness.py b/tests/unit/docs/test_llms_overview_freshness.py index c04585b..5a3e078 100644 --- a/tests/unit/docs/test_llms_overview_freshness.py +++ b/tests/unit/docs/test_llms_overview_freshness.py @@ -13,6 +13,7 @@ import sys from pathlib import Path +import click import pytest from tests.unit._script_test_utils import load_module_from_path @@ -52,6 +53,15 @@ def test_llms_and_command_overview_are_current() -> None: ) +def test_command_overview_records_optional_click_arguments() -> None: + generator = load_module_from_path("generate_command_overview_arguments", GENERATOR) + command = click.Command("import", params=[click.Argument(["source_path"], required=False)]) + + assert generator._command_arguments(command) == [ # pylint: disable=protected-access + {"name": "SOURCE_PATH", "required": False, "nargs": 1} + ] + + def test_command_overview_rejects_unrepresented_official_inventory(tmp_path: Path, monkeypatch) -> None: generator = load_module_from_path("generate_command_overview_inventory", GENERATOR) manifest = tmp_path / "packages" / "specfact-example" / "module-package.yaml" diff --git a/tests/unit/specfact_code_review/tools/test_radon_runner.py b/tests/unit/specfact_code_review/tools/test_radon_runner.py index e3c32e5..521bccf 100644 --- a/tests/unit/specfact_code_review/tools/test_radon_runner.py +++ b/tests/unit/specfact_code_review/tools/test_radon_runner.py @@ -17,7 +17,7 @@ def test_run_radon_returns_empty_when_only_non_python_paths(tmp_path: Path, monk run_mock = Mock() monkeypatch.setattr(subprocess, "run", run_mock) - assert run_radon([manifest]) == [] + assert not run_radon([manifest]) run_mock.assert_not_called() @@ -60,7 +60,7 @@ def test_run_radon_returns_no_findings_for_complexity_twelve_or_below(tmp_path: findings = run_radon([file_path]) - assert findings == [] + assert not findings def test_run_radon_returns_tool_error_on_parse_error(tmp_path: Path, monkeypatch: MonkeyPatch) -> None: @@ -131,12 +131,12 @@ def callback(ctx: typer.Context, a: str, b: str, c: str, d: str, e: str) -> None assert "kiss.parameter-count.warning" in {finding.rule for finding in findings} -def test_run_radon_exempts_typer_command_context_parameters(tmp_path: Path, monkeypatch: MonkeyPatch) -> None: +def test_run_radon_exempts_typer_command_parameters_without_context(tmp_path: Path, monkeypatch: MonkeyPatch) -> None: file_path = tmp_path / "commands.py" file_path.write_text( """ @app.command("run") -def callback(ctx: typer.Context, a: str, b: str, c: str, d: str, e: str) -> None: +def callback(a: str, b: str, c: str, d: str, e: str, f: str) -> None: return None """, encoding="utf-8", diff --git a/tests/unit/specfact_requirements/test_requirements_runtime.py b/tests/unit/specfact_requirements/test_requirements_runtime.py index 373462f..3f54dae 100644 --- a/tests/unit/specfact_requirements/test_requirements_runtime.py +++ b/tests/unit/specfact_requirements/test_requirements_runtime.py @@ -15,6 +15,7 @@ from specfact_requirements.requirements import runtime as requirements_runtime from specfact_requirements.requirements.runtime import ( RequirementsCoreUnavailableError, + auto_detect_openspec_change, import_native_requirements_to_bundle, import_requirements_file_to_bundle, list_requirements_with_coverage, @@ -239,6 +240,16 @@ def test_import_speckit_feature_persists_core_records(tmp_path: Path) -> None: assert result.diagnostics == [] +def test_auto_detect_openspec_change_ignores_archive_directory(tmp_path: Path) -> None: + project_root = tmp_path / "project" + change_dir = _openspec_change(project_root) + (project_root / "openspec" / "changes" / "archive" / "2026-07-14-widget-evidence").mkdir(parents=True) + + detected = auto_detect_openspec_change(project_root) + + assert detected == change_dir + + def test_import_rejected_by_core_does_not_persist_partial_sidecar(tmp_path: Path) -> None: project_root = tmp_path / "project" change_dir = _openspec_change(project_root) From 32935b07b34dd295196f13affe64b7f874d08010 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 18:59:00 +0000 Subject: [PATCH 5/7] chore(modules): ci sign changed modules --- packages/specfact-code-review/module-package.yaml | 1 + packages/specfact-requirements/module-package.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/specfact-code-review/module-package.yaml b/packages/specfact-code-review/module-package.yaml index 335552a..68e0112 100644 --- a/packages/specfact-code-review/module-package.yaml +++ b/packages/specfact-code-review/module-package.yaml @@ -24,3 +24,4 @@ category: codebase bundle_group_command: code integrity: checksum: sha256:6c227ffad4fb8c1c97c5c5d648883de6f544d6abcb07ed749b0c8310ccbd8590 + signature: yLg0zSLJzXrfnpw/VNvdRX628GLRQjmtcNK1slVKK6qBjLQ80SLbj6yqEjQp9eZGhb+XkhdnwJx2/Fjnn8XdCw== diff --git a/packages/specfact-requirements/module-package.yaml b/packages/specfact-requirements/module-package.yaml index 97d3b72..a5ab3c8 100644 --- a/packages/specfact-requirements/module-package.yaml +++ b/packages/specfact-requirements/module-package.yaml @@ -20,3 +20,4 @@ category: project bundle_group_command: requirements integrity: checksum: sha256:02ae009efbaba529ba0b4abc14a0ca11c0d08d6451dff094236ce3e850f046a7 + signature: 2WfMBL5+ISTzij7cpqX25K2blP7XXG52jcWc43xE8lPEJE8AKnMsYzZfArd75VVPjTS1kPqzwKxmGlGwodpaDg== From 4d13b3bd5b6079b934b9e1bc74ed7b84b720d630 Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Tue, 14 Jul 2026 21:33:17 +0200 Subject: [PATCH 6/7] fix(code-review): narrow Typer callback exemption --- .../openspec-01-intent-trace/TDD_EVIDENCE.md | 9 +- .../specfact-code-review/module-package.yaml | 5 +- .../tools/radon_runner.py | 82 ++++++++++++++++-- registry/index.json | 6 +- .../specfact-code-review-0.47.49.tar.gz | Bin 62417 -> 0 bytes ...specfact-code-review-0.47.49.tar.gz.sha256 | 1 - .../specfact-code-review-0.47.51.tar.gz | Bin 0 -> 62832 bytes ...specfact-code-review-0.47.51.tar.gz.sha256 | 1 + .../tools/test_radon_runner.py | 79 ++++++++++------- 9 files changed, 132 insertions(+), 51 deletions(-) delete mode 100644 registry/modules/specfact-code-review-0.47.49.tar.gz delete mode 100644 registry/modules/specfact-code-review-0.47.49.tar.gz.sha256 create mode 100644 registry/modules/specfact-code-review-0.47.51.tar.gz create mode 100644 registry/modules/specfact-code-review-0.47.51.tar.gz.sha256 diff --git a/openspec/changes/openspec-01-intent-trace/TDD_EVIDENCE.md b/openspec/changes/openspec-01-intent-trace/TDD_EVIDENCE.md index 1c1d014..889e349 100644 --- a/openspec/changes/openspec-01-intent-trace/TDD_EVIDENCE.md +++ b/openspec/changes/openspec-01-intent-trace/TDD_EVIDENCE.md @@ -60,8 +60,9 @@ auto-detected OpenSpec sources. - Failing-before result: `1 failed, 7 passed`; a Typer command without a `ctx` parameter still produced `kiss.parameter-count.warning`. -- Passing-after result: `8 passed`; decorated Typer commands are exempt from - the parameter-count rule regardless of whether they accept a context. +- Passing-after result: `9 passed`; commands are exempt only when their + decorator is owned by a statically identified Typer application, regardless + of whether they accept a context. ## Final quality gates @@ -71,7 +72,7 @@ auto-detected OpenSpec sources. - `hatch run check-bundle-imports` — passed. - `hatch run verify-modules-signature --payload-from-filesystem --enforce-version-bump --allow-missing-public-key` — passed for all manifests. - `hatch run contract-test` — passed (28 tests). -- `hatch run smart-test` — passed (883 tests). -- `hatch run test` — passed (883 tests, 2 third-party deprecation warnings). +- `hatch run smart-test` — passed (884 tests). +- `hatch run test` — passed (884 tests, 2 third-party deprecation warnings). - `openspec validate openspec-01-intent-trace --strict` — passed. - `hatch run specfact code review run --enforcement changed --bug-hunt --json --out /private/tmp/specfact-code-review-final.json` — passed with no findings. diff --git a/packages/specfact-code-review/module-package.yaml b/packages/specfact-code-review/module-package.yaml index 68e0112..f6f3821 100644 --- a/packages/specfact-code-review/module-package.yaml +++ b/packages/specfact-code-review/module-package.yaml @@ -1,5 +1,5 @@ name: nold-ai/specfact-code-review -version: 0.47.49 +version: 0.47.51 commands: - code tier: official @@ -23,5 +23,4 @@ description: Official SpecFact code review bundle package. category: codebase bundle_group_command: code integrity: - checksum: sha256:6c227ffad4fb8c1c97c5c5d648883de6f544d6abcb07ed749b0c8310ccbd8590 - signature: yLg0zSLJzXrfnpw/VNvdRX628GLRQjmtcNK1slVKK6qBjLQ80SLbj6yqEjQp9eZGhb+XkhdnwJx2/Fjnn8XdCw== + checksum: sha256:f85ae00bc406952621b590367370ef7a9d28acbc26703befa5b1b1a76a6ef516 diff --git a/packages/specfact-code-review/src/specfact_code_review/tools/radon_runner.py b/packages/specfact-code-review/src/specfact_code_review/tools/radon_runner.py index af623cd..2ac30b6 100644 --- a/packages/specfact-code-review/src/specfact_code_review/tools/radon_runner.py +++ b/packages/specfact-code-review/src/specfact_code_review/tools/radon_runner.py @@ -106,13 +106,14 @@ def _kiss_metric_findings(file_path: Path) -> list[ReviewFinding]: except (OSError, SyntaxError) as exc: return _tool_error(file_path, f"Unable to parse source for KISS metrics: {exc}") + typer_command_targets = _typer_command_targets(tree) findings: list[ReviewFinding] = [] for function_node in ast.walk(tree): if not isinstance(function_node, ast.FunctionDef | ast.AsyncFunctionDef): continue findings.extend(_kiss_loc_findings(function_node, file_path)) findings.extend(_kiss_nesting_findings(function_node, file_path)) - findings.extend(_kiss_parameter_findings(function_node, file_path)) + findings.extend(_kiss_parameter_findings(function_node, file_path, typer_command_targets)) return findings @@ -165,7 +166,9 @@ def _kiss_nesting_findings( return findings -def _typer_cli_entrypoint_exempt(function_node: ast.FunctionDef | ast.AsyncFunctionDef, file_path: Path) -> bool: +def _typer_cli_entrypoint_exempt( + function_node: ast.FunctionDef | ast.AsyncFunctionDef, file_path: Path, typer_command_targets: set[str] +) -> bool: """Typer command callbacks legitimately take many injected options; skip parameter-count KISS on them.""" normalized = str(file_path).replace("\\", "/") # Stable path suffix: matches in-repo and user-scoped installs (~/.specfact/modules/.../src/...). @@ -174,7 +177,7 @@ def _typer_cli_entrypoint_exempt(function_node: ast.FunctionDef | ast.AsyncFunct # elsewhere still get complexity checks. if function_node.name == "run" and normalized.endswith("specfact_code_review/review/commands.py"): return True - return _has_typer_command_decorator(function_node) + return _has_typer_command_decorator(function_node, typer_command_targets) def _decorator_name_parts(decorator: ast.expr) -> tuple[str, ...]: @@ -187,21 +190,82 @@ def _decorator_name_parts(decorator: ast.expr) -> tuple[str, ...]: return () -def _has_typer_command_decorator(function_node: ast.FunctionDef | ast.AsyncFunctionDef) -> bool: +def _typer_command_targets(tree: ast.Module) -> set[str]: + """Return names that own Typer command or callback decorators in a module.""" + typer_module_names = _typer_module_names(tree) + typer_constructor_names = _typer_constructor_names(tree) + return typer_module_names | _typer_application_names(tree, typer_module_names, typer_constructor_names) + + +def _typer_module_names(tree: ast.Module) -> set[str]: + names: set[str] = set() + for node in tree.body: + if not isinstance(node, ast.Import): + continue + for alias in node.names: + if alias.name == "typer": + names.add(alias.asname or alias.name) + return names + + +def _typer_constructor_names(tree: ast.Module) -> set[str]: + names: set[str] = set() + for node in tree.body: + if not isinstance(node, ast.ImportFrom) or node.module != "typer": + continue + for alias in node.names: + if alias.name == "Typer": + names.add(alias.asname or alias.name) + return names + + +def _typer_application_names( + tree: ast.Module, typer_module_names: set[str], typer_constructor_names: set[str] +) -> set[str]: + names: set[str] = set() + for node in tree.body: + if isinstance(node, ast.Assign | ast.AnnAssign) and _is_typer_constructor( + node.value, typer_module_names, typer_constructor_names + ): + names.update(_assignment_target_names(node)) + return names + + +def _is_typer_constructor( + value: ast.expr | None, typer_module_names: set[str], typer_constructor_names: set[str] +) -> bool: + if not isinstance(value, ast.Call): + return False + if isinstance(value.func, ast.Name): + return value.func.id in typer_constructor_names + return ( + isinstance(value.func, ast.Attribute) + and isinstance(value.func.value, ast.Name) + and value.func.value.id in typer_module_names + and value.func.attr == "Typer" + ) + + +def _assignment_target_names(node: ast.Assign | ast.AnnAssign) -> set[str]: + targets = node.targets if isinstance(node, ast.Assign) else [node.target] + return {target.id for target in targets if isinstance(target, ast.Name)} + + +def _has_typer_command_decorator( + function_node: ast.FunctionDef | ast.AsyncFunctionDef, typer_command_targets: set[str] +) -> bool: for decorator in function_node.decorator_list: parts = _decorator_name_parts(decorator) - if parts == ("command",) or parts[-1:] == ("command",): - return True - if parts[-1:] == ("callback",): + if len(parts) == 2 and parts[0] in typer_command_targets and parts[1] in {"command", "callback"}: return True return False def _kiss_parameter_findings( - function_node: ast.FunctionDef | ast.AsyncFunctionDef, file_path: Path + function_node: ast.FunctionDef | ast.AsyncFunctionDef, file_path: Path, typer_command_targets: set[str] ) -> list[ReviewFinding]: findings: list[ReviewFinding] = [] - if _typer_cli_entrypoint_exempt(function_node, file_path): + if _typer_cli_entrypoint_exempt(function_node, file_path, typer_command_targets): return findings parameter_count = len(function_node.args.posonlyargs) parameter_count += len(function_node.args.args) diff --git a/registry/index.json b/registry/index.json index 030cacb..9f3fb0f 100644 --- a/registry/index.json +++ b/registry/index.json @@ -78,9 +78,9 @@ }, { "id": "nold-ai/specfact-code-review", - "latest_version": "0.47.49", - "download_url": "modules/specfact-code-review-0.47.49.tar.gz", - "checksum_sha256": "fb87c809d36770cd661e18a473fe0f41f3d930b51b2248c04315b37d6319c162", + "latest_version": "0.47.51", + "download_url": "modules/specfact-code-review-0.47.51.tar.gz", + "checksum_sha256": "ee0b2a366293ecf7f3d08331287397322cea35cda5cbd3af7b9df01bd3c00ab1", "core_compatibility": ">=0.44.0,<1.0.0", "tier": "official", "publisher": { diff --git a/registry/modules/specfact-code-review-0.47.49.tar.gz b/registry/modules/specfact-code-review-0.47.49.tar.gz deleted file mode 100644 index 7339cbcac548ba387f4368a1f4373757ad756fbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62417 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 diff --git a/registry/modules/specfact-code-review-0.47.49.tar.gz.sha256 b/registry/modules/specfact-code-review-0.47.49.tar.gz.sha256 deleted file mode 100644 index 2f8fae4..0000000 --- a/registry/modules/specfact-code-review-0.47.49.tar.gz.sha256 +++ /dev/null @@ -1 +0,0 @@ -fb87c809d36770cd661e18a473fe0f41f3d930b51b2248c04315b37d6319c162 diff --git a/registry/modules/specfact-code-review-0.47.51.tar.gz b/registry/modules/specfact-code-review-0.47.51.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..c7c51b386fd775b5971099389276bfb8e1dbdcc1 GIT binary patch literal 62832 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 literal 0 HcmV?d00001 diff --git a/registry/modules/specfact-code-review-0.47.51.tar.gz.sha256 b/registry/modules/specfact-code-review-0.47.51.tar.gz.sha256 new file mode 100644 index 0000000..6ffe893 --- /dev/null +++ b/registry/modules/specfact-code-review-0.47.51.tar.gz.sha256 @@ -0,0 +1 @@ +ee0b2a366293ecf7f3d08331287397322cea35cda5cbd3af7b9df01bd3c00ab1 diff --git a/tests/unit/specfact_code_review/tools/test_radon_runner.py b/tests/unit/specfact_code_review/tools/test_radon_runner.py index 521bccf..3c8affe 100644 --- a/tests/unit/specfact_code_review/tools/test_radon_runner.py +++ b/tests/unit/specfact_code_review/tools/test_radon_runner.py @@ -5,19 +5,34 @@ from pathlib import Path from unittest.mock import Mock +import pytest from pytest import MonkeyPatch from specfact_code_review.tools.radon_runner import run_radon from tests.unit.specfact_code_review.tools.helpers import assert_tool_run, completed_process, create_noisy_file +def _parameter_count_rules(tmp_path: Path, monkeypatch: MonkeyPatch, source: str) -> set[str]: + file_path = tmp_path / "commands.py" + file_path.write_text(source, encoding="utf-8") + monkeypatch.setattr( + subprocess, + "run", + Mock(return_value=completed_process("radon", stdout=json.dumps({str(file_path): []}))), + ) + return {finding.rule for finding in run_radon([file_path])} + + def test_run_radon_returns_empty_when_only_non_python_paths(tmp_path: Path, monkeypatch: MonkeyPatch) -> None: manifest = tmp_path / "module-package.yaml" manifest.write_text("name: example\n", encoding="utf-8") run_mock = Mock() monkeypatch.setattr(subprocess, "run", run_mock) - assert not run_radon([manifest]) + result = run_radon([manifest]) + + assert isinstance(result, list) + assert not result run_mock.assert_not_called() @@ -60,6 +75,7 @@ def test_run_radon_returns_no_findings_for_complexity_twelve_or_below(tmp_path: findings = run_radon([file_path]) + assert isinstance(findings, list) assert not findings @@ -109,44 +125,45 @@ def test_run_radon_uses_dedicated_tool_identifier_for_kiss_findings(tmp_path: Pa assert {finding.tool for finding in kiss_findings} == {"radon-kiss"} -def test_run_radon_requires_typer_decorator_for_context_parameter_exemption( - tmp_path: Path, monkeypatch: MonkeyPatch -) -> None: - file_path = tmp_path / "commands.py" - file_path.write_text( - """ +@pytest.mark.parametrize( + ("source", "expects_parameter_count_warning"), + [ + ( + """ def callback(ctx: typer.Context, a: str, b: str, c: str, d: str, e: str) -> None: return None """, - encoding="utf-8", - ) - monkeypatch.setattr( - subprocess, - "run", - Mock(return_value=completed_process("radon", stdout=json.dumps({str(file_path): []}))), - ) - - findings = run_radon([file_path]) - - assert "kiss.parameter-count.warning" in {finding.rule for finding in findings} + True, + ), + ( + """ +import typer +app = typer.Typer() -def test_run_radon_exempts_typer_command_parameters_without_context(tmp_path: Path, monkeypatch: MonkeyPatch) -> None: - file_path = tmp_path / "commands.py" - file_path.write_text( - """ @app.command("run") def callback(a: str, b: str, c: str, d: str, e: str, f: str) -> None: return None """, - encoding="utf-8", - ) - monkeypatch.setattr( - subprocess, - "run", - Mock(return_value=completed_process("radon", stdout=json.dumps({str(file_path): []}))), + False, + ), + ( + """ +@custom.command("run") +def callback(a: str, b: str, c: str, d: str, e: str, f: str) -> None: + return None +""", + True, + ), + ], +) +def test_run_radon_applies_parameter_count_rule_to_cli_decorators( + tmp_path: Path, monkeypatch: MonkeyPatch, source: str, expects_parameter_count_warning: bool +) -> None: + findings = _parameter_count_rules( + tmp_path, + monkeypatch, + source, ) - findings = run_radon([file_path]) - - assert "kiss.parameter-count.warning" not in {finding.rule for finding in findings} + assert ("kiss.parameter-count.warning" in findings) is expects_parameter_count_warning From 6ca04acb8749768bd729172d4e86ff2b502315af Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 19:38:46 +0000 Subject: [PATCH 7/7] chore(modules): ci sign changed modules --- packages/specfact-code-review/module-package.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/specfact-code-review/module-package.yaml b/packages/specfact-code-review/module-package.yaml index f6f3821..afdf906 100644 --- a/packages/specfact-code-review/module-package.yaml +++ b/packages/specfact-code-review/module-package.yaml @@ -24,3 +24,4 @@ category: codebase bundle_group_command: code integrity: checksum: sha256:f85ae00bc406952621b590367370ef7a9d28acbc26703befa5b1b1a76a6ef516 + signature: fJJEEZliDUcVlOmmjMLAqrYAjHz+r1jVLU8JB09SDeKTVM0yrilkWCqnGpKKMAwat4dw/s0ispT+brZogMqoAQ==