Skip to content

checkSurvivingPlaceholders returns passed:true on a zero-file scan, so a mis-rooted Setup 9(d) gate cannot fail #2058

Description

@cammcd

Summary

checkSurvivingPlaceholders() in skills/LifeOS/Tools/InstallEngine.ts returns
passed: true when it scans zero files. A mis-rooted or nonexistent rootDir therefore
reports success, which is precisely the failure mode Setup.md step 9(d) exists to catch.

The code

export function checkSurvivingPlaceholders(rootDir: string): {
  passed: boolean; files: Array<...>; total: number;
} {
  // ...walk, which begins: if (!existsSync(dir)) return;
  return { passed: total === 0, files, total };
}

passed is derived from total === 0 alone. Nothing records how many files were examined,
so "clean tree" and "never looked at anything" are indistinguishable to every caller.

Why it matters

Setup.md step 9(d) leans on this as a gate:

then checkSurvivingPlaceholders(<configRoot>) and require passed: true [...] a skipped
or mis-rooted pass is the difference between a system that knows the user's name and one
that addresses them as {{PRINCIPAL_NAME}}

The document explicitly anticipates a mis-rooted pass, but the function's return shape cannot
express one. A bad root produces a green result and the installer proceeds.

Reproduction

const r = checkSurvivingPlaceholders("/path/that/does/not/exist");
// => { passed: true, files: [], total: 0 }

Encountered for real: a mis-rooted call reported passed: true while Doctor.ts
simultaneously reported 68 unrendered placeholders across 26 sites in the same tree.

Suggested fix

Count scanned files and require a non-empty scan.

let scanned = 0;
const processFile = (filePath: string): void => {
  if (!TEMPLATE_EXTENSIONS.has(fileExtension(filePath))) return;
  scanned++;
  // ...
};
// ...
return { passed: total === 0 && scanned > 0, files, total, scanned };

Returning scanned also gives callers something to log, which makes a mis-rooted pass
obvious in transcripts rather than invisible.

Related

The #1874 / #1852 / #1993 cluster covers substituteTree corrupting the engine's own
IDENTITY_PLACEHOLDERS table. This is a distinct defect in the verification half: even
with a correct table, the gate cannot fail when it never ran.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions