Files
MultiPhysicsVault/CHANGELOG.md
T
김경종 72dad72703
Tests / Hermetic test suite (push) Has been cancelled
Tests / Skill frontmatter validation (push) Has been cancelled
add claude-obsidian
2026-05-28 10:57:16 +09:00

46 KiB
Raw Blame History

Changelog

All notable changes to claude-obsidian. Format: Keep a Changelog. Versioning: SemVer.

[1.9.2] - 2026-05-27 (prompt-cache hardening + path-handling robustness)

Ports Anthropic prompt-caching best practices into the one place the plugin calls the Anthropic API directly: tier-1 contextual-prefix generation in scripts/contextual-prefix.py. Verified by full-repo sweep that cache_control and the Anthropic API surface exist nowhere else (incl. claude-canvas/). No change to retrieval output — API payload shape + observability only.

Changed

  • Cache only above the Haiku floor (scripts/contextual-prefix.py). The page-body cache_control marker is now attached only when the body clears the Haiku 4.5 minimum cacheable size (HAIKU_CACHE_MIN_CHARS = 16384, ~4096 tokens × 4 chars/token). Below the floor the Anthropic API silently ignores the marker, so the prior unconditional marker was a no-op that misled the reader. Extracted as the pure, unit-tested cache_control_for().
  • .claude-plugin/plugin.json + marketplace.json version 1.9.1 → 1.9.2.

Added

  • Cache telemetry (scripts/contextual-prefix.py). The tier-1 path now logs cache: wrote=<N> read=<N> tok from the response usage fields — integers only, never page content, preserving the v1.7.1 data-egress posture. Implements the docs' "monitor cache hit rates" guidance and reveals whether the body cache is actually firing given the floor.
  • Sequential-invariant note at the chunk loop (process_page), documenting that cache reads depend on chunk 0's response landing before chunk 1 is sent (Anthropic prompt-caching concurrency rule). Guards against a future parallelization silently zeroing every cache read.
  • tests/test_contextual_prefix.py — hermetic coverage of the cache_control_for() floor decision (below / at / above floor, empty body, floor constant matches the documented Haiku minimum). Wired into make test (now 9 suites) + make test-contextual.

Documented

  • Tier-1 "prompt-cached" claim now states the ~16 KB Haiku floor in the contextual-prefix.py module docstring and the ingest diagrams in docs/compound-vault-guide.md and skills/wiki-retrieve/SKILL.md, so docs match runtime behavior.

Fixed

  • Explicit missing or out-of-vault page paths now fail cleanly (scripts/contextual-prefix.py). A single explicit path that does not exist exits 3 (was: silent exit 0, swallowed by the is_file() filter in main()); a path resolving outside the vault exits 2 with a message (was: a raw ValueError traceback from relative_to()). --all runs are unaffected.
  • Removed the dead EXIT_NO_ADDRESS (exit 5) constant and its docstring entry — it was defined and documented but never raised. Renamed the shadowed prefix progress-label variable in process_page to progress.

Verification

  • make test: 9 hermetic suites green; the contextual suite now mocks the API payload to assert cache_control attaches only above the floor and the model reply is truncated to one line. No regressions.
  • Explicit-path exit codes confirmed by run: missing in-vault path → 3, out-of-vault path → 2, valid page → 0, --all unaffected.
  • python3 scripts/contextual-prefix.py wiki/getting-started.md --peek: tier selection unchanged (synthetic without --allow-egress).
  • Live tier-1 telemetry leg (sends page bodies off-machine) requires explicit --allow-egress and is left to operator verification per the repo's consent design.

[1.9.1] - 2026-05-18 (v1.9.0 audit hardening)

Patch release closing 6 of 6 remaining HIGH/MEDIUM findings from the v1.9.0 pre-public-promotion audit (docs/audits/v1.9.0-pre-public-promotion-audit-2026-05-18.md) plus 3 LOW hardening items. Composite score moves from 91.6 to ~94 raw average. Public-promotion ship verdict remains GREEN.

Fixed (defensive hardening)

  • H4 — stale-lock reaper wiring (hooks/hooks.json). New SessionStart command runs bash scripts/wiki-lock.sh clear-stale --max-age 3600 at every session resume/startup. Locks orphaned by a crashed batch ingest get reaped automatically on the next session, not just on operator demand.
  • S2 — opt-out gate for PostToolUse auto-commit (hooks/hooks.json). Hook now exits early if .vault-meta/auto-commit.disabled exists. Default behavior unchanged for existing users; per-vault opt-out is one touch away. Useful for shared repos, CI runs, or any scenario where the operator wants to commit manually.
  • Data M3 — symlink canonicalization (scripts/wiki-lock.sh:110-142). validate_path() previously rejected literal .. segments but did not canonicalize symlinks. A symlink inside wiki/ resolving outside VAULT_ROOT could escape. Now resolves via python3 os.path.realpath and rejects any path whose canonical form is outside commonpath(VAULT_ROOT, target). Cross-platform (GNU coreutils + macOS BSD); no realpath flag dependency.
  • Data M4 — .vault-meta/locks/.gitkeep + gitignore pattern change. .vault-meta/locks/* (not the dir itself) is now ignored; .gitkeep is whitelisted so the directory ships on fresh clone. Runtime behavior unchanged (ensure_dirs() always created it lazily); this just removes the first-acquire side-effect on directory presence.
  • Data M1 — rerank.py warning routes to hook.log (scripts/rerank.py:158-176). When the embed-cache lock is unavailable after 3 tries, the WARN line now also appends to .vault-meta/hook.log with a timestamp, so users see the event via wiki lint or by tailing the log. stderr-only was invisible to most callers.
  • S4 — ollama-localhost assert (bin/setup-retrieve.sh:97-117). If OLLAMA_URL env var points off-localhost, refuse to probe unless --allow-remote-ollama is passed. Mirrors the existing scripts/tiling-check.py:351 gate. Closes a defense-in-depth gap where a malicious env var could redirect probes to an attacker-controlled endpoint.

Documented

  • H2 + S3 — multi-tenant threat model (SECURITY.md). New "Threat model: single-tenant vault" section documents three intentional design choices (cross-process lock release, auto-commit hook scope, filesystem-permission trust boundary) and the mitigations for shared-host deployments. Closes the documentation gap the audit flagged: the design choices are correct for single-tenant, but operators in shared-host scenarios deserve to know what changes for them.

Changed

  • .claude-plugin/plugin.json + marketplace.json version 1.9.0 → 1.9.1.

Deferred to v1.9.2 (not in this release)

  • Data M2 — embed-cache + chunk-orphan GC: new --gc subcommand for bm25-index.py + contextual-prefix.py that prunes entries whose backing pages no longer exist. Requires hermetic tests covering edge cases; scoped for a dedicated release.
  • W1 — wiki/meta/ release-session note relocation: 12 files with incoming wikilinks need a coordinated graph update. Bundled with References M1+M2 (17 dead wikilink targets) for one-pass wiki cleanup.
  • Security S1 — Excalidraw checksum pin: requires upstream release hash verification + maintenance burden for future releases. Tracked separately.
  • GROW note from v1.9.0 audit — 7th always-check cut in agents/verifier.md: cross-file string consistency check (catches the class of bug where a single-file fix should have been a multi-file cascade, like the 548d294 + F1-F5 sequence).

Verification

  • make test: 8 hermetic suites green (~1234 assertions). No regressions.
  • Live symlink-escape test on wiki-lock.sh validate_path: ln -s /tmp/foo ./escape && bash scripts/wiki-lock.sh acquire escape/x.md correctly rejects with "path resolves outside vault via symlink".
  • Both plugin manifests parse as JSON.
  • Pre-push verifier agent dispatch on staged diff: SHIP, 0 BLOCKER, 0 HIGH.

[1.9.0] - 2026-05-18 (10-principle thinking framework)

Minor release adding the 10-principle thinking framework as a first-class layer of the plugin. The framework (OBSERVE-OBSERVE-LISTEN-THINK-CONNECT-CONNECT-FEEL-ACCEPT-CREATE-GROW) is integrated at three levels: as the new /think skill, as an appendix on every existing SKILL.md, and as the methodology spine for the v1.8.0 pre-push audit (which used it as its phase structure). Skill count: 14 → 15.

Added

  • skills/think/SKILL.md — new skill #15. Canonical source for the 10-principle thinking loop. Walks Claude through external observation, metacognition (the often-skipped one), active listening, first-principles analysis (six-cut kernel lives here), lateral connection, system orchestration, intuition, intellectual humility (anti-sycophancy enforcement), generative output, and iterative growth. Triggers on "think this through", "10-principle review", "/think", "OBSERVE LISTEN THINK", "deep think", "systematic thinking", "structured reasoning". Allowed tools: Read, Grep, Glob, Bash (read-only; loads structure and discipline, not mutation). ~250 lines covering the 10 principles with one-paragraph definitions, when-to-invoke guidance, stage-by-stage prompts (5 questions per stage), anti-patterns (the common skips), and composition notes with /best-practices, /save, /wiki-lint, agents/verifier.md, and /autoresearch.

Changed

  • All 14 existing SKILL.md files — each receives a unique "## How to think (10-principle mapping)" appendix at the end. Per-skill 10-row table mapping each principle to that skill's specific work. Examples: wiki-mode's OBSERVE-internal is "audit the assumption that mode=generic is the default"; autoresearch's OBSERVE-internal is "am I steering the search toward what I already expect to find? confirmation bias kills research"; wiki-lint's FEEL is "a lint report should empower, not shame". Each appendix is non-trivial and skill-specific (not a template stub), satisfying the plan's verification rule #12.

  • .claude-plugin/plugin.json + marketplace.json — version 1.8.2 → 1.9.0. Description unchanged (the framework is additive to the v1.8.0 + v1.8.2 surface).

Repo hygiene (first-public-release prep)

  • CONTRIBUTING.md (NEW) — workflow, six-cut self-review checklist, commit conventions, test requirements.
  • CODE_OF_CONDUCT.md (NEW) — adopts Contributor Covenant v2.1 by reference.
  • SECURITY.md (NEW) — private disclosure policy, response SLA, scope, credit policy.
  • .github/ISSUE_TEMPLATE/bug_report.md (NEW) — reproduction + environment + skill-affected fields.
  • .github/ISSUE_TEMPLATE/feature_request.md (NEW) — scope + compatibility + testing fields.
  • .github/pull_request_template.md (NEW) — six-cut self-review + test results + verifier verdict + CHANGELOG reminder.
  • .github/workflows/test.yml (NEW) — CI runs make test on push/PR + validates SKILL.md frontmatter + agents tools: declaration + plugin manifest JSON validity.
  • Manifest + doc URL updatesplugin.json, marketplace.json, and 18 other files updated to reference the canonical repository URL.

Why this release

Per the v1.8.0 pre-push audit's GROW notes (docs/audits/v1.8.0-pre-push-audit-2026-05-18.md §10), the 10-principle framework proved its value as the AUDIT's mental spine — OBSERVE-internal forced explicit bias documentation; GROW forced a feedback-loop section. Shipping it as a first-class skill (and as appendices on all existing skills) makes the discipline available to every future invocation, not just to one-off audits. This is the GROW step of the audit itself, embodied in code.

Compass axis status after v1.9.0

Axis v1.8.0 v1.9.0
Compounding wiki primitive #1 #1
Multi-writer safety #1 #1
Retrieval architecture (free tier) #1 #1
License / openness #1 #1
Methodology support #1 #1 (deepened by framework integration)
Derivative outputs NO NO (v2.0 scope)
GUI / install ergonomics NO NO (v2.5+ scope)

5 of 7 axes #1 (unchanged count, but methodology axis deepens — claude-obsidian is now the only Claude+Obsidian plugin shipping methodology modes AND a first-class thinking-loop framework AND per-skill thinking guidance).

Migration notes

  • v1.8.x vaults: no action needed. All existing skills work identically; the "How to think" appendix is additive guidance, not behavioral change.
  • /think is invocable from any project that has this plugin installed; it does not require a vault.
  • The framework can be invoked explicitly (/think <problem>) or applied implicitly when an existing skill's appendix references it.

Composition

  • /think + /save = the canonical compounding loop. Apply the 10 principles to a problem; when done, save the insights worth not re-deriving.
  • /think + /best-practices = engineering discipline at the THINK stage of the framework. The six-cut kernel IS the inside of stage 4.
  • /think + agents/verifier.md = an OBSERVE-internal substitute for solo work — fresh-context reviewer that catches biases the chair missed.

[1.8.2] - 2026-05-18 (pre-push audit closure)

Patch release closing all 4 HIGH findings + 1 leaked BLOCKER-class hardening from the v1.8.0 pre-push audit. Audit: docs/audits/v1.8.0-pre-push-audit-2026-05-18.md. Per the audit's strict push gate (any BLOCKER halts), v1.8.2 takes the release from YELLOW (0 BLOCKER / 4 HIGH) to GREEN (0 BLOCKER / 0 HIGH).

Fixed

  • H1 — scripts/detect-transport.sh: implement manual_override. The documented escape hatch for MCP-only users ("manual_override": true in transport.json) was documented at wiki/references/transport-fallback.md but never honored by the script. v1.8.2 parses the existing snapshot BEFORE auto-detection; when manual_override: true, the user's preferred and fallback_chain are preserved across normal cycles AND --force refreshes. Auto-detection still runs to refresh the available.cli.* informational fields. Field round-trips through the JSON schema (new "manual_override": <bool> in every snapshot). Verified by smoke test: a pinned "preferred": "mcp-obsidian" survived a --force refresh.
  • H2 — agents/wiki-ingest.md: add Bash to tools + add ## Mode awareness (v1.8+) section. The parallel batch-ingest sub-agent was missing Bash in its tools: frontmatter despite mandating bash scripts/wiki-lock.sh acquire/release in its body — this defeated the v1.7 multi-writer safety guarantee. Sub-agent was also missing v1.8 mode-routing awareness, so batch-ingest in LYT/PARA/Zettelkasten vaults filed to v1.7 generic paths. Both gaps closed.
  • H3 — skills/autoresearch/SKILL.md: new ## Web egress hygiene (v1.8.2+) section. Four sub-policies: (1) URL validation (reject file://, javascript:, RFC1918), (2) content sanitization before write (strip <script>/<iframe>, escape [[/]] injections, reject embedded frontmatter delimiters, 50KB truncation), (3) per-loop cost expectation (~45 WebFetch calls per run), (4) failure mode (log to wiki/log.md, never silently swallow). The router's safe_name() is the FILENAME guard; this is the BODY-content guard.
  • H4 — skills/save/SKILL.md: prepend Step 0: Decide the destination root. The skill body assumed project-local wiki/ filing while the global ~/.claude/CLAUDE.md /save rule mandates personal-vault filing for cross-project saves. Step 0 makes the routing decision explicit with three rules in order: user-explicit override → project/global CLAUDE.md /save override → project-local wiki/ default. Path sanitization still applies regardless of destination root. Workflow step 5 now requires a collision check (ASK before overwrite).
  • wiki/references/transport-fallback.md: §Manual override now describes the actual v1.8.2 behavior (preserves preferred+fallback_chain while still refreshing available.cli.*; field round-trips through snapshot).

Changed

  • .claude-plugin/plugin.json + marketplace.json: version 1.8.0 → 1.8.2.
  • docs/audits/v1.8.0-pre-push-audit-2026-05-18.md (NEW): full pre-push audit report. 14 per-skill scores (average 84.6/100), per-tier finding ledger, v1.8.2 fix replay, hook safety, manifest accuracy, push-gate decision tree. Audit methodology used the 10-principle thinking spine (OBSERVE-OBSERVE-LISTEN-THINK-CONNECT-CONNECT-FEEL-ACCEPT-CREATE-GROW) as audit phases.

Verification

  • All 8 hermetic test suites green (~1234 assertions): allocate-address, tiling-check, boundary-score, bm25-index, retrieve, wiki-lock, concurrent-write, wiki-mode.
  • v1.8.2 manual_override smoke test: pinned preferred="mcp-obsidian" survived --force refresh.
  • All path-traversal attack vectors against route_path() confirmed sanitized inside vault root (6 dedicated assertions).
  • mkstemp atomic write yields 0600 perms (verified via stat).
  • --mode preview is non-mutating (verified via mtime).

Known issues at v1.8.2 (deferred to v1.9 or later)

The pre-push audit also surfaced 14 MEDIUM and 45 LOW findings. None block release. Triage in audit §12. Highlights:

  • wiki-cli mcp-obsidian + mcpvault tiers documented as fallback positions 2/3 but unreachable from auto-detection (deferred — manual_override is the workaround until MCP auto-detect ships in v1.7.x patch).
  • No tests/test_detect_transport.sh yet for v1.7+ transport script (planned v1.8.3).
  • 7 skills declare incomplete allowed-tools lists (missing Bash despite shelling out) — works in practice (harness default-allows), but convention violation (planned v1.8.3).
  • tests/__init__.py missing → python3 -m unittest tests.X form fails (direct invocation works) (planned v1.8.3).
  • Various doc/reality drift around the v1.8 ID format change (14-digit → 20-digit), v1.8 --mode flag not yet referenced in consumer docs (deferred LOW polish PR).

[1.8.0] - 2026-05-17 (methodology modes — closes compass priority gap 5)

Minor release closing the 5th and final priority gap from the May 2026 compass artifact: methodology support. Adds the wiki-mode skill with first-class support for four organizational styles (LYT / PARA / Zettelkasten / Generic). After this release, claude-obsidian is #1 on 5 of 7 axes per compass framework — up from 4/7 in v1.7. Full guide: docs/methodology-modes-guide.md.

Added

  • skills/wiki-mode/SKILL.md — new skill (skill #14). Reads .vault-meta/mode.json; defaults to generic (v1.7 behavior) when absent. Triggers on "set vault mode", "switch to PARA", "use LYT", "zettelkasten setup", etc.
  • scripts/wiki-mode.py — pure-stdlib router + config helper. Subcommands: get (current mode), config (full JSON), route <type> <name> (suggested path), set <mode> (write mode.json), id (mint Zettel timestamp ID), templates (list per-mode templates).
  • bin/setup-mode.sh — interactive setup with --mode <name> non-interactive flag. Idempotent; safe to re-run to switch modes. Optionally seeds template folders for the chosen mode.
  • 6 per-mode templates under skills/wiki-mode/templates/:
    • lyt/moc-template.md, lyt/atomic-template.md
    • para/project-template.md, para/area-template.md, para/resource-template.md
    • zettel/atomic-template.md
  • tests/test_wiki_mode.py — hermetic test suite (15 assertions covering load/save round-trip, all 4 modes' routing, slugify Unicode handling, Zettel ID format, corrupted-config fallback, CLI subprocess paths). make test is now 8 suites.
  • docs/methodology-modes-guide.md — narrative guide; when-to-use-which decision tree per mode; full schema documentation; migration guidance.

Changed

  • skills/wiki-ingest/SKILL.md — new "## Mode awareness (v1.8+)" section. Skill now consults wiki-mode.py route before filing new source/entity/concept pages. mode=generic preserves v1.7 behavior byte-for-byte.
  • skills/save/SKILL.md — new "## Mode awareness (v1.8+)" section. Session notes now route per active mode (with explicit note that the global ~/Documents/Obsidian Vault/sessions/ rule still applies to cross-project saves).
  • skills/autoresearch/SKILL.md — new "## Mode awareness (v1.8+)" section. Research synthesis output routes per active mode; every new entity/concept page in the research loop also routes via the router.
  • Makefile — new test-mode and setup-mode targets; test aggregate now runs 8 suites; clean-test-state removes .vault-meta/mode.json + .vault-meta/hook.log.
  • .gitignore.vault-meta/mode.json + .vault-meta/mode.*.tmp added. Host-specific runtime config by default; git add -f to commit if the user wants the mode choice to follow the repo.
  • CLAUDE.md — new "## Methodology Modes (v1.8+)" section + skill table row + plugin-name header reference.
  • .claude-plugin/plugin.json + marketplace.json — version 1.7.2 → 1.8.0; descriptions refreshed to mention methodology modes and "5 of 5 priority gaps closed."

Compass axis status after v1.8.0

Axis (compass §1 + audit §9) v1.7.2 v1.8.0
Compounding wiki primitive #1 #1
Multi-writer safety #1 #1
Retrieval architecture (free tier) #1 #1
License / openness #1 #1
Methodology support TIE #1 ← v1.8.0
Derivative outputs NO NO (v2.0 scope)
GUI / install ergonomics NO NO (v2.5+ scope)

5 of 7 axes #1. Remaining 2 axes require multi-release effort.

Honest scope acknowledgment

  • "Best ever obsidian skill per the priority research" = the 5 priority gaps closed. v1.8.0 reaches this milestone.
  • "Best ever in the market" requires v2.0 (derive — audio/quiz/study) + v2.5+ (Community Plugin GUI fork). These are weeks of work per release; v1.8.0 is the foundation, not the substitute.
  • The v1.7.0 audit's 24 findings (1 BLOCKER + 6 HIGH + 10 MEDIUM + 7 LOW) are fully CLOSED-or-DEFERRED as of v1.7.2; v1.8.0 inherits a clean audit ledger.

Migration notes

  • v1.7.x vaults: no action needed. wiki-mode defaults to generic when .vault-meta/mode.json is absent, which is identical to v1.7 behavior. The mode-awareness sections in wiki-ingest/save/autoresearch are no-ops in generic mode.
  • To adopt a non-default mode: bash bin/setup-mode.sh (or bash bin/setup-mode.sh --mode <name>). Interactive prompt picks one of LYT/PARA/Zettelkasten/Generic; optionally seeds template folders.
  • Switching modes does NOT auto-migrate existing files. Manual migration via file manager or git mv.

[1.7.2] - 2026-05-17 (SSS+ convergence — closes every audit finding)

Patch release closing every remaining MEDIUM (M1-M10) and LOW (L1-L7) finding from the v1.7.0 audit. Combined with v1.7.1 (which closed the 1 BLOCKER + 6 HIGH), this means the v1.7.0 audit's full 24-finding ledger is now CLOSED or formally DEFERRED-with-rationale. Plan: docs/audits/v1.7.2-sss-plus-plan.md.

Added

  • agents/verifier.md two new "always check" cuts (83d18ea): #5 Git hygiene (any new written path NOT in .gitignore → HIGH; would have caught the v1.7.1 .vault-meta/hook.log self-pollution bug mechanically); #6 Additive-without-pruning (if git diff --shortstat main..HEAD shows >+500 LOC with <50 deletions, flag MEDIUM). Verifier learns from what its prior dispatches missed.
  • Unicode multilingual test (8c219fb): tests/test_bm25_index.py::test_tokenize_unicode_multilingual covers Cyrillic, CJK, accented Latin, pure-emoji skip, mixed ASCII+non-ASCII.
  • --explain + --no-rerank test coverage (a80ae61): tests/test_retrieve.py now exercises both flags hermetically (test_explain_flag_adds_diagnostics_block + test_no_rerank_flag_strategy_bm25_only). +6 assertions.
  • Newline + carriage-return path rejection tests (d0db354): tests/test_wiki_lock.sh +2 assertions for the new validate_path rejections.
  • [i/total] progress prefix on contextual-prefix.py per-page logs (59cd7c8): Stage 1 over 47 pages with tier-2 (claude-cli) takes 5+ min; user now sees position, not just opaque per-page lines.

Changed (defensive-input + correctness fixes)

  • M2 — Unicode-aware BM25 tokenizer (8c219fb): [A-Za-z][A-Za-z0-9'\-]*\w[\w'\-]* with re.UNICODE. CJK / Cyrillic / Devanagari / accented Latin vaults previously had content silently dropped at index time. Same regex mirrored in scripts/baseline-v16.py so v1.6/v1.7 retrieval comparisons stay apples-to-apples for non-ASCII corpora.
  • M3 — scripts/rerank.py off-localhost error rewritten (d0db354): from "pass --allow-remote-ollama" to a 3-option breakdown citing the actual host, concrete recovery steps for each option, and the canonical paths.
  • M4 — scripts/wiki-lock.sh validate_path() rejects newlines + carriage returns (d0db354): would have silently corrupted the meta-lock line format.
  • M5 — scripts/retrieve.py import_sibling() wraps in try/except (d0db354): ImportError / SyntaxError / AttributeError now produce friendly diagnostics with recovery hints (bash bin/setup-retrieve.sh --check) instead of bare Python tracebacks. Pre-checks target file existence.
  • M6 — scripts/contextual-prefix.py empty-body WARN (d0db354): frontmatter-only pages now produce explicit WARN: ... has no chunkable body content instead of silent chunks=0.
  • M7 — scripts/rerank.py save_cache() non-blocking lock + 3-attempt retry (d0db354): replaces blocking fcntl.LOCK_EX (no timeout) with LOCK_NB + 100ms retry; falls back to unlocked write with WARN if all 3 attempts fail. Prevents indefinite hang on NFS / FUSE mounts without lock support. The temp+rename pattern provides write atomicity even unlocked.
  • L2 — Stage 1 progress indicator (59cd7c8): per-page log lines now carry [i/total] prefix.
  • L6 — scripts/wiki-lock.sh header doc (59cd7c8): explicit distinction between STALE_AFTER_SEC (per-acquire, default 60s) and clear-stale --max-age (admin reaper, default 3600s). Both time-since-acquire but distinct scopes.
  • L7 — scripts/bm25-index.py BM25 divide guard (59cd7c8): avg_dl_safe = avg_dl or 1.0. Currently unreachable but invariant-by-construction now rather than emergent-from-reachability.

Removed (kernel: "delete more than you add")

  • L3 — dead bm25_score() function (eafd449): 28 lines, never called, self-documented as "placeholder; real score computed in query()". Removed.
  • L4 — --rebuild flag stub on scripts/bm25-index.py build (eafd449): declared but never read; was reserved for incremental mode not in v1.7. Per kernel: no abstraction without 3 real callers.
  • L5 — --no-bm25 flag stub on scripts/retrieve.py (eafd449): returned EXIT_USAGE with "reserved for v1.7.x vector-only mode." Same kernel principle.

Honest accounting

  • Net LOC delta main..HEAD is +6009 / -30, NOT meeting the plan §1 acceptance criterion (≤+5000 OR ≥-200). Per plan §4 failure clause: "Do not invent prunes to game the metric." Honest decomposition: ~5500 LOC across new files alone (4 new scripts + 4 new tests + 2 new skills + 1 new agent + 1 new bin + ~2200 LOC docs). The v1.7 line was net-new feature substrate, not a refactor; v1.6 had no equivalent of a retrieval pipeline, lock primitive, transport detector, or contextual prefix generator to delete. Kernel-application axis ceilings at ~92-95 for the v1.7 line; the deduction is structural to building substrate, not negligence. Documented in docs/audits/v1.7.0-audit-2026-05-17.md §10.2.
  • M9 (bounded-slices: 4 skills touched by both §3.2 and §3.4) is documented as a process note in audit §10.3; not a code-level fix.
  • M11 (synonym category benchmark tied 60%/60%) persists post-tokenizer-change; v1.7 hybrid neither helps nor hurts on this category. Filed for v1.7.x rerank threshold tuning.
  • M12 (negative-query precision) was tied at 40%/40% in v1.7.0; post-Unicode-tokenizer it's 40%/20% (+20pp). Empirically closed by the tokenizer change.
  • L1 (§3.1 substrate +17/-5 no deletion) documented as defensible process note in audit §10.3.

Benchmark refresh (full 50-query corpus, v1.7.2 measurement)

Run via python3 scripts/benchmark-runner.py:

Category N v17 top-1 v17 top-5 v16 top-1 v16 top-5 Δ top-1
cross-page 10 20.0% 80.0% 30.0% 40.0% -10.0pp
derived 25 68.0% 88.0% 12.0% 24.0% +56.0pp
negative 5 40.0% 80.0% 20.0% 80.0% +20.0pp
partial-recall 5 60.0% 100.0% 20.0% 60.0% +40.0pp
synonym 5 60.0% 100.0% 60.0% 100.0% +0.0pp
TOTAL 50 54.0% 88.0% 22.0% 44.0% +32.0pp

Error reduction: +41.0% vs the ≥30% ship gate — PASS.

The +32pp/41% slightly beats the v1.7.0 audit's reported +30pp/+39.5%; the Unicode tokenizer change made baseline-v16.py marginally weaker (2pp on its top-1) which counts as a delta improvement for v1.7. cross-page top-1 regression vs audit (was +0pp, now 10pp) is within benchmark noise on N=10; cross-page top-5 stayed at 80% which is the synthesis-relevant metric.

Migration notes

  • v1.7.1 vaults: no action needed. All v1.7.2 changes are backward-compatible behavior improvements.
  • Re-running bash bin/setup-retrieve.sh is recommended (rebuilds BM25 index with the new Unicode tokenizer; multilingual content that was silently dropped will now be indexed).
  • The v1.7.0 audit's full 24-finding ledger is now CLOSED-or-formally-DEFERRED. v1.7.2 marks the end of the v1.7 line's audit-debt remediation cycle.

[1.7.1] - 2026-05-17 (audit-driven patch)

Patch release closing the 1 BLOCKER + 6 HIGH findings from the v1.7.0 audit (docs/audits/v1.7.0-audit-2026-05-17.md). All v1.7.0 features remain available; the changes are guard-rails and one new agent.

Fixed

  • BLOCKER B1 — Data egress without consent (ca68bb6). scripts/contextual-prefix.py now requires an explicit --allow-egress flag (default off) before selecting tier-1 (Anthropic API) or tier-2 (claude CLI subprocess). Without the flag, pick_prefix_tier() returns "synthetic" regardless of ANTHROPIC_API_KEY or claude binary presence. bin/setup-retrieve.sh adds a y/N consent prompt before any non-synthetic Stage 1 run. skills/wiki-retrieve/SKILL.md adds a Data Privacy callout (also closes H6). Mirror of the existing scripts/tiling-check.py:351 --allow-remote-ollama precedent.
  • H1 — Stage 1 failure had no rollback path (4837d4f). bin/setup-retrieve.sh now captures Stage 1's exit code, exits 5 on non-zero, and prints a 3-option recovery hint (incremental resume, full wipe, single-page re-process). Stage 2 only runs after Stage 1 success.
  • H2 — make clean-test-state didn't remove v1.7 artifacts (7e1f187). Extended the target to remove .vault-meta/chunks/, .vault-meta/bm25/, .vault-meta/locks/, .vault-meta/transport.json, .vault-meta/.wiki-lock.meta, and the related .tmp files. The Makefile target now matches the v1.7 .gitignore set.
  • H3 — PostToolUse hook swallowed lock-check errors (7120970). Restructured hooks/hooks.json to capture the wiki-lock script's exit code directly (not via a pipeline), defer the auto-commit on any non-zero rc, and only run git add after both the rc check and the non-empty-list check pass.
  • H4 — No verifier-agent pass at workstream gates (3ea443f). Added agents/verifier.md — a read-only (Read/Grep/Glob/Bash only; no Write/Edit) pre-commit specialist that reads the staged diff, applies the /best-practices six-cut + agent kernel, and returns findings in four tiers (BLOCKER/HIGH/MEDIUM/LOW). CLAUDE.md "Pre-commit verifier (v1.7.1+)" section references it as the recommended pre-commit step.
  • H5 — detect-transport.sh JSON escaping was shell-only (722ac97). Added a json_escape() helper that pipes through python3 -c json.dumps, applied to CLI_VERSION (both obsidian-cli and obsidian-binary paths). The heredoc now emits ${CLI_VERSION} without surrounding quotes since the helper produces a pre-quoted JSON string. Defense in depth against pathological upstream version output (backslashes, tabs, newlines, control chars).
  • H6 — skills/wiki-retrieve/SKILL.md had no Data Privacy section (bundled with B1 in ca68bb6). New section at the top of the skill body documents the two-layer egress guard (--allow-egress flag + setup-retrieve prompt) and points back to the tiling-check.py precedent.

Added

  • agents/verifier.md — pre-commit specialist; see H4 above.
  • scripts/baseline-v16.py + scripts/benchmark-runner.py — audit instrumentation that ran the 50-query retrieval benchmark documented in wiki/meta/retrieval-benchmark-v1.7.md. Result: v1.7 top-1 54.0% vs v1.6 baseline 24.0% (+30pp); error reduction +39.5% vs the ≥30% gate. Future audits can re-run with python3 scripts/benchmark-runner.py.
  • docs/audits/v1.7.0-audit-2026-05-17.md (481 lines) — the full audit report.
  • docs/audits/v1.7.1-fixes-plan.md — the sequenced 6-commit roadmap this release executes.

Changed

  • Versions bumped to 1.7.1 in .claude-plugin/plugin.json and .claude-plugin/marketplace.json (description fields refreshed to mention the verifier agent and the egress-consent guard).
  • CLAUDE.md "Pre-commit verifier (v1.7.1+)" section added; "Concurrency (v1.7+)" section retained verbatim.

Polish (post-fix self-audit refinements)

After the 7 v1.7.1 commits landed, a re-pass with agents/verifier.md against the slice surfaced 2 MEDIUM + 3 LOW polish items. All closed in one follow-up commit:

  • scripts/detect-transport.sh — split CLI_VERSION_RAW (human log line) from CLI_VERSION (pre-quoted JSON for the heredoc). The JSON-escape fix from H5 made the log line CLI: obsidian-cli ("1.12.0") carry visible quotes; the split keeps both paths clean. Also: CLI_VERSION_RAW="" initialized in the top-of-script init block alongside CLI_PRESENT, CLI_BINARY, CLI_VERSION (defense in depth under set -euo pipefail; closes a latent unbound-variable risk that worked today only by bash short-circuit semantics).
  • agents/verifier.mdtools: field kept as CSV (Read, Grep, Glob, Bash) to match in-repo precedent (wiki-ingest.md, wiki-lint.md). Both CSV and YAML list are accepted forms across ~/.claude/agents/ (audit-* use CSV, blog-* and challenge-auditor-* use YAML list), but the three local repo agents are CSV, so consistency-with-siblings is the deciding factor. The polish commit initially converted to YAML list per a prior verifier recommendation that didn't cross-check sibling files; reverted in the follow-up after deeper chair probe.
  • bin/setup-retrieve.sh — refreshed the header docstring (lines 13-26) to mention --allow-egress and the consent gate. Inline comments at line 121 were already correct; the file-top doc was the stale one.
  • scripts/contextual-prefix.py — docstring on generate_prefix() explaining the deliberate asymmetric fallback (api→cli→synthetic, but cli→synthetic only — climbing from cli to api would silently spend money the user did not authorize).
  • hooks/hooks.json — breadcrumb log to .vault-meta/hook.log on the rare non-zero LOCK_RC defer path. Verified with concurrency (10 parallel hook fires → 10 atomic lines, no interleaving; line length < PIPE_BUF), no format-string injection (printf uses literal format with %s placeholders), filesystem-failure edge cases preserve exit 0 (defer behavior intact). .vault-meta/hook.log added to .gitignore so the breadcrumb file is never auto-staged by the same PostToolUse hook (closes a self-pollution loop that would have surfaced on the first non-zero LOCK_RC event).

Migration notes

  • v1.6 vaults: no action needed. The new components are opt-in or read-only.
  • v1.7.0 adopters who provisioned bin/setup-retrieve.sh and had ANTHROPIC_API_KEY set: the next bin/setup-retrieve.sh run will prompt for consent before proceeding with the non-synthetic tier. Decline to keep all data on-machine (tier-3 synthetic), accept to preserve the prior behavior. Existing chunks/ data is unaffected either way.
  • Test suite: make test continues to run 7 hermetic suites (~1162 assertions). Zero ollama, zero network dependency.

[1.7.0] - 2026-05-17 (Compound Vault refoundation)

The v1.7 line, codenamed Compound Vault, refoundations the plugin around four pillars from the May 2026 gap analysis: substrate alignment with kepano/obsidian-skills, Obsidian-CLI-native transport, contextual + hybrid retrieval, and safe multi-writer ingest. v1.6 vaults that never install the new opt-in components see no behavior change. Full design rationale in docs/compound-vault-guide.md.

Added

  • §3.2 Default transportskills/wiki-cli/SKILL.md (recipe reference for Obsidian CLI), scripts/detect-transport.sh (writes .vault-meta/transport.json snapshot; auto-stale at 7d), wiki/references/transport-fallback.md (canonical decision tree). 5 transport-aware skills (wiki-ingest, wiki-query, save, autoresearch, wiki-lint) gained "## Transport (v1.7+)" sections.
  • §3.3 Hybrid retrieval pipeline (wiki-retrieve, opt-in) — implements Anthropic's Sept 2024 Contextual Retrieval pattern as agent-skill plumbing. 4 new scripts: scripts/contextual-prefix.py (3-tier auto: Anthropic API → claude CLI subprocess → synthetic), scripts/bm25-index.py (Okapi BM25, k1=1.5 b=0.75, pure stdlib, flock-guarded), scripts/rerank.py (cosine on nomic-embed-text via ollama, embed-cache), scripts/retrieve.py (orchestrator: BM25 top-20 → rerank top-5 → page dedupe). bin/setup-retrieve.sh opt-in bootstrap. skills/wiki-retrieve/SKILL.md documents the architecture and cost ceiling (~$12/1000 docs per Anthropic). Wired into skills/wiki-query/SKILL.md via "## Retrieval (v1.7+)" section with graceful exit-10 fallback to the v1.6 hot→index→drill read order.
  • §3.4 Multi-writer safety (wiki-lock, core)scripts/wiki-lock.sh per-file advisory locking. Age-based staleness (default STALE_AFTER_SEC=60), cross-process release allowed by design. 4 skills (wiki-ingest, wiki-fold, save, autoresearch) gained "## Concurrency (v1.7+)" sections with concrete acquire/release recipes. The latent corruption bug from v1.6 — documented but unenforced in skills/wiki-ingest/SKILL.md:259-264 — is now closed.
  • New skills (2): wiki-cli (§3.2) and wiki-retrieve (§3.3). Total skill count is now 13.
  • New scripts (6): detect-transport.sh, contextual-prefix.py, bm25-index.py, rerank.py, retrieve.py, wiki-lock.sh.
  • New tests (4): tests/test_bm25_index.py (~30 hermetic assertions including BM25 monotonicity and IDF positivity), tests/test_retrieve.py (22 hermetic assertions including end-to-end subprocess test), tests/test_wiki_lock.sh (14 hermetic assertions including age-based stale reap), tests/test_concurrent_write.sh (6 hermetic assertions; the critical multi-writer correctness gate — 10 parallel workers, no losses, no garbled lines). make test now runs 7 suites with zero network and zero ollama dependency.
  • New docs: docs/compound-vault-guide.md (omnibus v1.7 guide), wiki/references/transport-fallback.md (transport decision tree).
  • Makefile targets: test-bm25, test-retrieve, test-lock, test-concurrent, setup-retrieve.

Changed

  • §3.1 Substrate hard-prefer on kepano/obsidian-skillsskills/obsidian-markdown/SKILL.md, skills/obsidian-bases/SKILL.md, and skills/canvas/SKILL.md upgraded from soft-defer ("if kepano installed, prefer it") to hard-prefer ("this is a fallback; prefer kepano"). Architectural behavior unchanged; signal sharpened. skills/defuddle/SKILL.md documented as canonical (kepano does not ship a defuddle skill). .claude-plugin/marketplace.json declares recommendedCompanions: [kepano/obsidian-skills] with install hint.
  • hooks/hooks.json PostToolUse — added a lock-in-flight check before git add. When bash scripts/wiki-lock.sh list returns non-zero count, the auto-commit defers. Prevents torn commits during multi-agent ingest. Falls through gracefully if wiki-lock.sh is absent.
  • agents/wiki-ingest.md — rewrote the "Sub-agents MUST NOT" section. The prohibition on calling allocate-address.sh from sub-agents is preserved (counter monotonicity). A NEW rule is added: sub-agents MAY now write pages, but MUST acquire locks first.
  • Versions synced to 1.7.0 across plugin.json and marketplace.json.

Migration notes

  • v1.6 vaults need no action. The new components are opt-in (bash bin/setup-retrieve.sh for hybrid retrieval) or universally beneficial (wiki-lock is core; no setup needed). The plugin remains MIT-licensed; no paid tier introduced.
  • To install the recommended companion: claude plugin marketplace add kepano/obsidian-skills. Existing local fallbacks remain functional without it.
  • Estimated upgrade time: 5 minutes (substrate auto-detected; transport auto-detected on first session; retrieval requires explicit bash bin/setup-retrieve.sh).

Out of scope for v1.7 (deferred to v1.8+)

  • Methodology modes (LYT / PARA / Zettelkasten / Generic via wiki-mode skill) — planned for v1.8.
  • NotebookLM-class derivative outputs (audio, quiz, flashcards, study guide via wiki-derive) — planned for v1.9 or v2.0.
  • Multimodal ingest adapters (YouTube, PDF, EPUB, image OCR via wiki-ingest-multimodal) — planned for v1.9.
  • Periodic review artifacts (wiki-review) — planned for v1.8.

[1.6.0] - 2026-04-24

Added (DragonScale Mechanism 4, opt-in)

  • Boundary-first autoresearch: scripts/boundary-score.py computes (out_degree - in_degree) * recency_weight across the wikilink graph and emits top-K frontier pages. /autoresearch invoked without a topic now offers the top-5 frontier pages as research candidates when the vault has adopted DragonScale.
  • tests/test_boundary_score.py — 35 unit tests covering frontmatter parsing, recency weight, wikilink extraction (with code-block guard), graph construction, scoring, CLI interface.
  • make test-boundary target + integration into make test.

Changed

  • skills/autoresearch/SKILL.md — new Topic Selection section with three paths: explicit (A), boundary-first (B, opt-in), user-ask (C, default without DragonScale).
  • commands/autoresearch.md — no-topic usage documented for both modes.
  • wiki/concepts/DragonScale Memory.md — Mechanism 4 flipped from NOT IMPLEMENTED to shipped; exact scoring formula and "what is NOT included" callout added. Version bumped to v0.4.
  • Version synced to 1.6.0 across plugin.json and marketplace.json.

[1.5.1] - 2026-04-24 (Phase 3.6 hardening)

Fixed

  • scripts/tiling-check.py: --report PATH now resolved against VAULT_ROOT and rejected if it escapes (security: prevents hostile or accidental writes outside the vault).
  • .vault-meta/legacy-pages.txt: rollout baseline corrected from 2026-04-24 to 2026-04-23 (matches earliest addressed page in the seed vault).
  • AGENTS.md: wiki-fold listed in the skills table; stale claim that "all skills use only name/description" narrowed to newer skills (older skills still carry allowed-tools for Claude Code compatibility).
  • skills/wiki-ingest/SKILL.md: resolves the internal contradiction between "immutable .raw/" and "maintain .raw/.manifest.json" — user-dropped source documents remain immutable; only the manifest is wiki-ingest-maintained.
  • docs/install-guide.md: version 1.2.0 -> 1.5.0 with a DragonScale optional-install callout.

[1.5.0] - 2026-04-24

Added (DragonScale Memory extension, opt-in)

  • Mechanism 1 — Fold operator (skills/wiki-fold/): extractive, structurally-idempotent rollups of wiki/log.md entries into per-batch meta-pages under wiki/folds/. Dry-run via stdout by default (does not trigger PostToolUse auto-commit hook); commit mode explicit.
  • Mechanism 2 — Deterministic page addresses (opt-in): scripts/allocate-address.sh flock-guarded atomic allocator; new address: c-NNNNNN frontmatter convention; re-ingest idempotency via .raw/.manifest.json address_map. wiki-ingest and wiki-lint skills feature-detect DragonScale setup.
  • Mechanism 3 — Semantic tiling lint (opt-in): scripts/tiling-check.py uses local nomic-embed-text via ollama to flag candidate duplicate pages by cosine similarity. Banded thresholds (error/review/pass) documented as conservative seeds with manual calibration procedure.
  • wiki/concepts/DragonScale Memory.md — full design spec (v0.3) with four mechanisms, scope boundary, and primary-source citations.
  • bin/setup-dragonscale.sh — idempotent installer that provisions .vault-meta/ counter, thresholds, and legacy-pages manifest.
  • tests/ — shell + python test suite for the allocator and tiling-check. Run via make test.
  • Makefile — developer targets (test, setup-dragonscale, clean-test-state).

Changed

  • hooks/hooks.json PostToolUse now stages .vault-meta/ in addition to wiki/ and .raw/ so DragonScale runtime state is captured by the auto-commit hook.
  • skills/wiki-ingest/SKILL.md and skills/wiki-lint/SKILL.md gained opt-in DragonScale sections behind feature-detection guards; original behavior unchanged for vaults that have not run setup-dragonscale.sh.
  • agents/wiki-ingest.md explicitly forbids parallel sub-agents from calling the allocator (single-writer rule for address assignment).
  • agents/wiki-lint.md extended to describe Address Validation and Semantic Tiling checks.
  • Stale allowed-tools frontmatter removed from wiki-ingest and wiki-lint SKILL.md (kepano convention: only name and description).
  • Version strings synced across .claude-plugin/plugin.json, .claude-plugin/marketplace.json, and documentation.

Security

  • scripts/tiling-check.py locks OLLAMA_URL to localhost by default. Remote endpoints require --allow-remote-ollama. Symlinks and vault-root escapes are rejected before any read.

Not in this release

  • Mechanism 4 — Boundary-first autoresearch: documented in the spec as a future proposal; no code shipped. skills/autoresearch/SKILL.md unchanged.

[1.4.3] - prior

Previous state. See git log for details.