# os-vault invariants

Behavioral invariants of the plugin. Changing any of these requires explicit human approval.
Enforced by `tests/harness.sh` (golden fixtures) unless noted otherwise.

1. **Episodic and semantic memory stay separate systems.** Vault notes hold evergreen,
   cross-project knowledge (ADR-012); session/event history goes to memsearch (ADR-015).
   `/os-vault:query` never answers "what happened when" questions — those route to memsearch.

2. **Six flat namespaced facets, plus `scope`.** Note frontmatter tags are
   `type/`/`client/`/`project/`/`domain/`/`tool/`/`convention/` (ADR-011); `scope`
   (`global`/`project`/`client`) is a frontmatter field, not a tag. `type/` is required on
   every note. Source of truth for the schema is `vault-conventions.md` at the vault root —
   never duplicated or paraphrased into plugin code or skills.

3. **Hooks are fail-open, never block a session.** Every hook
   (`session_start.py`, `session_context.py`, `post_tool_use_write.py`, `session_end.py`,
   `memsearch_sync.py`, `vault_sync.py`) degrades silently on error; none may disrupt session
   startup or shutdown.

4. **SessionStart returns sub-second.** Heavy work (graph rebuild) is detached to the
   background; `session_start.py` only does the staleness check and kicks off the detached
   rebuild. Context injection is a separate hook (`session_context.py`, UserPromptSubmit).

5. **Sync happens only at SessionEnd, in a fixed order.** `vault_sync.py` must run after
   `session_end.py` so the daily journal note it writes is included in the commit;
   `memsearch_sync.py` is a separate, independent SessionEnd entry (split by ADR-016) for the
   memsearch repo. Neither auto-commit runs mid-session.

6. **Vault-not-repo rule.** `/os-vault:write` writes only to the resolved vault root
   (`${OS_VAULT_PATH:-$HOME/Documents/SecondBrain}`), never to a project repository. The vault
   path is resolved mechanically at the start of every write — never hardcoded.

7. **Write is query-first.** Before creating a new note, check for an existing note on the
   same subject; a contradicting/extending fact updates the existing note (bumping
   `last_updated`) rather than creating a duplicate.

8. **No silent new note types.** A fact that fits no existing type is filed under the closest
   existing type with a visible `## Type-fit note` misfit marker, or escalated to
   `/os-vault:design-template` — never given an invented type silently.
