Caught by the new downgrade-and-revert CI lane (PR #692) on its first fully-functional run — run 29196274312, diagnostics artifact attached to the run.
Sequence (real, from the lane): previously-published flair init + seed (its Harper boots fine) → swap in current build → boot (composes HARPER_CONFIG with models.embedding.default {backend, modelName, modelsDir}, which merges AND PERSISTS into the instance-root config) → kill mid-migration → reinstall the previously-published release → its Harper fails boot: Harper config file validation error: 'models.embedding.default.backend' is required (hdb.log, 4s after "Harper successfully started" — env-manager init). The DATA survived byte-identically (the lane's later assertions never got to run, but the ops-read verification in earlier runs and the migration invariants held) — it's the config file that bricks the old stack.
The gap this exposes: our migration-safety invariant I ("source never modified in place, additive-first, old binary must boot") covered data. The instance config file is also mutable state the new build writes in place — and it carried a shape the previous release's Harper cannot validate. Config is state; it needs the same downgrade discipline.
Fix directions to evaluate (in order of preference):
- Reassert-only, never persist: the composer already re-sends
HARPER_CONFIG on every boot ("persists and is reasserted each boot") — if it's reasserted anyway, the persisted copy may be unnecessary; keeping the models block out of the instance file makes the config version-agnostic on downgrade. Needs verification against the Fabric deploy path, which has its own config handling.
- Write the block in a shape every supported Harper version validates (compat union).
- Treat config changes as migrations (expansion-N/contraction-N+1 applied to config keys).
Exact persisted-config divergence still needs local reproduction (the old release's Harper requires backend — the current composer writes it, so the persisted/merged shape must lose or reshape it; repro will pin whether the merge, the validator schema, or a path-resolution difference is at fault).
Blocks #692 going green (the lane is correctly red until this is fixed).
🤖 Generated with Claude Code
Caught by the new downgrade-and-revert CI lane (PR #692) on its first fully-functional run — run 29196274312, diagnostics artifact attached to the run.
Sequence (real, from the lane): previously-published flair init + seed (its Harper boots fine) → swap in current build → boot (composes
HARPER_CONFIGwithmodels.embedding.default {backend, modelName, modelsDir}, which merges AND PERSISTS into the instance-root config) → kill mid-migration → reinstall the previously-published release → its Harper fails boot:Harper config file validation error: 'models.embedding.default.backend' is required(hdb.log, 4s after "Harper successfully started" — env-manager init). The DATA survived byte-identically (the lane's later assertions never got to run, but the ops-read verification in earlier runs and the migration invariants held) — it's the config file that bricks the old stack.The gap this exposes: our migration-safety invariant I ("source never modified in place, additive-first, old binary must boot") covered data. The instance config file is also mutable state the new build writes in place — and it carried a shape the previous release's Harper cannot validate. Config is state; it needs the same downgrade discipline.
Fix directions to evaluate (in order of preference):
HARPER_CONFIGon every boot ("persists and is reasserted each boot") — if it's reasserted anyway, the persisted copy may be unnecessary; keeping the models block out of the instance file makes the config version-agnostic on downgrade. Needs verification against the Fabric deploy path, which has its own config handling.Exact persisted-config divergence still needs local reproduction (the old release's Harper requires
backend— the current composer writes it, so the persisted/merged shape must lose or reshape it; repro will pin whether the merge, the validator schema, or a path-resolution difference is at fault).Blocks #692 going green (the lane is correctly red until this is fixed).
🤖 Generated with Claude Code