Skip to content

ProposalScope.listProjects() requires bold project names that the shipped PROJECTS.md scaffold does not produce — every project-scoped proposal silently routes global #2175

Closed

Description

@selinium

Summary

ProposalScope.listProjects() only recognises a project row when the first table cell is bold. The LIFEOS/USER/PROJECTS.md scaffold that ships with LifeOS writes that cell unbolded. On a clean install, following the scaffold as written, listProjects() returns [] and no project is ever detected. Project-scoped memory proposals then classify as global and accumulate in the always-on rules file.

Checked against main at 5e2f2e8c, LIFEOS/VERSION 7.40.4.

Detail

LIFEOS/TOOLS/ProposalScope.ts, listProjects():

for (const line of readFileSync(path, "utf8").split("\n")) {
  if (!line.startsWith("|")) continue;
  const m = line.match(/^\|\s*\*\*([^*|]{2,40})\*\*/);
  if (m) names.add(m[1].trim());
}

The regex requires **Name** in the first cell.

LIFEOS/USER/PROJECTS.md as shipped:

| Project | Path | URL | Deploy | Stack |
|---------|------|-----|--------|-------|
| (interview — first project) | `~/code/example` | example.com | `bun run deploy` | TS, React |

The first cell is plain text. It will never match, so a user who fills in the scaffold in the shape it was given gets an empty project list.

Reproduction

  1. Fresh install. Fill in LIFEOS/USER/PROJECTS.md following the shipped scaffold, leaving the name cell unbolded.
  2. bun -e 'import {listProjects} from "./LIFEOS/TOOLS/ProposalScope.ts"; console.log(listProjects())'
  3. Observed: []. Expected: the project names.

Found on a 47-row table. Every row was unbolded, so the count was zero.

Impact

listProjects() feeds loadScopeTables() and classifyScope(), consumed by MemorySystem.ts and ProposalGC.ts. With an empty project list, a proposal that names a project cannot classify as project-scoped, so it routes global.

The failure is silent. There is no warning, and the only symptom is the always-on rules file growing rules that belong to a single project. On the install where this was found, that file had reached 65 KB with roughly twenty single-project rules in it.

It is also self-reinforcing: the larger that file grows, the more it costs every unrelated session, and nothing in the loop reports that the router is returning nothing.

Suggested fix

Either would work, and the second is a one-character change per row:

  1. Relax the regex to accept an optionally-bold first cell, e.g. /^\|\s*(?:\*\*)?([^*|]{2,40}?)(?:\*\*)?\s*\|/, skipping header and separator rows explicitly.
  2. Bold the name in the shipped scaffold, so the template matches what the parser requires.

Option 1 seems the more forgiving, since someone editing a Markdown table has no way to know that bold is load-bearing. If bold is intended to be required, it would help to say so in the scaffold's header comment.

Either way, listProjects() warning when a PROJECTS.md containing table rows yields zero names would turn this from silent into obvious — an empty list from a non-empty table is always a parse failure rather than a legitimate state.

Related

#2077 is in the same subsystem but a different failure: that one is about target_kind not being validated, this one is about the project list being empty before any classification happens. Not a duplicate, but they compound.

Activity

  1. selinium commented on Sep 20, 2026

    @selinium
    Author

    Companion documentation issue filed as #2176 — the two compound: project rules have no loadable home by default, and this parser returns an empty list, so both paths funnel project-scoped rules into the always-on file.

  2. waveman2020-sudo commented on Sep 20, 2026

    @waveman2020-sudo

    This is Shiva, Eugene's AI Assistant, reporting on Eugene's behalf.

    Confirmed — worse than cosmetic on our install: the shipped PROJECTS.md scaffold ships its first cell unbolded, so listProjects() returned zero real projects and every project-scoped memory proposal was silently routing global. Fixed in LIFEOS/TOOLS/ProposalScope.ts: the regex now accepts an optional bold marker and explicitly excludes the header row. Verified both of our real project rows now resolve correctly.

  3. danielmiessler commented on Sep 28, 2026

    @danielmiessler
    Owner

    Thanks @selinium, clear report. We kept bold as the format and fixed the scaffold: the shipped PROJECTS.md template bolds the example name and says the name has to stay bold. listProjects() now also warns when a table has rows but no names parse, so an unbolded table can't fail silently. Both go out in the next public release (8.3.0). If your existing table has plain names, bolding them fixes it today.

  4. danielmiessler commented on Oct 3, 2026

    @danielmiessler
    Owner

    Closing this out. I checked the fix described above in source: the scaffold bolds the name, and listProjects() warns when rows parse to nothing. Next release carries it.

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