Skip to content

Import path policy issues#237

Merged
djm81 merged 3 commits intocursor/codebase-import-runtime-hardening-98dffrom
cursor/import-path-policy-issues-b408
Apr 20, 2026
Merged

Import path policy issues#237
djm81 merged 3 commits intocursor/codebase-import-runtime-hardening-98dffrom
cursor/import-path-policy-issues-b408

Conversation

@djm81
Copy link
Copy Markdown
Contributor

@djm81 djm81 commented Apr 20, 2026

Summary

This PR addresses multiple critical issues across specfact-cli-modules to improve module discovery performance, .specfactignore pattern handling, runtime patching robustness, and YAML template generation. Key changes include:

  • Performance: Optimized ignored directory counting to use capped, non-recursive scans, preventing costly full filesystem traversals.
  • Correctness: Corrected glob pattern normalization for dot-prefixed names and ensured ignore rules remain active for descendants of explicit entry points.
  • Robustness: Enabled **kwargs forwarding in runtime patches, serialized Path.rglob patching with a threading.RLock to prevent race conditions, and moved patch application to command-specific entry points.
  • Reliability: Improved template generation to produce valid YAML with proper escaping and enhanced template root resolution to raise clear errors when no match is found.
  • Maintainability: Merged repo-local .specfactignore with user-provided patterns, added comprehensive unit tests, and addressed various code quality, typing, and import cycle issues.

Refs:

  • specfact-cli issue: #
  • related module migration item/change: #

Scope

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

Bundle Impact

List impacted bundles and version updates:

  • nold-ai/specfact-project: old -> new

Validation Evidence

Paste command output snippets or link workflow runs.

Required local gates

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

Signature + version integrity (required)

  • hatch run verify-modules-signature --payload-from-filesystem --enforce-version-bump passes (matches PRs targeting dev)
  • If this PR targets main, also confirmed: hatch run verify-modules-signature --require-signature --payload-from-filesystem --enforce-version-bump (and/or approval triggered sign-modules-on-approval for same-repo PRs)
  • Changed bundle versions were bumped when module payloads changed
  • Manifests signed when required by your target branch (CI may sign on approval for dev/main same-repo PRs)

CI and Branch Protection

  • PR orchestrator jobs expected:
    • verify-module-signatures
    • sign-modules-on-approval (on approval, same-repo PRs to dev/main only)
    • quality (3.11)
    • quality (3.12)
    • quality (3.13)
  • Branch protection required checks are aligned with the above

Docs / Pages

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

Checklist

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

cursoragent and others added 3 commits April 20, 2026 22:10
…alization

Replace recursive rglob counting for ignored directories with a single
os.scandir of the immediate directory so pruning stays cheap.

Strip only leading ./ and / path prefixes from specfactignore patterns
instead of lstrip character classes, preserving dot-prefixed names.

Co-authored-by: Dom <djm81@users.noreply.github.com>
_install_patch now accepts **kwargs and merges them via dataclasses.replace
so positional+keyword calls (e.g. incremental_callback) work after patching.

Explicit-root bypass in should_ignore_path only skips the entry root path,
not descendants, so scoped discovery still prunes node_modules and defaults.

Tests cover entry-point pruning and patch keyword forwarding.

Co-authored-by: Dom <djm81@users.noreply.github.com>
- OpenSpec bundle-packaged-resources: heading blank lines for MD041/MD022
- protocol.yaml.j2: YAML-safe string emission via tojson
- Remove eager apply_import_runtime_patches from package __init__; call from
  sync_repository and from_code with commands_module to avoid import cycles
- template_paths: RuntimeError when no candidate matches required_glob
- import_runtime_patches: RLock around Path.rglob swap; importlib for commands
- import_path_policy: merge repo .specfactignore with caller patterns; capped
  ignored-dir counts; file entry_point handling; discover_code_files kwargs typing
- Tests: entry-point under .venv, YAML assertions for protocol/workflow, patch fixture

Co-authored-by: Dom <djm81@users.noreply.github.com>
@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 20, 2026

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 20, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (1)
  • ^dev$

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4518d241-9cb2-436b-b4f3-677398843ca6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/import-path-policy-issues-b408

Comment @coderabbitai help to get the list of available commands and usage tips.

@djm81 djm81 self-assigned this Apr 20, 2026
@djm81 djm81 added the enhancement New feature or request label Apr 20, 2026
@djm81 djm81 moved this from Todo to In Progress in SpecFact CLI Apr 20, 2026
@djm81 djm81 linked an issue Apr 20, 2026 that may be closed by this pull request
@djm81 djm81 merged commit 001a0be into cursor/codebase-import-runtime-hardening-98df Apr 20, 2026
4 checks passed
@github-project-automation github-project-automation Bot moved this from In Progress to Done in SpecFact CLI Apr 20, 2026
Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 57cbbc5d1d

ℹ️ About Codex in GitHub

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

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

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

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

Comment on lines +258 to +259
if count >= _MAX_IGNORED_ENTRY_COUNT_SAMPLE:
break
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Lower heavy-ignored threshold below sampling cap

_count_ignored_entries now stops counting at 100 top-level entries, but ImportDiscoveryOptions.heavy_ignored_entry_threshold still defaults to 500 in this module, so a single large ignored tree (for example one very large node_modules directory) can no longer trigger the heavy-artifact warning path. This silently removes the warning/ETA signal for the most common large-repo case and makes import progress messaging less accurate unless users manually override thresholds.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Lock doesn't protect original_rglob capture causing race
    • Capture of Path.rglob and definition of patched now happen inside the RLock so each context saves/restores the true unpatched descriptor under mutual exclusion.
  • ✅ Fixed: Sampling cap makes heavy-artifact warning unreachable with defaults
    • Default heavy_ignored_entry_threshold was lowered to 100 to match _MAX_IGNORED_ENTRY_COUNT_SAMPLE so one ignored tree can trigger the warning with defaults.

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 57cbbc5. Configure here.

try:
yield
finally:
Path.rglob = original_rglob # type: ignore[assignment]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Lock doesn't protect original_rglob capture causing race

Medium Severity

original_rglob = Path.rglob is captured at line 67, outside the _rglob_patch_lock acquired at line 89. If thread A holds the lock (and has patched Path.rglob), thread B captures the patched version as its original_rglob before blocking on the lock. When thread B later restores Path.rglob in its finally, it permanently installs thread A's stale patched closure instead of the real Path.rglob. This corrupts Path.rglob for the rest of the process lifetime, directly undermining the stated goal of the RLock.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 57cbbc5. Configure here.

break
except OSError:
return 1
return max(count, 1)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sampling cap makes heavy-artifact warning unreachable with defaults

Medium Severity

_count_ignored_entries caps its return value at _MAX_IGNORED_ENTRY_COUNT_SAMPLE (100), but the default _DEFAULT_HEAVY_IGNORED_ENTRY_THRESHOLD is 500. A single ignored directory like node_modules can now only contribute a count of at most 100, which can never reach 500. The "heavy artifact tree" warning is effectively dead under default settings. The test only passes because it overrides the threshold to 2.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 57cbbc5. Configure here.

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

Labels

enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Change] Codebase import runtime hardening

2 participants