detail
Root-caused and fixed the TASKGATE.php matching failures reported earlier this session (misrouted 'search the old zips archive' to unrelated SOP-COMMAND-BUILD.md). NOT a scoring-algorithm problem -- a regex PARSING bug in the SOP-INDEX.md entry extractor. The capture pattern used \s{4} to detect indented description lines, but \s matches newlines too. Wherever two blank lines separated entries (2 newlines + 2-space next-header indent = exactly 4 whitespace chars), \s{4} bridged straight across the blank lines and treated the NEXT SOP's header line as fake continuation content of the PREVIOUS entry -- silently merging that next entry's vocabulary into the wrong SOP's haystack and erasing it as its own independently-matchable entry entirely. Confirmed by replicating the exact parsing+scoring logic in Python against the live SOP-INDEX.md: the old regex found only 46 of the file's actual 54 SOP entries -- 8 were being silently swallowed this way, including SOP-OLD-ZIPS-INDEX.md, SOP-OLD-ZIPS-ARCHIVE.md, SOP-OLD-ZIPS-SEARCH.md, SOP-JANUS-PEEK.md, SOP-TOOLS-MAINTENANCE.md, SOP-HEALTH-LEGACY-DATA.md, SOP-GROCERY-TRACKER.md, SOP-PRINT-FORMAT.md. Fix: changed \s{4} to [ ]{4} (literal space class, cannot match newlines) in TASKGATE.php's single preg_match_all call -- one line changed. Diffed old vs new local files to confirm ONLY that one token differs. No PHP CLI available for syntax check (per platform note) -- used K394 bracket/brace/paren-balance substitute instead, both balanced identically before and after. Re-ran the full parse+score simulation with the fix: all 54 entries now found (8 more than before, zero lost), and the original broken query now correctly surfaces SOP-OLD-ZIPS-INDEX.md + SOP-OLD-ZIPS-SEARCH.md as a genuine tie instead of a false match to an unrelated SOP. This does not fix the separate, pre-existing gap where 'run janus'/'close session' still don't match anything -- that's missing SOP-INDEX vocabulary content, not a parsing defect, and is out of scope for this fix.