Skip to content

Bug: RebuildArchSummary never skips — checks a filename nothing ever writes, and resolves the generator with the wrong case #1586

Description

@benoitdepaire

Bug: RebuildArchSummary never skips — checks a filename nothing ever writes, and resolves the generator with the wrong case

Summary

hooks/handlers/RebuildArchSummary.ts contains two independent path defects in a single function. Together they mean the handler either regenerates the architecture summary every time it runs, or never runs at all, depending on your filesystem — but never does the thing it was written to do, which is regenerate only when a tracked system file actually changed.

The entire mtime-comparison body of the function is unreachable on every platform.

Defect 1 — the existence check targets a filename that is never produced

LifeOS/install/hooks/handlers/RebuildArchSummary.ts:27

const output = join(paiDir, "DOCUMENTATION", "LIFEOS_ARCHITECTURE_SUMMARY.md");

But the generator writes a different name — LifeOS/install/LIFEOS/TOOLS/ArchitectureSummaryGenerator.ts:39:

const SUMMARY_OUTPUT = path.join(LIFEOS_DIR, "DOCUMENTATION", "ARCHITECTURE_SUMMARY.md");

LIFEOS_ARCHITECTURE_SUMMARY.md does not exist anywhere in the repository and no code path writes it. The only file present is LifeOS/install/LIFEOS/DOCUMENTATION/ARCHITECTURE_SUMMARY.md.

So existsSync(output) is unconditionally false, and the handler always takes the early-return branch at lines 33–38:

const outputStat = existsSync(output) ? statSync(output) : null;
if (!outputStat) {
  console.error("[RebuildArchSummary] Architecture summary missing - regenerating");
  await rebuild(generator, paiDir);
  return;                       // <-- always taken
}

Everything after that return — the trackedDirs walk, the mtime comparison, and the "... is current" skip path — is dead code that has never executed.

Effect: every invocation spawns bun ArchitectureSummaryGenerator.ts generate as a subprocess and rewrites ARCHITECTURE_SUMMARY.md, whether or not anything changed. The file is left perpetually dirty in git.

Defect 2 — the generator path uses the wrong case (breaks on case-sensitive filesystems)

LifeOS/install/hooks/handlers/RebuildArchSummary.ts:28

const generator = join(paiDir, "Tools/ArchitectureSummaryGenerator.ts");

The canonical path in the repo is LIFEOS/TOOLS/ArchitectureSummaryGenerator.ts — uppercase TOOLS. Every other reference in the tree uses that casing (LIFEOS/TOOLS/DocCheck.ts:58, LIFEOS/TOOLS/ReferenceCheck.ts:319).

Two lines later:

if (!existsSync(generator)) return;
  • On macOS/APFS (case-insensitive), Tools/ resolves to TOOLS/, the check passes, and Defect 1 fires — constant regeneration.
  • On Linux (case-sensitive), existsSync returns false and the handler returns immediately. The architecture summary is never regenerated, silently.

Defect 2 masks Defect 1 on Linux, which is likely why the constant-regeneration symptom hasn't been widely reported.

This is the same class as the case-duplicate path cleanup in bc0a20a (issues #1556 / #1557), just in a hook handler rather than a template.

Documentation is inconsistent too, in the same direction

The doc strings disagree with each other about the filename, which looks like a rename that only partially landed:

  • LifeOS/install/settings.enhancements.json:761 — "...regenerates LIFEOS_ARCHITECTURE_SUMMARY.md on Stop."
  • LifeOS/install/settings.enhancements.json:791 — "...regenerates ARCHITECTURE_SUMMARY.md when LifeosSystemArchitecture.md changes."
  • ArchitectureSummaryGenerator.ts:10 and :321 say LIFEOS_ARCHITECTURE_SUMMARY.md in comments/help text, while the code at :39 writes ARCHITECTURE_SUMMARY.md.
  • RebuildArchSummary.ts:3 and :8 say DOCUMENTATION/ARCHITECTURE_SUMMARY.md — contradicting line 27 of the same file.

Affected versions

Present in every release where both files exist: v6.0.2, v6.0.3, v6.0.5, v7.0.0, v7.1.1, and current main (origin/HEAD). The handler line has been byte-identical since v6.0.0.

Verified with:

git show v7.1.1:LifeOS/install/hooks/handlers/RebuildArchSummary.ts | sed -n '27,28p'
git show origin/HEAD:LifeOS/install/LIFEOS/TOOLS/ArchitectureSummaryGenerator.ts | sed -n '39p'
git ls-tree -r --name-only origin/HEAD | grep -i ARCHITECTURE_SUMMARY

Reproduction (macOS)

  1. Install LifeOS v7.1.1 and let DocIntegrity.hook.ts fire (it calls handleRebuildArchSummary()).
  2. Observe stderr: [RebuildArchSummary] Architecture summary missing - regenerating — even though LIFEOS/DOCUMENTATION/ARCHITECTURE_SUMMARY.md is present and current.
  3. git status shows ARCHITECTURE_SUMMARY.md modified after every run.
  4. The "[RebuildArchSummary] DOCUMENTATION/ARCHITECTURE_SUMMARY.md is current" message never appears in any log, because that branch is unreachable.

Suggested fix

-  const output = join(paiDir, "DOCUMENTATION", "LIFEOS_ARCHITECTURE_SUMMARY.md");
-  const generator = join(paiDir, "Tools/ArchitectureSummaryGenerator.ts");
+  const output = join(paiDir, "DOCUMENTATION", "ARCHITECTURE_SUMMARY.md");
+  const generator = join(paiDir, "TOOLS/ArchitectureSummaryGenerator.ts");

Ideally both constants would be imported from a shared module rather than duplicated as string literals in two files — that duplication is what allowed them to drift apart. The stale LIFEOS_ARCHITECTURE_SUMMARY.md mentions in ArchitectureSummaryGenerator.ts:10, :321 and settings.enhancements.json:761 are worth correcting in the same pass.

Note on impact

With the shipped SessionEnd registration this costs one unnecessary subprocess and one needless file rewrite per session end — modest, but it also means the handler's actual purpose (skip when nothing changed) has never worked, and on Linux it never regenerates at all.

Worth flagging for anyone who has customised the registration: if DocIntegrity.hook.ts is moved to Stop, this fires on every assistant turn. On a machine with several concurrent sessions that was measurable CPU load — which is how I found it. That amplification is a local misconfiguration, not a defect in the shipped config, but the underlying dead-code path is the shipped behaviour.

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