fix(identity): getIdentity/getPrincipal never read the names LIFEOS_CONFIG.toml requires - #1781
Open
anikinsasha wants to merge 1 commit into
Open
Conversation
LifeosConfig refuses to load without a non-empty [da].name and [principal].name/timezone, and setup points the principal at those fields. getIdentity()/getPrincipal() read neither: settings.daidentity -> identity-file frontmatter -> DEFAULT_IDENTITY. identity.ts already imports loadLifeosConfig, but only to resolve paths.userDir. Config now wins for the fields it carries. The existing chain is preserved as legacyIdentity()/legacyPrincipal(), so an install with no config resolves exactly as it did before. test/hooks/Identity.test.ts is the falsifier: four of its five cases fail against the unpatched file, and the fifth (no config present) passes both ways by design.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
LifeosConfigrefuses to load without a non-empty[da].name(LIFEOS/TOOLS/LifeosConfig.ts:160), andLIFEOS_CONFIG.tomllabels the field "required — your DA's name (rename to anything)".getIdentity()never reads it.identity.tsalready importsloadLifeosConfig— at:31, to resolvepaths.userDir, and for nothing else.So the loader treats the field as mandatory and the resolver behaves as though it does not exist. Same pair for
[principal].name/timezone(:152,:155) andgetPrincipal().This is #1459 finished at the root. That PR taught Pulse to defer to
LIFEOS_CONFIG.toml [da]; the central identity loader, which 14 files reach throughgetDAName()and 11 throughgetIdentity(), was never given the same treatment.What changes
hooks/lib/identity.tsgetIdentity()/getPrincipal()overlayLIFEOS_CONFIG.tomlonto the existing chain; that chain moves verbatim intolegacyIdentity()/legacyPrincipal()test/hooks/Identity.test.tsThree ways it bites today
1. A rename does nothing. The field says "rename to anything". Rename your DA there and every
getDAName()call site keeps the old answer, because resolution stops at thecore.namefrontmatterDAInterview.tswrote once. There is no path by which editing the required field changes the resolved name.2. A fresh install resolves the placeholder. The shipped
USER/DIGITAL_ASSISTANT/DA_IDENTITY.mdcarries onlyprovenance/last_updated/conventionfrontmatter — nocore:block. Nothing writessettings.daidentity. So before/interviewruns,getIdentity()returnsLifeOS/Personal AI/#3B82F6/ empty voice id / zeroed prosody, andgetPrincipal()returnsUser, no matter whatLIFEOS_CONFIG.tomlsays. An install whose identity file was authored by hand rather than by the interview stays there permanently.3.
[da].coloris dead config.LifeosConfig.ts:179normalises it and, before this change, nothing in the payload read it —grep -rn 'da\.color'returns the normaliser and nothing else.DAInterview.ts:445writescolor: "#3B82F6"as a literal into the frontmatter that wins, so a configured colour has never had an effect.The sharpest symptom is that one instance answers two ways:
getConfiguredDAName()-style config readers report the configured name whilegetDAName()reports the placeholder, and which one a given surface shows depends on nothing more than which helper its author happened to reach for.Precedence, and the fallback
Config wins for the fields it carries: name, full name, display name, colour, main voice id and prosody for
[da]; name, pronunciation, timezone for[principal]. Optional fields fall back to the configured name rather than to the placeholder, so a config with onlynameset still resolves coherently.Everything else is untouched.
loadLifeosConfig()throwing — no config file yet, or a malformed one — returns the legacy result unchanged, which is the pre-existing behaviour ofpaiUserDir()directly above. An install with noLIFEOS_CONFIG.tomlresolves exactly as it does today.Falsifier
test/hooks/Identity.test.ts. Five cases; the four asserting config precedence fail against the unpatched file, and the fifth — no config present — passes both ways by design, which is the no-regression claim.Resolution is exercised in subprocesses because
identity.tsderives its identity-file paths at module load, so an in-process env change would not reproduce a real session.Placed at
test/hooks/per TestingDoctrine's parallel-tree rule rather than co-located, which that doc lists as an anti-pattern. The payload ships no test tree today, so drop the file if tests are not meant to ship publicly — the fix stands without it, and the reproduction is: