Files

76 lines
3.5 KiB
Java

import java.nio.file.*;
import java.util.*;
import java.util.regex.*;
import java.util.stream.*;
/**
* Cross-check the quoted DebugLog lines in docs/android_app/real_device_checklist.md
* against the Kotlin sources, so a verifier can confirm the checklist describes
* logs the code can actually produce.
*
* WHY NOT A PLAIN SEARCH: the sources build messages by interpolation
* ("$name write=$n/${packet.size}") while the checklist shows instantiated
* examples ("GetParameter1 write=4/4"). A literal search therefore produces
* false negatives. This tool instead (1) tries the literal with <placeholders>
* removed, then (2) falls back to requiring the remaining identifier-ish words
* to appear somewhere in the sources.
*
* A "needs review" line means the whole message is instance data (the template
* lives in one string literal and the command name is a call-site argument) —
* those must be traced by hand to the call site. Both categories were manually
* resolved for the 2026-09-11 run (see verification_guide.md §3 Phase A).
*
* Usage:
* java CheckStrings.java docs/android_app/real_device_checklist.md android/app/src/main
*/
public class CheckStrings {
public static void main(String[] a) throws Exception {
String md = Files.readString(Paths.get(a[0]), java.nio.charset.StandardCharsets.UTF_8);
StringBuilder src = new StringBuilder();
try (Stream<Path> s = Files.walk(Paths.get(a[1]))) {
List<Path> kt = s.filter(x -> x.toString().endsWith(".kt")).collect(Collectors.toList());
for (Path p : kt) src.append(Files.readString(p, java.nio.charset.StandardCharsets.UTF_8)).append('\n');
}
String all = src.toString();
// only lines that show a DebugLog tag: [usb] [vm] [session] [cmd] [stream] [pip] [remote] [crash]
Matcher m = Pattern.compile("`(\\[(?:usb|vm|session|cmd|stream|pip|remote|crash)\\][^`]*)`").matcher(md);
int exact = 0, skeleton = 0, miss = 0;
Set<String> seen = new LinkedHashSet<>();
List<String> misses = new ArrayList<>();
while (m.find()) {
String line = m.group(1);
if (!seen.add(line)) continue;
// the tag is a separate DebugLog argument in the source
String msg = line.replaceFirst("^\\[[a-z]+\\]\\s*", "");
String literal = msg.replaceAll("<[^>]*>", "").trim();
if (literal.length() >= 6 && all.contains(literal)) { exact++; continue; }
String skel = msg
.replaceAll("<[^>]*>", " ")
.replaceAll("0x[0-9A-Fa-f]+", " ")
.replaceAll("\\b\\d+(\\.\\d+)?\\b", " ")
.replaceAll("[A-Za-z]*\\d[A-Za-z0-9]*", " ")
.replaceAll("[^\\x20-\\x7E\\u4e00-\\u9fff]+", " ");
List<String> keep = new ArrayList<>();
for (String w : skel.trim().split("\\s+")) {
if (w.length() >= 3 && w.matches("[A-Za-z_:.\\-\\[\\]()/]+")) keep.add(w);
}
boolean found = !keep.isEmpty();
for (String w : keep) if (!all.contains(w)) found = false;
if (found) skeleton++;
else { miss++; misses.add(line + " [probe: " + String.join(" ", keep) + "]"); }
}
System.out.println("exact literal match : " + exact);
System.out.println("skeleton match : " + skeleton);
System.out.println("needs human review : " + miss);
if (!misses.isEmpty()) {
System.out.println();
for (String s : misses) System.out.println(" ? " + s);
}
}
}