# 02. Deterministic code reconnaissance module meta: id: pygienium-02 feature: pygienium priority: P1 depends_on: [pygienium-01] tags: [infrastructure, no-model] objective: - Build `src/recon.ts`: a deterministic, no-model pass that walks the target repo and writes a compact markdown report (languages, manifests, file counts, dead-file candidates) so every check has stable ground truth. deliverables: - `src/recon.ts` exporting `runRecon(cwd)`, `runReconAsync(cwd, opts)`, `reconReportPath(cwd)`, `ReconResult` - Writes `pygienium/recon/report.md` under cwd - Detects: languages by extension, build manifests, total files/bytes, git head/branch, and a "candidate files" list (source files not under skip dirs) written to `pygienium/recon/candidates.jsonl` + summary - Soft caps (MAX_FILES, MAX_BYTES) and SIGINT-safe async walk mirroring piolium's recon steps: - Port piolium's `recon.ts` structure: MANIFEST_FILES, LANGUAGE_BY_EXT, SKIP_DIRS, safe git exec, walkAndTally + async variant with yieldToEventLoop - Adapt skip dirs to include `pygienium` (own output dir) - Add a `candidates.jsonl` emitter listing source files (by language) for the check runners to consume; cap entries to keep it bounded - Export `buildReconReport` for unit testing tests: - Unit: `buildReconReport` on a fake ReconResult produces expected markdown sections (Arrange a result, Act build, Assert headers present) - Integration: run recon against this repo; assert report.md + candidates.jsonl exist and counts > 0 acceptance_criteria: - `runRecon(cwd)` returns a ReconResult and writes report.md + candidates.jsonl - A repo without `.git` does not throw (graceful degradation) - Very large trees are capped without wedging validation: - Inspect `pygienium/recon/report.md` and `pygienium/recon/candidates.jsonl` after a run notes: - Recon is Q0-equivalent: deterministic, runs in-process, no model calls - This is the foundation every check consumes for targeting