Self-organizing AI second brain for Obsidian + Claude Code. Drop any source and Claude reads, links, and files it into one connected knowledge graph of plain Markdown you own. AI note-taking, personal knowledge management (PKM), and an open-source Notion alternative. Based on Karpathy's LLM Wiki pattern.
This report presents the forensic synthetic code analysis of AgriciDaniel/claude-obsidian, a Python project with 14,330 GitHub stars. SynthScan v2.0 examined 51,467 lines of code across 161 source files, recording 732 pattern matches distributed across 13 syntactic categories. The overall adjusted score of 16.4 places this repository in the Moderate AI signal band.
The scanner applied 160+ deterministic lexical heuristics, multi-line block detectors, abstract syntax tree depth profilers, and a cross-file Jaccard similarity matrix to construct a statistically normalised synthetic code estimate. All matches are individually weighted by severity coefficient and contextual multiplier before summation, and the resulting headline score is temporally discounted to account for the repository's development history relative to the commercial emergence of large language model coding tooling (November 2022 onward).
Longitudinal tracking requires multiple scan runs. Once this repository is re-scanned after new commits land, this chart will visualise how the synthetic code signal evolves over time — enabling you to detect whether AI authorship is growing, stabilising, or being actively corrected by human engineers.
Classifies detected patterns by their diagnostic confidence and structural impact. CRITICAL patterns (coefficient 10) represent definitive synthetic signatures — hallucinated imports, explicit LLM attribution metadata — virtually never produced by human authors. HIGH (5) indicates strong structural tells such as cross-file repetition or cross-linguistic idioms. MEDIUM (2) covers recognisable conversational padding and AI-specific vocabulary. LOW (1) captures subtle indicators like tautological comments and generic boilerplate that require density to carry independent signal.
This horizontal bar chart decomposes the repository's raw synthetic code score by top-level directory, allowing you to pinpoint precisely which modules or components carry the highest AI authorship density. Directories with disproportionately high scores relative to their size warrant targeted manual review: concentrated AI signatures often trace back to mass-generated configuration layers, auto-ported test suites, LLM-scaffolded boilerplate classes, or entire subsystems authored under heavy copilot assistance. Use this view to prioritise your human code-review effort.
The scanner identified 732 distinct pattern matches across 13 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a statistically significant AI authorship indicator. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the diagnostic confidence level (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — comment-context matches receive a ×1.5 weight because LLMs systematically over-annotate. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier as dense clusters constitute far stronger evidence of synthetic authorship than isolated hits.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | tests/test_contracts.py | 68 | def test_capability_and_transaction_operation_types_cannot_drift(self) -> None: | CODE |
| LOW⚡ | tests/test_contracts.py | 71 | def test_canonical_contracts_validate(self) -> None: | CODE |
| LOW⚡ | tests/test_contracts.py | 74 | def test_manifest_covers_every_current_skill(self) -> None: | CODE |
| LOW⚡ | tests/test_contracts.py | 81 | def test_product_contract_locks_privacy_compatibility_and_release_authority( | CODE |
| LOW⚡ | tests/test_contracts.py | 285 | def test_missing_implementation_path_is_rejected(self) -> None: | CODE |
| LOW⚡ | tests/test_contracts.py | 292 | def test_unregistered_skill_is_rejected(self) -> None: | CODE |
| LOW⚡ | tests/test_contracts.py | 301 | def test_inconsistent_mutation_and_egress_declarations_are_rejected(self) -> None: | CODE |
| LOW⚡ | tests/test_contracts.py | 409 | def test_missing_optional_configuration_is_available(self) -> None: | CODE |
| LOW⚡ | tests/test_contracts.py | 414 | def test_partial_configuration_is_degraded(self) -> None: | CODE |
| LOW⚡ | tests/test_contracts.py | 422 | def test_complete_configuration_is_configured(self) -> None: | CODE |
| LOW⚡ | tests/test_contracts.py | 428 | def test_successful_execution_is_verified(self) -> None: | CODE |
| LOW⚡ | tests/test_contracts.py | 434 | def test_failed_execution_is_degraded(self) -> None: | CODE |
| LOW | tests/test_contracts.py | 105 | def test_evaluation_is_deterministic_and_has_no_absolute_roots(self) -> None: | CODE |
| LOW | tests/test_contracts.py | 113 | def test_canonical_core_capabilities_report_only_behavioral_verification( | CODE |
| LOW | tests/test_contracts.py | 148 | def test_canonical_verifiers_are_behavioral_or_explain_their_absence(self) -> None: | CODE |
| LOW | tests/test_contracts.py | 168 | def test_wiki_cli_and_lint_scopes_are_least_privilege(self) -> None: | CODE |
| LOW | tests/test_contracts.py | 211 | def test_verified_wiki_contract_covers_every_init_target(self) -> None: | CODE |
| LOW | tests/test_contracts.py | 244 | def test_cli_check_only_and_unknown_capability(self) -> None: | CODE |
| LOW | tests/test_contracts.py | 324 | def test_absolute_tracked_paths_are_rejected(self) -> None: | CODE |
| LOW | tests/test_contracts.py | 335 | def test_empty_verifier_requires_an_explicit_reason(self) -> None: | CODE |
| LOW | tests/test_contracts.py | 340 | def test_self_and_schema_only_verifiers_are_rejected(self) -> None: | CODE |
| LOW | tests/test_contracts.py | 379 | def test_malformed_json_returns_structured_errors(self) -> None: | CODE |
| LOW | tests/test_contracts.py | 385 | def test_duplicate_contract_keys_return_structured_errors(self) -> None: | CODE |
| LOW | tests/test_contracts.py | 445 | def test_missing_automated_verifier_stays_configured_with_reason(self) -> None: | CODE |
| LOW⚡ | tests/test_release.py | 355 | def test_tracked_symlink_is_rejected(self) -> None: | CODE |
| LOW⚡ | tests/test_release.py | 365 | def test_root_raw_and_live_vault_state_are_hard_rejected(self) -> None: | CODE |
| LOW⚡ | tests/test_release.py | 375 | def test_secret_token_is_rejected(self) -> None: | CODE |
| LOW⚡ | tests/test_release.py | 385 | def test_private_repo_url_needs_named_disclosure(self) -> None: | CODE |
| LOW⚡ | tests/test_release.py | 395 | def test_absolute_home_path_is_rejected(self) -> None: | CODE |
| LOW⚡ | tests/test_release.py | 403 | def test_personal_email_address_is_rejected(self) -> None: | CODE |
| LOW⚡ | tests/test_release.py | 413 | def test_quoted_unicode_literal_and_encoded_email_forms_are_rejected(self) -> None: | CODE |
| LOW⚡ | tests/test_release.py | 459 | def test_unreviewed_binary_is_rejected(self) -> None: | CODE |
| LOW⚡ | tests/test_release.py | 466 | def test_missing_config_and_non_zip_output_fail_closed(self) -> None: | CODE |
| LOW⚡ | tests/test_release.py | 476 | def test_failed_build_does_not_replace_existing_artifact(self) -> None: | CODE |
| LOW⚡ | tests/test_release.py | 483 | def test_collected_bytes_must_match_the_clean_git_blob(self) -> None: | CODE |
| LOW⚡ | tests/test_release.py | 651 | def test_traversal_entry_is_rejected_without_extraction(self) -> None: | CODE |
| LOW⚡ | tests/test_release.py | 659 | def test_archive_symlink_and_special_entry_are_rejected(self) -> None: | CODE |
| LOW⚡ | tests/test_release.py | 669 | def test_compressed_bomb_is_rejected_before_expansion(self) -> None: | CODE |
| LOW | tests/test_release.py | 66 | def test_public_policy_never_selects_root_contributor_vault_state(self) -> None: | CODE |
| LOW | tests/test_release.py | 170 | def test_release_authority_json_rejects_duplicate_keys(self) -> None: | CODE |
| LOW | tests/test_release.py | 184 | def test_release_authority_json_rejects_nonfinite_numbers(self) -> None: | CODE |
| LOW | tests/test_release.py | 200 | def test_release_authority_rejects_unknown_keys(self) -> None: | CODE |
| LOW | tests/test_release.py | 215 | def test_portable_unicode_path_collision_is_rejected_before_build(self) -> None: | CODE |
| LOW | tests/test_release.py | 232 | def test_two_builds_are_byte_identical_and_self_auditing(self) -> None: | CODE |
| LOW | tests/test_release.py | 267 | def test_public_marketplace_is_injected_only_into_the_audited_artifact( | CODE |
| LOW | tests/test_release.py | 341 | def test_dirty_and_untracked_worktrees_are_rejected_without_output(self) -> None: | CODE |
| LOW | tests/test_release.py | 427 | def test_release_safe_email_addresses_are_accepted(self) -> None: | CODE |
| LOW | tests/test_release.py | 438 | def test_non_email_at_sign_forms_are_accepted(self) -> None: | CODE |
| LOW | tests/test_release.py | 448 | def test_release_safe_domains_require_an_exact_match(self) -> None: | CODE |
| LOW | tests/test_release.py | 501 | def test_git_environment_cannot_redirect_release_provenance(self) -> None: | CODE |
| LOW | tests/test_release.py | 542 | def test_build_does_not_refresh_or_mutate_the_real_git_index(self) -> None: | CODE |
| LOW | tests/test_release.py | 575 | def test_release_version_and_date_surfaces_are_coordinated(self) -> None: | CODE |
| LOW | tests/test_release.py | 612 | def test_repository_allowlist_is_canonical_and_valid(self) -> None: | CODE |
| LOW | tests/test_release.py | 681 | def test_live_state_and_secret_filename_are_rejected(self) -> None: | CODE |
| LOW | tests/test_release.py | 699 | def test_archive_with_personal_email_address_is_rejected(self) -> None: | CODE |
| LOW | tests/test_release.py | 716 | def test_tampered_valid_artifact_fails_manifest_and_checksums(self) -> None: | CODE |
| LOW | tests/test_release.py | 734 | def test_mode_tampering_is_rejected_against_manifest(self) -> None: | CODE |
| LOW | tests/test_release.py | 750 | def test_local_header_timestamp_must_match_central_directory(self) -> None: | CODE |
| LOW | tests/test_release.py | 770 | def test_alternate_valid_zip_header_encoding_is_noncanonical(self) -> None: | CODE |
| LOW | tests/test_release.py | 794 | def test_audit_snapshot_rejects_artifact_path_replacement(self) -> None: | CODE |
| 463 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | tests/test_concurrent_write.sh | 56 | # ── Worker function: acquire lock, append, release ────────────────────────── | COMMENT |
| MEDIUM | tests/test_concurrent_write.sh | 81 | # ── Spawn workers in parallel ─────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/test_concurrent_write.sh | 100 | # ── Verify: file has seed + exactly N tagged lines ────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_concurrent_write.sh | 117 | # ── Verify: no orphaned lockfiles ─────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_concurrent_write.sh | 121 | # ── Verify: clear-stale reports 0 (nothing to reap) ───────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_concurrent_write.sh | 125 | # ── Verify: file content sanity (no truncated/garbled lines) ──────────────── | COMMENT |
| MEDIUM⚡ | tests/test_contextual_prefix.py | 50 | # ─── Below the floor → no cache_control (silent no-op avoided) ─────────────── | COMMENT |
| MEDIUM⚡ | tests/test_contextual_prefix.py | 60 | # ─── At / above the floor → ephemeral cache_control ────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_lock.sh | 77 | # ── acquire on a fresh path returns 0 ──────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_lock.sh | 81 | # ── second acquire while the lock is fresh returns 75 ──────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_lock.sh | 88 | # ── peek shows the lock ────────────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_lock.sh | 95 | # ── list shows the held lock ───────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_lock.sh | 102 | # ── release frees the lock (cross-process release is allowed by design) ───── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_lock.sh | 107 | # ── re-acquire after release succeeds ─────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_lock.sh | 112 | # ── short --stale-after-sec lets us test age-based reap quickly ───────────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_lock.sh | 146 | # ── peek on unheld path ────────────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_lock.sh | 150 | # ── path validation: absolute path rejected ────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_lock.sh | 154 | # ── path validation: traversal rejected ────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_lock.sh | 158 | # ── path validation: empty rejected ────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_lock.sh | 162 | # ── path validation: newline rejected (v1.7.2; closes audit M4) ────────────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_lock.sh | 168 | # ── path validation: carriage return rejected (v1.7.2; closes audit M4) ────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_lock.sh | 172 | # ── numeric inputs are validated before Bash arithmetic ────────────────────────────── | COMMENT |
| MEDIUM | tests/test_wiki_lock.sh | 306 | # ── stress: 10 unique paths all acquire cleanly ────────────────────────────── | COMMENT |
| MEDIUM | tests/test_wiki_lock.sh | 326 | # ── summary ────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_bm25_index.py | 60 | # ─── tokenize() ────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/test_bm25_index.py | 190 | # ─── build_index + query() ─────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/test_bm25_index.py | 856 | # ─── CLI smoke test ────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_mode.py | 200 | # ─── Zettel ID format ─────────────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_mode.py | 476 | # ─── Invalid content type raises ─────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_wiki_mode.py | 486 | # ─── CLI subprocess: `wiki-mode.py get` returns mode string ───────────────── | COMMENT |
| MEDIUM | tests/test_wiki_mode.py | 48 | # ─── Default-to-generic when no config file ────────────────────────────────── | COMMENT |
| MEDIUM | tests/test_wiki_mode.py | 65 | # ─── Existing config load ──────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/test_wiki_mode.py | 97 | # ─── Existing corrupt mode.json fails closed ──────────────────────────────── | COMMENT |
| MEDIUM | tests/test_wiki_mode.py | 116 | # ─── Mode=generic routing matches v1.7 conventions ────────────────────────── | COMMENT |
| MEDIUM | tests/test_wiki_mode.py | 142 | # ─── Mode=lyt routing: all atomic notes flat under wiki/notes/ ────────────── | COMMENT |
| MEDIUM | tests/test_wiki_mode.py | 154 | # ─── Mode=para routing: actionability-based folders ───────────────────────── | COMMENT |
| MEDIUM | tests/test_wiki_mode.py | 184 | # ─── Mode=zettelkasten routing: flat, timestamp-prefixed ──────────────────── | COMMENT |
| MEDIUM | tests/test_wiki_mode.py | 246 | # ─── Slugify handles unicode + special chars ──────────────────────────────── | COMMENT |
| MEDIUM | tests/test_wiki_mode.py | 405 | # ─── CLI --mode preview override (v1.8.2) ─────────────────────────────────── | COMMENT |
| MEDIUM | tests/test_wiki_mode.py | 529 | # ─── CLI subprocess: `wiki-mode.py id` returns a sortable nonce ID ─────── | COMMENT |
| MEDIUM | tests/test_wiki_mode.py | 549 | # ─── CLI subprocess: `wiki-mode.py route source NAME` returns a path ──────── | COMMENT |
| MEDIUM | tests/test_wiki_mode.py | 576 | # ─── CLI subprocess: invalid mode rejected ────────────────────────────────── | COMMENT |
| MEDIUM | tests/test_wiki_mode.py | 591 | # ─── CLI subprocess: templates listing returns all 6 ─────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_retrieve.py | 81 | # ─── import_sibling ────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_retrieve.py | 89 | # ─── chunk_snippet ─────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/test_retrieve.py | 104 | # ─── rerank.cosine() ───────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/test_retrieve.py | 238 | # ─── rerank.rerank() no-op fallback ────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/test_retrieve.py | 379 | # ─── Nomic asymmetric task prefixes and cache scheme ────────────────────── | COMMENT |
| MEDIUM | tests/test_retrieve.py | 620 | # ─── retrieve.py CLI: exit 10 when not provisioned ──────────────────────────── | COMMENT |
| MEDIUM | tests/test_retrieve.py | 820 | # ─── Integration smoke test: end-to-end with synthetic data ────────────────── | COMMENT |
| MEDIUM | tests/test_retrieve.py | 1109 | # ─── M8 closure: --explain and --no-rerank flag coverage ───────────────────── | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_transaction.py | 2009 | CODE | |
| LOW | tests/test_transaction.py | 2120 | CODE | |
| LOW | tests/test_transaction.py | 2344 | CODE | |
| LOW | tests/test_transaction.py | 2028 | CODE | |
| LOW | tests/test_windows_compat.py | 230 | CODE | |
| LOW | tests/test_contextual_prefix.py | 681 | CODE | |
| LOW | tests/test_contextual_prefix.py | 750 | CODE | |
| LOW | tests/test_lint_engine.py | 284 | CODE | |
| LOW | tests/test_ledgers.py | 321 | CODE | |
| LOW | tests/test_ledgers.py | 532 | CODE | |
| LOW | tests/test_setup_vault.py | 69 | CODE | |
| LOW | tests/test_bm25_index.py | 684 | CODE | |
| LOW | tests/test_bm25_index.py | 748 | CODE | |
| LOW | tests/test_bm25_index.py | 877 | CODE | |
| LOW | tests/test_capture.py | 1005 | CODE | |
| LOW | tests/test_retrieve.py | 579 | CODE | |
| LOW | tests/test_checkpoint.py | 169 | CODE | |
| LOW | tests/test_checkpoint.py | 531 | CODE | |
| LOW | tests/test_installed_tree_boundary.py | 50 | CODE | |
| LOW | claude_obsidian/release.py | 456 | CODE | |
| LOW | claude_obsidian/release.py | 837 | CODE | |
| LOW | claude_obsidian/release.py | 1310 | CODE | |
| LOW | claude_obsidian/release.py | 1336 | CODE | |
| LOW | claude_obsidian/release.py | 1984 | CODE | |
| LOW | claude_obsidian/checkpoint.py | 1190 | CODE | |
| LOW | claude_obsidian/checkpoint.py | 513 | CODE | |
| LOW | claude_obsidian/paths.py | 361 | CODE | |
| LOW | claude_obsidian/legacy_lock.py | 119 | CODE | |
| LOW | claude_obsidian/legacy_lock.py | 293 | CODE | |
| LOW | claude_obsidian/legacy_lock.py | 570 | CODE | |
| LOW | claude_obsidian/transaction.py | 419 | CODE | |
| LOW | claude_obsidian/transaction.py | 471 | CODE | |
| LOW | claude_obsidian/transaction.py | 727 | CODE | |
| LOW | claude_obsidian/transaction.py | 1051 | CODE | |
| LOW | claude_obsidian/transaction.py | 1450 | CODE | |
| LOW | claude_obsidian/transaction.py | 2122 | CODE | |
| LOW | claude_obsidian/transaction.py | 2297 | CODE | |
| LOW | claude_obsidian/transaction.py | 2843 | CODE | |
| LOW | claude_obsidian/transaction.py | 4022 | CODE | |
| LOW | claude_obsidian/transaction.py | 4183 | CODE | |
| LOW | claude_obsidian/transaction.py | 4433 | CODE | |
| LOW | claude_obsidian/transaction.py | 1814 | CODE | |
| LOW | claude_obsidian/package_validation.py | 253 | CODE | |
| LOW | claude_obsidian/package_validation.py | 310 | CODE | |
| LOW | claude_obsidian/capture.py | 585 | CODE | |
| LOW | claude_obsidian/capture.py | 638 | CODE | |
| LOW | claude_obsidian/capture.py | 720 | CODE | |
| LOW | claude_obsidian/capture.py | 821 | CODE | |
| LOW | claude_obsidian/capture.py | 908 | CODE | |
| LOW | claude_obsidian/capture.py | 1496 | CODE | |
| LOW | claude_obsidian/hook_adapter.py | 218 | CODE | |
| LOW | claude_obsidian/ledgers.py | 274 | CODE | |
| LOW | claude_obsidian/ledgers.py | 346 | CODE | |
| LOW | claude_obsidian/ledgers.py | 467 | CODE | |
| LOW | claude_obsidian/ledgers.py | 901 | CODE | |
| LOW | claude_obsidian/contracts.py | 320 | CODE | |
| LOW | claude_obsidian/contracts.py | 620 | CODE | |
| LOW | claude_obsidian/contracts.py | 1203 | CODE | |
| LOW | claude_obsidian/lint_engine.py | 194 | CODE | |
| LOW | claude_obsidian/lint_engine.py | 605 | CODE | |
| 9 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_contracts.py | 4 | CODE | |
| LOW | tests/test_release.py | 4 | CODE | |
| LOW | tests/test_transaction.py | 4 | CODE | |
| LOW | tests/test_legacy_lock.py | 4 | CODE | |
| LOW | tests/test_setup_wrappers.py | 4 | CODE | |
| LOW | tests/test_distribution_vaults.py | 4 | CODE | |
| LOW | tests/test_setup_retrieve.py | 4 | CODE | |
| LOW | tests/test_vault_root_separation.py | 4 | CODE | |
| LOW | tests/test_vault_ops.py | 3 | CODE | |
| LOW | tests/test_setup_multi_agent.py | 4 | CODE | |
| LOW | tests/test_extensions.py | 4 | CODE | |
| LOW | tests/test_windows_compat.py | 15 | CODE | |
| LOW | tests/test_knowledge_contracts.py | 4 | CODE | |
| LOW | tests/test_cli_mode.py | 4 | CODE | |
| LOW | tests/test_lint_engine.py | 4 | CODE | |
| LOW | tests/test_cli_approval.py | 4 | CODE | |
| LOW | tests/test_ledgers.py | 4 | CODE | |
| LOW | tests/test_setup_vault.py | 4 | CODE | |
| LOW | tests/test_hooks.py | 4 | CODE | |
| LOW | tests/test_package_validation.py | 4 | CODE | |
| LOW | tests/test_capture.py | 4 | CODE | |
| LOW | tests/test_paths.py | 4 | CODE | |
| LOW | tests/test_benchmark_tools.py | 4 | CODE | |
| LOW | tests/test_detect_transport.py | 4 | CODE | |
| LOW | tests/test_gates.py | 4 | CODE | |
| LOW | tests/test_checkpoint.py | 3 | CODE | |
| LOW | tests/test_installed_tree_boundary.py | 4 | CODE | |
| LOW | claude_obsidian/release.py | 9 | CODE | |
| LOW | claude_obsidian/checkpoint.py | 3 | CODE | |
| LOW | claude_obsidian/paths.py | 3 | CODE | |
| LOW | claude_obsidian/url_safety.py | 3 | CODE | |
| LOW | claude_obsidian/legacy_lock.py | 10 | CODE | |
| LOW | claude_obsidian/transaction.py | 9 | CODE | |
| LOW | claude_obsidian/__init__.py | 8 | CODE | |
| LOW | claude_obsidian/gates.py | 3 | CODE | |
| LOW | claude_obsidian/package_validation.py | 10 | CODE | |
| LOW | claude_obsidian/extensions.py | 3 | CODE | |
| LOW | claude_obsidian/capture.py | 8 | CODE | |
| LOW | claude_obsidian/vault_ops.py | 3 | CODE | |
| LOW | claude_obsidian/cli.py | 3 | CODE | |
| LOW | claude_obsidian/hook_adapter.py | 3 | CODE | |
| LOW | claude_obsidian/ledgers.py | 3 | CODE | |
| LOW | claude_obsidian/contracts.py | 8 | CODE | |
| LOW | claude_obsidian/lint_engine.py | 23 | CODE | |
| LOW | claude_obsidian/json_utils.py | 3 | CODE | |
| LOW | claude_obsidian/mode_config.py | 3 | CODE | |
| LOW | claude_obsidian/__main__.py | 1 | CODE | |
| LOW | scripts/claude-obsidian.py | 4 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_transaction.py | 1126 | except Exception: | CODE |
| LOW | tests/test_transaction.py | 1819 | except Exception as exc: | CODE |
| LOW | claude_obsidian/transaction.py | 2012 | except Exception: | CODE |
| LOW | claude_obsidian/transaction.py | 4076 | except Exception as exc: # recovery must aggregate every path failure | CODE |
| LOW | claude_obsidian/capture.py | 1631 | except Exception as exc: | CODE |
| LOW | claude_obsidian/ledgers.py | 572 | except Exception as exc: | CODE |
| LOW | claude_obsidian/ledgers.py | 675 | except Exception as exc: | CODE |
| LOW | claude_obsidian/ledgers.py | 730 | except Exception as exc: | CODE |
| LOW | claude_obsidian/ledgers.py | 997 | except Exception as exc: | CODE |
| LOW | claude_obsidian/ledgers.py | 1231 | except Exception as exc: | CODE |
| LOW | claude_obsidian/lint_engine.py | 635 | except Exception as exc: | CODE |
| LOW | claude_obsidian/lint_engine.py | 653 | except Exception as exc: | CODE |
| LOW | claude_obsidian/lint_engine.py | 809 | except Exception as exc: | CODE |
| MEDIUM | claude_obsidian/lint_engine.py | 784 | def _transaction_reader() -> Any: | CODE |
| LOW | scripts/rerank.py | 429 | except Exception as e: | CODE |
| LOW | scripts/rerank.py | 456 | except Exception as e: | CODE |
| LOW | scripts/tiling-check.py | 407 | except Exception as exc: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | scripts/rerank.py | 0 | parse a positive, bounded result count for command-line callers. | STRING |
| HIGH | scripts/retrieve.py | 0 | parse a positive, bounded result count for command-line callers. | STRING |
| HIGH | scripts/bm25-index.py | 0 | parse a positive, bounded result count for command-line callers. | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | bin/setup-vault.sh | 1 | #!/usr/bin/env bash | COMMENT |
| LOW | tests/test_concurrent_write.sh | 1 | #!/usr/bin/env bash | COMMENT |
| LOW | tests/test_wiki_lock.sh | 1 | #!/usr/bin/env bash | COMMENT |
| LOW | scripts/detect-transport.sh | 1 | #!/usr/bin/env bash | COMMENT |
| LOW | scripts/allocate-address.sh | 1 | #!/usr/bin/env bash | COMMENT |
| LOW | scripts/bm25-index.py | 121 | # Small high-frequency-stopword list (English). Conservative — keep recall high. | COMMENT |
| LOW | scripts/bm25-index.py | 161 | EXIT_LOCK = 1 | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | skills/wiki/SKILL.md | 6 | # Wiki orchestration | COMMENT |
| MEDIUM | skills/wiki/references/modes.md | 1 | # Domain-specific scaffold profiles | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | tests/test_contracts.py | 58 | def update_capability(self, **changes: object) -> None: | CODE |
| LOW | claude_obsidian/release.py | 2591 | __all__ = ["audit_artifact", "build_public_artifact"] | CODE |
| LOW | claude_obsidian/url_safety.py | 94 | __all__ = ["URLSafetyIssue", "url_credential_issue"] | CODE |
| LOW | claude_obsidian/capture.py | 2211 | __all__ = [ | CODE |
| LOW | claude_obsidian/mode_config.py | 83 | __all__ = [ | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | tests/test_transaction.py | 296 | '"expected_hashes":{"wiki/A.md":null},' | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | claude_obsidian/release.py | 127 | "your-api-key", | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | bin/setup-vault.sh | 8 | # Usage: | COMMENT |
| LOW | scripts/detect-transport.sh | 8 | # Usage: | COMMENT |
| LOW | scripts/allocate-address.sh | 9 | # Usage: | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | claude_obsidian/release.py | 123 | "placeholder", | CODE |
| LOW | claude_obsidian/release.py | 396 | word in captured for word in ("example", "placeholder", "redacted", "your-") | CODE |