--- description: Fold repo supplement — SAST boundaries, router contract, and validation rules argument-hint: "[TASK=] [MODE=engineering] [PHASE=]" --- # AGENTS.md (Repo Supplement) Operating model (retrieval contract, execution loop, metadata, handoff, ask-first list): `../yams/docs/prompts/PROMPT-eng-codex.md`. C++ design/TDD/ assertion/profiling flow: `../yams/docs/prompts/PROMPT-yams-cpp-workflow.md`. Use `../yams/AGENTS.md` as the reference style for keeping this file lean: generic agent behavior belongs in the shared prompt files; this file holds only what is specific to Fold. ## Project Contract fold is a C++ SAST with two analysis paths: - Source path: Clang LibTooling plus bounded Z3-backed detectors. - Binary path: radare2-backed heuristic extraction for strings, symbols, calls, sections, xrefs, and simple pseudocode patterns. Keep these paths separate unless a task explicitly asks for router work. Do not try to lift binary instructions into the source symbolic IR as a shortcut. ## CLI And Router Work Read `docs/research/cli-router.md` before changing scan-mode behavior. The intended CLI contract is: - `fold scan --mode source ...` runs only the source backend. - `fold scan --mode binary --binary ` runs only the binary backend. - `fold scan --mode hybrid --compile-db --binary ` runs both through the scan router. - `fold scan --mode auto ...` chooses hybrid when both source and binary inputs are present. Compatibility requirements: - Keep existing `--input-type source|binary` behavior until explicitly removed. - Existing `fold scan --input-type binary --binary ` commands must keep working. - Exit codes stay stable: `0` no actionable findings, `1` actionable findings, `2` input/config/report failure, including a scan that left any requested translation unit unanalyzed (see `coverage` in docs/USAGE.md). - Reports must preserve per-finding backend provenance. Router implementation rules: - Put orchestration in `include/fold/cli/scan_router.hpp` and `src/cli/scan_router.cpp` when implementation starts. - Prefer small router-specific structs over widening `AnalysisBackend`. - Hybrid mode should begin as `merge-only`; add hint exchange only after tests prove independent source and binary behavior is unchanged. - Binary hints may focus source work, but must not silently hide source coverage unless the user requested a capped hybrid candidate set. - Source hints may focus binary decompilation, but raw binary string/symbol scans should still run unless explicitly disabled. ## Backend Boundaries - `include/fold/core/analysis_backend.hpp` is intentionally narrow. - `ClangBackend` owns source analysis and delegates to the mature detector pipeline. - `R2Backend` owns radare2 sessions and binary heuristics. - Keep binary findings heuristic unless there is source/Z3 corroboration. - Keep source solver metrics and binary heuristic metrics separate in profiles. ## Validation Run focused tests for the area you changed, then the full suite for CLI/router or backend changes: ```sh ninja -C build/release meson test -C build/release --print-errorlogs git diff --check ``` Useful focused tests: ```sh meson test -C build/release fold:scan_e2e --print-errorlogs meson test -C build/release fold:binary_backend --print-errorlogs meson test -C build/release fold:subprocess_fanout --print-errorlogs meson test -C build/release fold:cross_tu_security --print-errorlogs ``` For binary or hybrid changes, run a curl source/binary smoke if the fixture paths are available in the workspace. ## Worktree Safety This repository often has unrelated local edits from benchmark and experiment runs. Do not revert or rewrite files you did not intentionally modify. Keep changes minimal and check `git diff --check` before handing off. ## Cross-Language Wire Formats When a production path spans Rust and C++ (fold-rust NDJSON → RustBackend parsing, fold-swift NDJSON → SwiftBackend parsing), JSON/NDJSON key names must be centralized in a single source of truth. Do not duplicate string literals across Rust and C++. Canonical key homes: - IR expression trees: `include/fold/ir/expr_json.hpp` (`namespace json_keys`). - Frontend record envelopes (`info`/`error`/`function`/`finding`/`summary`/ `symbolic-summary`/`interface`/`ir`) and their data keys: `include/fold/frontend/ndjson_keys.hpp` (`namespace fold::frontend::ndjson_keys`). Rules: - C++ serialization (`toJson`) and deserialization (`fromJson`, backend parsing) MUST use these constants, not raw string literals. - Rust/other-language producers MUST match the canonical names. Document the expected keys in a comment block at the emitter site (`tools/fold-rust/src/main.rs` near `FindingData`, `tools/fold-swift/ fold_swift.cpp` near `emitFinding`). - When a new expression shape (Call, Member, ArraySubscript, etc.) or NDJSON record shape is added, add its canonical keys to the owning header first, then implement on both sides. - New `finding_kind` values must also be added to `FindingKind` + `findingKindName()` (`src/report/finding.cpp`) and to the backend parse tables; unknown wire kinds map to `FindingKind::UnknownForeign` with a warning, never silently relabeled. - `fromJson` may accept legacy key aliases (read: `j.value("canonical_key", j.value("legacy_key", default))`) for backward compatibility, but MUST prefer the canonical form on write.