Symptom
On repos where a control's deterministic tier resolves INCONCLUSIVE rather than PASS/FAIL, the follow-on llm_eval pass fires with file_contents = {} in the consultation request. Every downstream LLM call reasons about a list of file paths plus dependency statuses but no actual file content, and returns inconclusive at 0.20-0.30 confidence. In a survey of 29 repos, only tqdm produced any PENDING_LLM at all (4 controls); renaming flask's README.md -> README.rst moved it from 0 to 5 PENDING controls, all with empty consultations.
9 Sonnet calls, 9 non-answers, all because the LLM tier fires precisely when the file it would have read isn't reachable.
Root cause
packages/darnit/src/darnit/sieve/builtin_handlers.py:626-640 -- llm_eval_handler resolves only one dynamic token:
files_to_include = config.get("files_to_include", [])
file_contents: dict[str, str] = {}
for f in files_to_include[:5]:
resolved = f
if f == "$FOUND_FILE":
resolved = context.gathered_evidence.get("found_file", "")
if not resolved:
continue
gathered_evidence["found_file"] is set only by file_exists_handler on PASS (lines 143, 160, 173). The regex/pattern handler evidence carries files_checked, found_files, files_found, matched etc. -- but never found_file.
9 out of 9 llm_eval passes in packages/darnit-baseline/src/darnit_baseline/openssf-baseline.toml use files_to_include = ["$FOUND_FILE"].
The pipeline that reaches llm_eval with empty file_contents is:
pattern -> llm_eval (no file_exists sibling; $FOUND_FILE never set)
This is the shape of DO-03.02, DO-04.01, DO-05.01, VM-02.01, GV-01.01, SA-01.01, SA-02.01 -- the exact controls that fire on the tqdm/flask-with-rst repros.
Why it fires precisely when there's nothing to show
_regex_no_files_result (builtin_handlers.py:485-508) returns INCONCLUSIVE with evidence={"files_checked": files_list} when the candidate list produces zero on-disk matches. INCONCLUSIVE -> ATTACH_EVIDENCE_AND_CONTINUE -> llm_eval fires -> $FOUND_FILE empty -> consultation ships with file_contents: {}.
flask README.md vs README.rst is the same mechanism: with README.md present, DO-03.02's files = ["SECURITY.md", "README.md", "docs/releases.md", "CONTRIBUTING.md", "docs/RELEASE-VERIFICATION.md"] matches something -> pattern PASSes/FAILs conclusively -> orchestrator stops. With README.rst only, no candidate matches -> INCONCLUSIVE -> llm_eval fires -> empty consultation.
Fix options, ordered by scope
-
TOML-only: change every llm_eval block's files_to_include from ["$FOUND_FILE"] to enumerate real candidate paths (superset of the sibling pattern's files). The handler already skips missing files via except OSError, so listing candidates that may not exist is safe. Zero framework code change; downside is TOML duplicates the pattern's file list.
-
Wire regex evidence to llm_eval: enrich regex_handler evidence with an existing_files key (candidates that actually exist on disk regardless of match state). Teach llm_eval to fall back to that when $FOUND_FILE is empty. One evidence key + ~5 lines of resolution logic. Preserves single-source-of-truth for the file list.
-
use_locator = true on llm_eval: give llm_eval the same locator resolution file_exists has. Consistent declarative surface; largest scope of the three.
Repro
- Any repo without a
README.md, SECURITY.md, or the other .md files a DO-* / VM-* / GV-* / SA-* control lists in its pattern.files, but with equivalent .rst/.txt content. tqdm is a real-world example; mv README.md README.rst on any other repo reproduces.
- Run
darnit audit (or the MCP audit_openssf_baseline tool) with the harness or any driver that dispatches PENDING_LLM. Inspect the consultation payload -- file_contents will be {}.
Related
packages/darnit/src/darnit/sieve/builtin_handlers.py: llm_eval_handler, regex_handler, _regex_no_files_result
packages/darnit/src/darnit/sieve/orchestrator.py: apply_check_execution_rule INCONCLUSIVE branch
packages/darnit-baseline/src/darnit_baseline/openssf-baseline.toml: 9 [[controls."...".passes]] blocks with handler = "llm_eval"
Surfaced during a survey of 29 repos (10 general + 19 CNCF).
Symptom
On repos where a control's deterministic tier resolves INCONCLUSIVE rather than PASS/FAIL, the follow-on
llm_evalpass fires withfile_contents = {}in the consultation request. Every downstream LLM call reasons about a list of file paths plus dependency statuses but no actual file content, and returnsinconclusiveat 0.20-0.30 confidence. In a survey of 29 repos, only tqdm produced any PENDING_LLM at all (4 controls); renaming flask'sREADME.md->README.rstmoved it from 0 to 5 PENDING controls, all with empty consultations.9 Sonnet calls, 9 non-answers, all because the LLM tier fires precisely when the file it would have read isn't reachable.
Root cause
packages/darnit/src/darnit/sieve/builtin_handlers.py:626-640--llm_eval_handlerresolves only one dynamic token:gathered_evidence["found_file"]is set only byfile_exists_handleron PASS (lines 143, 160, 173). Theregex/patternhandler evidence carriesfiles_checked,found_files,files_found,matchedetc. -- but neverfound_file.9 out of 9
llm_evalpasses inpackages/darnit-baseline/src/darnit_baseline/openssf-baseline.tomlusefiles_to_include = ["$FOUND_FILE"].The pipeline that reaches
llm_evalwith emptyfile_contentsis:This is the shape of DO-03.02, DO-04.01, DO-05.01, VM-02.01, GV-01.01, SA-01.01, SA-02.01 -- the exact controls that fire on the tqdm/flask-with-rst repros.
Why it fires precisely when there's nothing to show
_regex_no_files_result(builtin_handlers.py:485-508) returns INCONCLUSIVE withevidence={"files_checked": files_list}when the candidate list produces zero on-disk matches. INCONCLUSIVE ->ATTACH_EVIDENCE_AND_CONTINUE->llm_evalfires ->$FOUND_FILEempty -> consultation ships withfile_contents: {}.flask README.md vs README.rst is the same mechanism: with README.md present, DO-03.02's
files = ["SECURITY.md", "README.md", "docs/releases.md", "CONTRIBUTING.md", "docs/RELEASE-VERIFICATION.md"]matches something -> pattern PASSes/FAILs conclusively -> orchestrator stops. With README.rst only, no candidate matches -> INCONCLUSIVE -> llm_eval fires -> empty consultation.Fix options, ordered by scope
TOML-only: change every
llm_evalblock'sfiles_to_includefrom["$FOUND_FILE"]to enumerate real candidate paths (superset of the siblingpattern'sfiles). The handler already skips missing files viaexcept OSError, so listing candidates that may not exist is safe. Zero framework code change; downside is TOML duplicates the pattern's file list.Wire
regexevidence tollm_eval: enrichregex_handlerevidence with anexisting_fileskey (candidates that actually exist on disk regardless of match state). Teachllm_evalto fall back to that when$FOUND_FILEis empty. One evidence key + ~5 lines of resolution logic. Preserves single-source-of-truth for the file list.use_locator = trueonllm_eval: givellm_evalthe same locator resolutionfile_existshas. Consistent declarative surface; largest scope of the three.Repro
README.md,SECURITY.md, or the other .md files a DO-* / VM-* / GV-* / SA-* control lists in itspattern.files, but with equivalent .rst/.txt content. tqdm is a real-world example;mv README.md README.rston any other repo reproduces.darnit audit(or the MCPaudit_openssf_baselinetool) with the harness or any driver that dispatches PENDING_LLM. Inspect the consultation payload --file_contentswill be{}.Related
packages/darnit/src/darnit/sieve/builtin_handlers.py:llm_eval_handler,regex_handler,_regex_no_files_resultpackages/darnit/src/darnit/sieve/orchestrator.py:apply_check_execution_ruleINCONCLUSIVE branchpackages/darnit-baseline/src/darnit_baseline/openssf-baseline.toml: 9[[controls."...".passes]]blocks withhandler = "llm_eval"Surfaced during a survey of 29 repos (10 general + 19 CNCF).