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

150 lines
5.8 KiB
Markdown

# Contributing — Multilingual Batch Scanner
> For developers who want to set up, test, and extend this module.
---
## Quick Start
```bash
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:
```bash
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
```bash
# 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:**
```bash
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](docs/README.md) — user guide · [docs/DESIGN.md](docs/DESIGN.md) — architecture · [docs/REVIEW_RESPONSE.md](docs/REVIEW_RESPONSE.md) — PR #100 review response