mirror of
https://github.com/Ar9av/obsidian-wiki.git
synced 2026-09-14 20:36:34 +08:00
8b5859d0f8
* fix(cache): lock and atomically write .manifest.json update_source was a plain read-modify-write with no mutual exclusion, so any two overlapping writers lost an entry silently: the second reader's snapshot predated the first writer's write. This fires in three real configurations — batch-plan fan-out dispatching parallel ingest subagents, the Dockerized server writing a vault a local skill is also using, and a scheduled daily-update overlapping an interactive session. Reproduced with 12 concurrent update_source processes against one vault: 6 of 12 entries recorded before, 12 of 12 after. Writes now take an advisory lockfile and replace the manifest atomically via a temp file plus os.replace. O_CREAT|O_EXCL rather than fcntl because this ships on Windows. Hashing stays outside the lock — it can take seconds on a large source tree and nothing in the manifest depends on it. The contention test spawns real subprocesses; a single-process test cannot observe this race. * feat(trust): flag illegal lifecycle transitions in lint The lifecycle field is a state machine, but nothing enforced its edges. Ledger entries now record the lifecycle at review time, giving lint a baseline to compare the current frontmatter against. Only edges that are illegal for every possible sequence of unobserved intermediate states are flagged: falling back to draft (only ingest sets draft) and exiting archived (terminal). draft -> verified is deliberately not flagged — ledger snapshots are sparse, so a legitimate intermediate reviewed may simply never have been recorded, and flagging that pair would fire on valid history. Additive: entries predating the lifecycle field carry no baseline and are skipped, so existing vaults behave identically until their next trust-record. Owner-extended lifecycle states never match the illegal pairs, so the check degrades to a no-op rather than firing on states it does not understand. Warns by default, fails under --strict-trust, matching how the surrounding trust checks were already staged. * feat(wiki-status): add vault equilibrium mode The maintenance skills each optimize one shared vault for a different objective, so any of them can undo another's work and no single skill reporting clean means maintenance is done. Equilibrium mode runs every maintenance audit in report-only form and reports whether any skill still has a pending change. The vault is converged only when all of them propose nothing. It also detects oscillation via a snapshot in _insights.md, alongside the existing GRAPH_SNAPSHOT: a skill whose pending count keeps returning after being driven to zero is being reversed by another skill, and the vault can never settle. Reported, never auto-fixed — resolving it is a decision about whose objective wins. Pending moves are attributed back to their manifest source, so a source that repeatedly produces pages needing repair surfaces as a suggestion to review its source_quality. Report-only; the owner still decides through the existing trust flow. Skill-only, no Python: lint already emits JSON counts and the other three audits are LLM passes. * docs: document manifest write safety, lifecycle checks, and equilibrium Covers the advisory lock and atomic manifest write (including the parallel-run contract), the illegal_lifecycle_transitions check and why draft -> verified is excluded, and equilibrium mode in the architecture feature list.
13 KiB
13 KiB