Heal legacy frontmatter automatically; never hard-fail on old enum values#4
Merged
Merged
Conversation
…lues A store written by an older build (e.g. importance: medium from before the binary high/low schema) errored with "invalid importance" on load/edit. Add a general normalization layer with the invariant "map toward attention, not away": any value that is no longer a valid enum member, or a field absent from an older file, coerces to its highest-attention valid value (importance/urgency -> high, status -> active). Wired at three layers so it is self-healing without manual steps: - read: CalculatePriorityScore normalizes its copy, so legacy values sort toward attention immediately instead of silently collapsing to low. - write: Service.Save heals + persists + emits a Warning per coercion. - startup: a version-gated one-time sweep (Service.Migrate, config schema_version vs core.CurrentSchemaVersion) runs from wire, rewriting every stale Dossier once and logging to stderr (never stdout, so mcp serve stays clean). doctor now reports legacy values as healable rather than fatal. Closed the write-side source of "medium" (MCP tool schema, CLI --importance/--urgency mapping, SPEC CLI synopsis). Extending for a future field: add its Normalize plus one block in Frontmatter.Normalize and bump CurrentSchemaVersion. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016hmNrNMx38h6ewgJwJXpEp
Pre-existing formatting issue unrelated to the normalization change, but the CI `gofmt -l .` gate checks the whole tree and was failing the build. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016hmNrNMx38h6ewgJwJXpEp
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.
Problem
Updating Dossier on a machine with existing dossiers errored with
invalid importance: "medium". Root cause is broader than stale data: theimportance/urgencyschema narrowed from a three-level scale to binaryhigh|low(SPEC.md, Eisenhower 2×2), but the write side never locked down — the MCP tool schema still advertisedlow|medium|high, the CLI passed non-h/lvalues through verbatim, andSPEC.mddocumentedh|m|l. So even a fresh install could regenerate the error. Validation runs on every write over the whole frontmatter (fsstore.go:291), so a single bad value locked the entire record against any edit.Fix
A general normalization layer with the invariant "map toward attention, not away": any value that is no longer a valid enum member, or a field absent from an older file, coerces to its highest-attention valid value (
importance/urgency→high,status→active). Implemented once inFrontmatter.Normalize(internal/core/dossier.go) and wired at three layers so it self-heals without manual steps:CalculatePriorityScorenormalizes its copy, so a legacymediumdossier sorts toward attention immediately instead of silently collapsing to low.Service.Saveheals + persists canonical + emits aWarningper coercion (surfaced via CLI/MCP/TUI).Service.Migrate,config.schema_versionvscore.CurrentSchemaVersion) runs fromwire, rewriting every stale Dossier once and logging to stderr (never stdout, somcp servestays clean). The gate makes it a no-op on every subsequent launch.doctornow reports legacy values as healable rather than fatal. The write-side source ofmediumwas also closed: MCP tool schema, CLI--importance/--urgencymapping, and theSPEC.mdCLI synopsis.Extending for a future field: add the field's
Normalize+ one block inFrontmatter.Normalize, and bumpCurrentSchemaVersion.Verification
Frontmatternormalizers (incl. idempotency), priority-score-toward-attention,Saveheals+warns, andMigratestore-wide + idempotent.go vet, andgofmtall clean.importance: mediumfile auto-healed tohighon the next launch (with stderr warning + version bump), and the second run was silent.Note for reviewers
One judgment call: an unknown
statuscoerces toactive(toward visibility). If unknown statuses should instead map toblocked(force triage), that's a one-line change.🤖 Generated with Claude Code
https://claude.ai/code/session_016hmNrNMx38h6ewgJwJXpEp
Generated by Claude Code