Files
wehub-resource-sync 2114ccd278
CI / Lint & Test (Python 3.13) (push) Failing after 2s
CI / Lint & Test (Python 3.14) (push) Failing after 1s
CI / Lint & Test (Python 3.12) (push) Failing after 2s
CI / DCO Check (push) Has been skipped
Scorecard supply-chain security / Scorecard analysis (push) Failing after 2s
chore: import upstream snapshot with attribution
2026-07-13 12:23:39 +08:00

5.8 KiB

Contributing — Multilingual Batch Scanner

For developers who want to set up, test, and extend this module.


Quick Start

python3 -m venv .venv
source .venv/bin/activate
pip install -e .
cp contrib/batch_scan/.env.example .env   # edit with your API keys

Verify everything works:

python -m contrib.batch_scan.batch_scan ./tests/fixtures/ -f terminal --workers 8

Project Map

contrib/batch_scan/
├── batch_scan.py          # CLI entry + ThreadPoolExecutor (start here)
├── runner.py              # graph.invoke() wrapper + 7 patches + pool wiring (core)
├── gap_fill.py            # GapFillAnalyzer — LLM pass for 8 uncovered rules
├── api_pool.py            # ApiKeyPool — multi-key scheduler + 429 backoff
├── detection.py           # Unicode script-ratio language detection
├── annotation.py          # Finding language-compatibility labels
├── discovery.py           # Recursive SKILL.md finder
├── reports.py             # Terminal / JSON / Markdown formatters
├── CONTRIBUTING.md        # this file
│
├── docs/
│   ├── README.md          # user guide — all commands, test commands, reviewer index
│   ├── DESIGN.md          # architecture — concurrency, patches, dual-patch mechanism
│   ├── REVIEW_RESPONSE.md # PR #100 review response
│   └── archive/           # deep dives, history, future work, pitfalls
│
└── tests/
    ├── test_pool_wiring.py            # smoke — 3-path pool verification
    ├── test_monkeypatch_invasiveness.py # thread isolation, scoping (14 tests)
    ├── test_monkeypatch_fragility.py    # guard verification, deep deps (26 tests)
    ├── docs/
    │   ├── TEST_DESIGN.md             # WHY each suite was designed
    │   ├── TEST_GUIDE.md              # WHAT each file covers + run commands
    │   └── BUGS_FOUND.md              # 16 bugs found & fixed
    └── tests-pro/
        ├── test_api_pool.py           # 45 tests — acquire/release/backoff
        ├── test_gap_fill.py           # 41 tests — JSON parsing, prompt building
        ├── test_runner_patches.py     # 24 tests — context manager, patches
        ├── test_annotation.py         # 10 tests — language compatibility
        ├── random_numbered.py         # main entry point (seed=42)
        └── mutation_max.py            # 30-bug injection framework

Running Tests

# All 164 tests
python contrib/batch_scan/tests/tests-pro/random_numbered.py       # 120 unit (seed=42)
python contrib/batch_scan/tests/test_pool_wiring.py                 # 4 smoke checks
python contrib/batch_scan/tests/test_monkeypatch_invasiveness.py    # 14 thematic
python contrib/batch_scan/tests/test_monkeypatch_fragility.py       # 26 thematic

# Review-themed only
python -m unittest \
  contrib.batch_scan.tests.test_monkeypatch_invasiveness \
  contrib.batch_scan.tests.test_monkeypatch_fragility -v
python contrib/batch_scan/tests/test_pool_wiring.py

# Mutation test
python contrib/batch_scan/tests/tests-pro/mutation_max.py

# End-to-end (fixture suite)
python -m contrib.batch_scan.batch_scan ./tests/fixtures/ -f terminal --workers 8
python -m contrib.batch_scan.batch_scan ./tests/fixtures/ -f terminal --workers 8 --no-llm

Three commands catch most regressions:

python contrib/batch_scan/tests/tests-pro/random_numbered.py
python contrib/batch_scan/tests/test_pool_wiring.py
python -m contrib.batch_scan.batch_scan ./tests/fixtures/ -f terminal --workers 8

Code Conventions

Match SkillSpector upstream exactly:

  • SPDX header on every .py file
  • from __future__ import annotations as first import
  • Imports: stdlib → third-party → skillspector.* → relative (.)
  • | None syntax (not Optional[X])
  • frozenset / Final for module-level constants (UPPER_SNAKE_CASE)
  • Private helpers: _lower_snake_case
  • logger = get_logger(__name__) in every module
  • Comments explain why, not what
  • Docstrings on all public functions and classes

Commit Style

fix: wire ApiKeyPool into llm_analyzer_base graph path
feat: add multilingual batch scanner with parallel execution
docs: document dual-patch pool wiring fix
  • Present-tense, imperative mood
  • Signed-off-by trailer required (NVIDIA DCO)
  • Co-authored-by trailer for joint work

Key Design Points

Before modifying code, understand these three:

  1. Dual-patch pool wiring. set_api_pool() patches both llm_utils.get_chat_model AND llm_analyzer_base.get_chat_model. The latter is necessary because llm_analyzer_base imports via from ... import, creating a local reference that single-module patching misses. See docs/archive/PITFALLS.md.

  2. Instance-attribute injection (not class-attribute). Patch 1 writes self.response_schema = None to instance __dict__, not class __dict__. Python MRO finds instance attributes first. This is what makes patches thread-safe. Mutating the class attribute causes cross-thread races (this killed V1).

  3. Guard before apply. _verify_patch_targets() checks all 7 patch assumptions before _apply_patches() runs. If upstream changes a signature or removes a dependency, the guard raises immediately — patches fail closed, never silently.

Full architecture: docs/DESIGN.md. All pitfalls: docs/archive/PITFALLS.md.


Where to Contribute

See docs/archive/FUTURE_WORK.md for 12 future directions with effort estimates. High-impact items:

  • Checkpoint/resume (prevents data loss on large scans)
  • Language detection expansion (9+ languages)
  • SARIF output format
  • Non-English ground-truth fixtures

Next: docs/README.md — user guide · docs/DESIGN.md — architecture · docs/REVIEW_RESPONSE.md — PR #100 review response