Skip to content

The TELOS-summary generator's safety guard crashes on the shipped sample tree — two independent bugs, and 2 of 4 callers hide the failure #1815

Description

@tzioup

Structured for machine parsing: claims are atomic, each carries the command that verifies it. Every command runs against a fresh clone of this repo — none depend on my machine, my install, or my configuration. Full reproduction at the bottom.

Summary

LIFEOS/TOOLS/GenerateTelosSummary.ts regenerates PRINCIPAL_TELOS.md from source TELOS section files, and has a fail-loud guard meant to stop it from silently writing a summary that drops real content. On a completely fresh, unmodified install — the shipped sample tree, nothing customized yet — this guard trips and the tool exits 1, before any real user content exists to lose. This is the same file you already worked on for #1559 (the Core Models empty-section guard); this is a different bug in the same guard mechanism, found while re-checking that area.

Two independent defects are each individually sufficient to cause this, confirmed by controlled variants rather than just reading the code:

  1. The guard reads its "is there source content" check from a different source (TELOS.md) than the actual parse uses (the legacy per-section file, if present) — so on a tree with both, the two can disagree about the same section.
  2. Separately, and this is the one I hadn't expected going in: the guard never applies the same "ignore (sample) placeholder text" filter that the parser applies elsewhere. Even with only TELOS.md present (no legacy files at all), the guard still trips, because it just checks whether the section has any text, without checking whether that text is real content or template sample text.

Separately, of the four places in the codebase that call this tool, two swallow the resulting failure and print a false success message anyway.

Claims and verification

git clone --depth 1 https://github.com/danielmiessler/LifeOS && cd LifeOS

C1 — live reproduction on the exact shipped sample tree.

mkdir -p /tmp/fakehome/.claude
cp -r LifeOS/install/LIFEOS /tmp/fakehome/.claude/LIFEOS
cp -r LifeOS/install/USER /tmp/fakehome/.claude/USER
cd /tmp/fakehome/.claude/LIFEOS/TOOLS
HOME=/tmp/fakehome bun run GenerateTelosSummary.ts
echo "exit: $?"
❌ TELOS section "Missions" has source content but parsed to zero items — refusing to write a summary that silently drops it.
exit: 1

PRINCIPAL_TELOS.md was left byte-identical to the shipped template before and after — the guard fires before any write, so this is a hard stop, not silent corruption. But it means a brand new install can't regenerate this file at all without manual intervention.

C2 — the two functions reading from different sources.

GenerateTelosSummary.ts:91-99 (the actual parse — legacy file wins if it exists):

function readTelosFile(filename: string): string {
  const path = join(TELOS_DIR, filename);
  if (existsSync(path)) {
    return readFileSync(path, 'utf-8').replace(/^---\n[\s\S]*?\n---\n?/, '');
  }
  const sectionKey = LEGACY_FILE_TO_SECTION[filename];
  ...

GenerateTelosSummary.ts:60-67 (the guard's own source — TELOS.md only, never touches legacy files):

function loadTelosSections(): Record<string, string> {
  if (_telosSectionsCache) return _telosSectionsCache;
  const telosPath = join(TELOS_DIR, 'TELOS.md');
  if (!existsSync(telosPath)) { _telosSectionsCache = {}; return _telosSectionsCache; }
  const content = readFileSync(telosPath, 'utf-8');
  ...

GenerateTelosSummary.ts:469-474 (the guard itself, comparing the two):

for (const [key, label, count] of coreChecks) {
  if (((sections[key] ?? sections[key + 's']) ?? '').trim().length > 0 && count === 0) {
    console.error(`❌ TELOS section "${label}" has source content but parsed to zero items — refusing to write a summary that silently drops it.`);
    process.exit(1);
  }
}

On the shipped tree: readTelosFile('MISSION.md') (the parse) reads the legacy MISSION.md file directly, because it exists on disk. loadTelosSections()['mission'] (the guard) reads TELOS.md's own ## Mission section instead — a different string entirely.

C3 — the second, independent defect: the guard doesn't apply the same placeholder filter the parser does.

Both the legacy file and TELOS.md currently contain only (sample)-marked template text, which the parser's parseItems() correctly filters to zero real items via a shared /\(sample\b/i regex. The guard never applies that same filter to its own raw non-emptiness check — it just asks "is there text here," not "is there text here that isn't a sample placeholder." I confirmed this is independently sufficient with two controlled variants:

# variant A: only TELOS.md present, no legacy files at all
rm -f /tmp/fakehome/.claude/USER/TELOS/MISSION.md
HOME=/tmp/fakehome bun run GenerateTelosSummary.ts   # still exits 1, identical message

# variant B: only legacy files present, no TELOS.md at all
rm -f /tmp/fakehome/.claude/USER/TELOS/TELOS.md
HOME=/tmp/fakehome bun run GenerateTelosSummary.ts   # exits 0 — passes silently, though the same zero-real-items problem exists

Variant A shows the mismatch alone (independent of which source is present) still trips the guard, because it never filters sample text. Variant B shows the flip side: when TELOS.md is absent, loadTelosSections() returns an empty object and the guard's .length > 0 check is vacuously false, so it passes clean even though the same zero-item problem is present — a related blind spot in the opposite direction.

C4 — the complete, exhaustive caller list.

grep -rl "GenerateTelosSummary" --include='*.ts' --include='*.md' -- .

Read all 17 files this returns; four are genuine invocation sites (a fifth occurrence is a byte-identical duplicate of one, from the installer bundling itself twice):

Caller Mechanism Result
skills/Interview/Workflows/Phase0Setup.md:59 bun ~/.claude/LIFEOS/TOOLS/GenerateTelosSummary.ts 2>/dev/null || true, then unconditionally announces "Phase 0 done" hides the failure
skills/Interview/Workflows/ContextCheckin.md:163 identical 2>/dev/null || true pattern, proceeds straight to /reload hides the failure
LIFEOS/TOOLS/DerivedSync.ts:239 (spawned at line ~290) checks the exit code, logs it, propagates a non-zero exit from its own main() surfaces the failure correctly
LifeOS/Tools/SeedPulse.ts:32,52,69-84 execFileSync (throws on non-zero), caught and collected into a failed[] array, prints {ok:false,...} and exits 1 surfaces the failure correctly

Everything else in the 17-file search is a mention (a doc note, a comment, a display label) — not an invocation.

Scope of the claim

  • Tested with Bun 1.3.14 against a synthetic $HOME built by directly copying the shipped LifeOS/install/LIFEOS and LifeOS/install/USER trees unmodified — matching the installer's own documented copy behavior for these directories.
  • I'm not claiming the two hiding callers (Phase0Setup.md, ContextCheckin.md) are careless as a pattern — the other two callers in the same codebase handle this correctly, so it reads as an inconsistency between the two Interview-skill workflow docs and the two code-level callers, not a systemic issue.
  • I make no claim about intent.

Suggested fix

  1. Point the guard's non-emptiness check at the same source readTelosFile actually parses (or centralize both behind one function), so they can't disagree.
  2. Apply the same (sample)-filter regex the parser uses before the guard's emptiness check, so a fully-sample tree is recognized as "nothing real yet" rather than "content that got silently dropped."
  3. In the two workflow docs, surface the non-zero exit (even just printing the tool's own error text) instead of 2>/dev/null || true before announcing success.

I verified 1 and 2 against the code directly and can open a PR.

Reproduction

git clone --depth 1 https://github.com/danielmiessler/LifeOS && cd LifeOS
mkdir -p /tmp/fakehome/.claude
cp -r LifeOS/install/LIFEOS /tmp/fakehome/.claude/LIFEOS
cp -r LifeOS/install/USER /tmp/fakehome/.claude/USER
cd /tmp/fakehome/.claude/LIFEOS/TOOLS
HOME=/tmp/fakehome bun run GenerateTelosSummary.ts   # exits 1 on an unmodified fresh install

# the two independent-defect variants
rm -f /tmp/fakehome/.claude/USER/TELOS/MISSION.md
HOME=/tmp/fakehome bun run GenerateTelosSummary.ts   # still exits 1

# caller list
grep -rl "GenerateTelosSummary" --include='*.ts' --include='*.md' -- .

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