|
| 1 | +# Contributing — Multilingual Batch Scanner |
| 2 | + |
| 3 | +> For developers who want to set up, test, and extend this module. |
| 4 | +
|
| 5 | +--- |
| 6 | + |
| 7 | +## Quick Start |
| 8 | + |
| 9 | +```bash |
| 10 | +python3 -m venv .venv |
| 11 | +source .venv/bin/activate |
| 12 | +pip install -e . |
| 13 | +cp contrib/batch_scan/.env.example .env # edit with your API keys |
| 14 | +``` |
| 15 | + |
| 16 | +Verify everything works: |
| 17 | +```bash |
| 18 | +python -m contrib.batch_scan.batch_scan ./tests/fixtures/ -f terminal --workers 8 |
| 19 | +``` |
| 20 | + |
| 21 | +--- |
| 22 | + |
| 23 | +## Project Map |
| 24 | + |
| 25 | +``` |
| 26 | +contrib/batch_scan/ |
| 27 | +├── batch_scan.py # CLI entry + ThreadPoolExecutor (start here) |
| 28 | +├── runner.py # graph.invoke() wrapper + 7 patches + pool wiring (core) |
| 29 | +├── gap_fill.py # GapFillAnalyzer — LLM pass for 8 uncovered rules |
| 30 | +├── api_pool.py # ApiKeyPool — multi-key scheduler + 429 backoff |
| 31 | +├── detection.py # Unicode script-ratio language detection |
| 32 | +├── annotation.py # Finding language-compatibility labels |
| 33 | +├── discovery.py # Recursive SKILL.md finder |
| 34 | +├── reports.py # Terminal / JSON / Markdown formatters |
| 35 | +├── CONTRIBUTING.md # this file |
| 36 | +│ |
| 37 | +├── docs/ |
| 38 | +│ ├── README.md # user guide — all commands, test commands, reviewer index |
| 39 | +│ ├── DESIGN.md # architecture — concurrency, patches, dual-patch mechanism |
| 40 | +│ ├── REVIEW_RESPONSE.md # PR #100 review response |
| 41 | +│ └── archive/ # deep dives, history, future work, pitfalls |
| 42 | +│ |
| 43 | +└── tests/ |
| 44 | + ├── test_pool_wiring.py # smoke — 3-path pool verification |
| 45 | + ├── test_monkeypatch_invasiveness.py # thread isolation, scoping (14 tests) |
| 46 | + ├── test_monkeypatch_fragility.py # guard verification, deep deps (26 tests) |
| 47 | + ├── docs/ |
| 48 | + │ ├── TEST_DESIGN.md # WHY each suite was designed |
| 49 | + │ ├── TEST_GUIDE.md # WHAT each file covers + run commands |
| 50 | + │ └── BUGS_FOUND.md # 16 bugs found & fixed |
| 51 | + └── tests-pro/ |
| 52 | + ├── test_api_pool.py # 45 tests — acquire/release/backoff |
| 53 | + ├── test_gap_fill.py # 41 tests — JSON parsing, prompt building |
| 54 | + ├── test_runner_patches.py # 24 tests — context manager, patches |
| 55 | + ├── test_annotation.py # 10 tests — language compatibility |
| 56 | + ├── random_numbered.py # main entry point (seed=42) |
| 57 | + └── mutation_max.py # 30-bug injection framework |
| 58 | +``` |
| 59 | + |
| 60 | +--- |
| 61 | + |
| 62 | +## Running Tests |
| 63 | + |
| 64 | +```bash |
| 65 | +# All 164 tests |
| 66 | +python contrib/batch_scan/tests/tests-pro/random_numbered.py # 120 unit (seed=42) |
| 67 | +python contrib/batch_scan/tests/test_pool_wiring.py # 4 smoke checks |
| 68 | +python contrib/batch_scan/tests/test_monkeypatch_invasiveness.py # 14 thematic |
| 69 | +python contrib/batch_scan/tests/test_monkeypatch_fragility.py # 26 thematic |
| 70 | + |
| 71 | +# Review-themed only |
| 72 | +python -m unittest \ |
| 73 | + contrib.batch_scan.tests.test_monkeypatch_invasiveness \ |
| 74 | + contrib.batch_scan.tests.test_monkeypatch_fragility -v |
| 75 | +python contrib/batch_scan/tests/test_pool_wiring.py |
| 76 | + |
| 77 | +# Mutation test |
| 78 | +python contrib/batch_scan/tests/tests-pro/mutation_max.py |
| 79 | + |
| 80 | +# End-to-end (fixture suite) |
| 81 | +python -m contrib.batch_scan.batch_scan ./tests/fixtures/ -f terminal --workers 8 |
| 82 | +python -m contrib.batch_scan.batch_scan ./tests/fixtures/ -f terminal --workers 8 --no-llm |
| 83 | +``` |
| 84 | + |
| 85 | +**Three commands catch most regressions:** |
| 86 | +```bash |
| 87 | +python contrib/batch_scan/tests/tests-pro/random_numbered.py |
| 88 | +python contrib/batch_scan/tests/test_pool_wiring.py |
| 89 | +python -m contrib.batch_scan.batch_scan ./tests/fixtures/ -f terminal --workers 8 |
| 90 | +``` |
| 91 | + |
| 92 | +--- |
| 93 | + |
| 94 | +## Code Conventions |
| 95 | + |
| 96 | +Match SkillSpector upstream exactly: |
| 97 | + |
| 98 | +- **SPDX header** on every `.py` file |
| 99 | +- `from __future__ import annotations` as first import |
| 100 | +- Imports: stdlib → third-party → `skillspector.*` → relative (`.`) |
| 101 | +- `| None` syntax (not `Optional[X]`) |
| 102 | +- `frozenset` / `Final` for module-level constants (`UPPER_SNAKE_CASE`) |
| 103 | +- Private helpers: `_lower_snake_case` |
| 104 | +- `logger = get_logger(__name__)` in every module |
| 105 | +- Comments explain **why**, not what |
| 106 | +- Docstrings on all public functions and classes |
| 107 | + |
| 108 | +--- |
| 109 | + |
| 110 | +## Commit Style |
| 111 | + |
| 112 | +``` |
| 113 | +fix: wire ApiKeyPool into llm_analyzer_base graph path |
| 114 | +feat: add multilingual batch scanner with parallel execution |
| 115 | +docs: document dual-patch pool wiring fix |
| 116 | +``` |
| 117 | + |
| 118 | +- Present-tense, imperative mood |
| 119 | +- `Signed-off-by` trailer required (NVIDIA DCO) |
| 120 | +- `Co-authored-by` trailer for joint work |
| 121 | + |
| 122 | +--- |
| 123 | + |
| 124 | +## Key Design Points |
| 125 | + |
| 126 | +Before modifying code, understand these three: |
| 127 | + |
| 128 | +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`. |
| 129 | + |
| 130 | +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). |
| 131 | + |
| 132 | +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. |
| 133 | + |
| 134 | +Full architecture: `docs/DESIGN.md`. |
| 135 | +All pitfalls: `docs/archive/PITFALLS.md`. |
| 136 | + |
| 137 | +--- |
| 138 | + |
| 139 | +## Where to Contribute |
| 140 | + |
| 141 | +See `docs/archive/FUTURE_WORK.md` for 12 future directions with effort estimates. High-impact items: |
| 142 | +- Checkpoint/resume (prevents data loss on large scans) |
| 143 | +- Language detection expansion (9+ languages) |
| 144 | +- SARIF output format |
| 145 | +- Non-English ground-truth fixtures |
| 146 | + |
| 147 | +--- |
| 148 | + |
| 149 | +**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 |
0 commit comments