zettelforge 2.4.1__tar.gz → 2.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (320) hide show
  1. zettelforge-2.5.0/.github/CODEOWNERS +8 -0
  2. zettelforge-2.5.0/.github/workflows/ci.yml +158 -0
  3. {zettelforge-2.4.1 → zettelforge-2.5.0}/.github/workflows/docs.yml +2 -2
  4. {zettelforge-2.4.1 → zettelforge-2.5.0}/.github/workflows/publish.yml +3 -3
  5. {zettelforge-2.4.1 → zettelforge-2.5.0}/.github/workflows/snyk-security.yml +13 -6
  6. {zettelforge-2.4.1 → zettelforge-2.5.0}/CHANGELOG.md +146 -0
  7. zettelforge-2.5.0/CODEOWNERS +13 -0
  8. {zettelforge-2.4.1 → zettelforge-2.5.0}/CONTRIBUTING.md +8 -2
  9. {zettelforge-2.4.1 → zettelforge-2.5.0}/PKG-INFO +12 -1
  10. zettelforge-2.5.0/SECURITY.md +25 -0
  11. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/locomo_benchmark.py +94 -19
  12. zettelforge-2.5.0/benchmarks/locomo_results.json +287 -0
  13. {zettelforge-2.4.1 → zettelforge-2.5.0}/config.default.yaml +72 -4
  14. zettelforge-2.5.0/docs/how-to/configure-pii.md +217 -0
  15. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/how-to/configure-typedb.md +1 -1
  16. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/how-to/integrate-llm-agent.md +2 -0
  17. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/how-to/upgrade.md +45 -5
  18. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/index.md +32 -10
  19. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/reference/configuration.md +139 -24
  20. zettelforge-2.5.0/docs/rfcs/RFC-009-enrichment-pipeline-v2.md +737 -0
  21. zettelforge-2.5.0/docs/rfcs/RFC-010-enrichment-hotfix.md +115 -0
  22. zettelforge-2.5.0/docs/rfcs/RFC-011-local-llm-backend-config.md +435 -0
  23. zettelforge-2.5.0/docs/rfcs/RFC-012-litellm-unified-provider.md +369 -0
  24. zettelforge-2.5.0/docs/rfcs/RFC-013-presidio-pii-detection.md +517 -0
  25. zettelforge-2.5.0/docs/superpowers/research/2026-04-24-phase-0.5-attribution-prelim.md +123 -0
  26. zettelforge-2.5.0/docs/superpowers/research/2026-04-25-graph-retriever-silence.md +117 -0
  27. zettelforge-2.5.0/docs/superpowers/research/2026-04-25-phase-0.5-attribution.md +230 -0
  28. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/tutorials/01-quickstart.md +12 -2
  29. zettelforge-2.5.0/governance/controls.yaml +117 -0
  30. {zettelforge-2.4.1 → zettelforge-2.5.0}/pyproject.toml +49 -2
  31. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/__init__.py +34 -34
  32. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/alias_resolver.py +3 -4
  33. zettelforge-2.5.0/src/zettelforge/blended_retriever.py +128 -0
  34. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/cache.py +4 -4
  35. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/config.py +74 -13
  36. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/consolidation.py +49 -30
  37. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/demo.py +1 -1
  38. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/detection/base.py +11 -11
  39. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/detection/explainer.py +3 -3
  40. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/entity_indexer.py +118 -56
  41. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/extensions.py +2 -2
  42. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/fact_extractor.py +17 -4
  43. zettelforge-2.5.0/src/zettelforge/governance_validator.py +166 -0
  44. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/graph_retriever.py +7 -8
  45. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/integrations/langchain_retriever.py +5 -5
  46. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/intent_classifier.py +4 -5
  47. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/json_parse.py +1 -2
  48. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/knowledge_graph.py +34 -37
  49. zettelforge-2.5.0/src/zettelforge/lance_maintenance.py +242 -0
  50. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/llm_client.py +40 -17
  51. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/llm_providers/__init__.py +18 -7
  52. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/llm_providers/base.py +2 -2
  53. zettelforge-2.5.0/src/zettelforge/llm_providers/litellm_provider.py +141 -0
  54. zettelforge-2.5.0/src/zettelforge/llm_providers/local_provider.py +332 -0
  55. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/llm_providers/mock_provider.py +3 -3
  56. zettelforge-2.5.0/src/zettelforge/llm_providers/ollama_provider.py +129 -0
  57. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/llm_providers/registry.py +3 -4
  58. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/log.py +25 -4
  59. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/mcp/server.py +2 -3
  60. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/memory_evolver.py +23 -8
  61. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/memory_manager.py +145 -58
  62. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/memory_store.py +80 -24
  63. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/memory_updater.py +5 -6
  64. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/note_constructor.py +6 -6
  65. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/note_schema.py +23 -24
  66. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/observability.py +2 -2
  67. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/ocsf.py +41 -18
  68. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/ontology.py +37 -41
  69. zettelforge-2.5.0/src/zettelforge/pii_validator.py +218 -0
  70. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/retry.py +4 -2
  71. zettelforge-2.5.0/src/zettelforge/scripts/compact_lance.py +309 -0
  72. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/scripts/human_eval_sampler.py +6 -6
  73. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/scripts/telemetry_aggregator.py +17 -17
  74. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/scripts/telemetry_dashboard.py +10 -10
  75. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/sigma/entities.py +8 -8
  76. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/sigma/ingest.py +4 -4
  77. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/sigma/tags.py +2 -3
  78. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/sqlite_backend.py +32 -31
  79. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/storage_backend.py +23 -22
  80. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/synthesis_generator.py +10 -11
  81. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/synthesis_validator.py +3 -4
  82. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/telemetry.py +25 -25
  83. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/vector_memory.py +37 -22
  84. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/vector_retriever.py +89 -35
  85. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/yara/entities.py +9 -9
  86. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/yara/ingest.py +6 -8
  87. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_blended_retriever.py +68 -5
  88. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_consolidation.py +30 -0
  89. zettelforge-2.5.0/tests/test_entity_indexer_races.py +189 -0
  90. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_governance_spec_drift.py +25 -10
  91. zettelforge-2.5.0/tests/test_lance_maintenance.py +280 -0
  92. zettelforge-2.5.0/tests/test_llm_providers.py +725 -0
  93. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_logging_compliance.py +157 -0
  94. zettelforge-2.5.0/tests/test_pii_validator.py +341 -0
  95. zettelforge-2.4.1/.github/CODEOWNERS +0 -4
  96. zettelforge-2.4.1/.github/workflows/ci.yml +0 -118
  97. zettelforge-2.4.1/CODEOWNERS +0 -4
  98. zettelforge-2.4.1/SECURITY.md +0 -157
  99. zettelforge-2.4.1/benchmarks/locomo_results.json +0 -962
  100. zettelforge-2.4.1/governance/controls.yaml +0 -59
  101. zettelforge-2.4.1/src/zettelforge/blended_retriever.py +0 -47
  102. zettelforge-2.4.1/src/zettelforge/governance_validator.py +0 -61
  103. zettelforge-2.4.1/src/zettelforge/llm_providers/local_provider.py +0 -96
  104. zettelforge-2.4.1/src/zettelforge/llm_providers/ollama_provider.py +0 -56
  105. zettelforge-2.4.1/tests/test_llm_providers.py +0 -318
  106. {zettelforge-2.4.1 → zettelforge-2.5.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  107. {zettelforge-2.4.1 → zettelforge-2.5.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  108. {zettelforge-2.4.1 → zettelforge-2.5.0}/.github/SECURITY.md +0 -0
  109. {zettelforge-2.4.1 → zettelforge-2.5.0}/.github/dependabot.yml +0 -0
  110. {zettelforge-2.4.1 → zettelforge-2.5.0}/.github/pull_request_template.md +0 -0
  111. {zettelforge-2.4.1 → zettelforge-2.5.0}/.gitignore +0 -0
  112. {zettelforge-2.4.1 → zettelforge-2.5.0}/ARCHITECTURE.md +0 -0
  113. {zettelforge-2.4.1 → zettelforge-2.5.0}/CODE_OF_CONDUCT.md +0 -0
  114. {zettelforge-2.4.1 → zettelforge-2.5.0}/Dockerfile +0 -0
  115. {zettelforge-2.4.1 → zettelforge-2.5.0}/GOVERNANCE.md +0 -0
  116. {zettelforge-2.4.1 → zettelforge-2.5.0}/LICENSE +0 -0
  117. {zettelforge-2.4.1 → zettelforge-2.5.0}/MANIFEST.in +0 -0
  118. {zettelforge-2.4.1 → zettelforge-2.5.0}/README.md +0 -0
  119. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/BENCHMARK_REPORT.md +0 -0
  120. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/LOCOMO_BENCHMARK_COMPARISON.md +0 -0
  121. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/auto_ralph.py +0 -0
  122. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/benchmark_harness.py +0 -0
  123. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/cti_benchmark_v2.py +0 -0
  124. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/cti_retrieval_benchmark.py +0 -0
  125. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/cti_retrieval_results.json +0 -0
  126. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/cti_v2_results.json +0 -0
  127. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/ctibench_benchmark.py +0 -0
  128. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/ctibench_results.json +0 -0
  129. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/dataset.json +0 -0
  130. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/enterprise-attack.json +0 -0
  131. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/evolve_benchmark.py +0 -0
  132. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/evolve_results.json +0 -0
  133. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/graph_test.py +0 -0
  134. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/locomo_results_v1.3.0_baseline.json +0 -0
  135. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/memoryagentbench.py +0 -0
  136. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/memoryagentbench_results.json +0 -0
  137. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/mempalace_benchmark.py +0 -0
  138. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/mempalace_results.json +0 -0
  139. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/naive_memory.py +0 -0
  140. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/opencti_benchmark.py +0 -0
  141. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/ragas_benchmark.py +0 -0
  142. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/ragas_cti_results.json +0 -0
  143. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/ragas_results.json +0 -0
  144. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/results/benchmark_report.md +0 -0
  145. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/results/ralph_optimization_log.json +0 -0
  146. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/scale_benchmark.py +0 -0
  147. {zettelforge-2.4.1 → zettelforge-2.5.0}/benchmarks/scale_results.json +0 -0
  148. {zettelforge-2.4.1 → zettelforge-2.5.0}/config.example.yaml +0 -0
  149. {zettelforge-2.4.1 → zettelforge-2.5.0}/docker/docker-compose.yml +0 -0
  150. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/.well-known/security.txt +0 -0
  151. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/CNAME +0 -0
  152. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/architecture-diagram.mmd +0 -0
  153. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/archive/PACKAGE_SUMMARY.md +0 -0
  154. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/archive/README.md +0 -0
  155. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/archive/SKILL.md +0 -0
  156. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/ZettelForge_Architecture.mmd +0 -0
  157. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/architecture-overview.mmd +0 -0
  158. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/architecture-read-path.mmd +0 -0
  159. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/architecture-write-path.mmd +0 -0
  160. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/cf-analytics.js +0 -0
  161. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/demo.gif +0 -0
  162. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/favicon-16.png +0 -0
  163. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/favicon-32.png +0 -0
  164. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/favicon-512.png +0 -0
  165. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/favicon-64.png +0 -0
  166. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/favicon-apple-touch.png +0 -0
  167. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/favicon-old.svg +0 -0
  168. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/favicon.svg +0 -0
  169. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/logo.svg +0 -0
  170. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/social-preview.png +0 -0
  171. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/threatrecall-lockup-monogram.svg +0 -0
  172. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/threatrecall-lockup.svg +0 -0
  173. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/threatrecall-logo-flat.svg +0 -0
  174. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/threatrecall-logo-philosophy.md +0 -0
  175. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/threatrecall-logo.png +0 -0
  176. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/threatrecall-mark.png +0 -0
  177. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/zettelforge_architecture-light.svg +0 -0
  178. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/assets/zettelforge_architecture.svg +0 -0
  179. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/brand/brandIdentity.md +0 -0
  180. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/brand/colors_and_type.css +0 -0
  181. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/explanation/architecture.md +0 -0
  182. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/explanation/epistemic-tiers.md +0 -0
  183. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/explanation/stix-in-zettelforge.md +0 -0
  184. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/explanation/two-phase-pipeline.md +0 -0
  185. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/explanation/zettelkasten-philosophy.md +0 -0
  186. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/how-to/configure-lancedb.md +0 -0
  187. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/how-to/configure-opencti.md +0 -0
  188. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/how-to/ingest-news-report.md +0 -0
  189. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/how-to/migrate-jsonl-to-sqlite.md +0 -0
  190. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/how-to/query-apt-tools.md +0 -0
  191. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/how-to/reproduce-benchmarks.md +0 -0
  192. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/how-to/resolve-aliases.md +0 -0
  193. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/how-to/run-temporal-query.md +0 -0
  194. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/how-to/store-threat-actor.md +0 -0
  195. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/how-to/troubleshoot.md +0 -0
  196. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/human-evaluation-rubric.md +0 -0
  197. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/llms.txt +0 -0
  198. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/narrative/2026-04-16-the-memory-problem.md +0 -0
  199. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/overrides/main.html +0 -0
  200. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/reference/architecture-deep-dive.md +0 -0
  201. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/reference/governance-controls.md +0 -0
  202. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/reference/memory-manager-api.md +0 -0
  203. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/reference/module-inventory.md +0 -0
  204. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/reference/retrieval-policies.md +0 -0
  205. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/reference/stix-schema.md +0 -0
  206. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/rfcs/RFC-001-conversational-entity-extractor.md +0 -0
  207. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/rfcs/RFC-002-universal-llm-provider.md +0 -0
  208. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/rfcs/RFC-003-adversarial-review.md +0 -0
  209. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/rfcs/RFC-003-read-path-depth-routing.md +0 -0
  210. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/rfcs/RFC-007-operational-telemetry.md +0 -0
  211. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/stylesheets/brand-tokens.css +0 -0
  212. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/stylesheets/extra.css +0 -0
  213. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/stylesheets/fonts/Neuropol.otf +0 -0
  214. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/superpowers/research/2026-04-09-ctibench-ragas-benchmarks.md +0 -0
  215. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/superpowers/research/2026-04-09-fastembed-local-embeddings.md +0 -0
  216. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/superpowers/research/2026-04-09-hybrid-typedb-lancedb-architecture.md +0 -0
  217. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/superpowers/research/2026-04-09-local-llm-llama-cpp.md +0 -0
  218. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/superpowers/research/2026-04-15-anti-aversion-cleanup.md +0 -0
  219. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/superpowers/research/2026-04-15-causal-graph.md +0 -0
  220. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/superpowers/research/2026-04-15-ctibench-ate-fix.md +0 -0
  221. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/superpowers/research/2026-04-15-format-stability.md +0 -0
  222. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/superpowers/research/2026-04-15-memory-evolution.md +0 -0
  223. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/superpowers/research/2026-04-15-merge-consolidation.md +0 -0
  224. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/superpowers/research/2026-04-15-persistence-semantics.md +0 -0
  225. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/superpowers/research/2026-04-15-sqlite-migration.md +0 -0
  226. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/superpowers/research/2026-04-17-test-suite-audit.md +0 -0
  227. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/superpowers/research/README.md +0 -0
  228. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/superpowers/specs/2026-04-15-p1-features-prd.md +0 -0
  229. {zettelforge-2.4.1 → zettelforge-2.5.0}/docs/tutorials/02-first-cti-report.md +0 -0
  230. {zettelforge-2.4.1 → zettelforge-2.5.0}/examples/athf_bridge.py +0 -0
  231. {zettelforge-2.4.1 → zettelforge-2.5.0}/examples/mcp_claude_code.md +0 -0
  232. {zettelforge-2.4.1 → zettelforge-2.5.0}/examples/quickstart.py +0 -0
  233. {zettelforge-2.4.1 → zettelforge-2.5.0}/mkdocs.yml +0 -0
  234. {zettelforge-2.4.1 → zettelforge-2.5.0}/scripts/migrate_jsonl_to_sqlite.py +0 -0
  235. {zettelforge-2.4.1 → zettelforge-2.5.0}/scripts/rebuild_index.py +0 -0
  236. {zettelforge-2.4.1 → zettelforge-2.5.0}/scripts/record-demo.sh +0 -0
  237. {zettelforge-2.4.1 → zettelforge-2.5.0}/scripts/typedb-setup.sh +0 -0
  238. {zettelforge-2.4.1 → zettelforge-2.5.0}/scripts/zettelforge-rebuild.service +0 -0
  239. {zettelforge-2.4.1 → zettelforge-2.5.0}/scripts/zettelforge-rebuild.timer +0 -0
  240. {zettelforge-2.4.1 → zettelforge-2.5.0}/server.json +0 -0
  241. {zettelforge-2.4.1 → zettelforge-2.5.0}/skills/claude-code-skill.md +0 -0
  242. {zettelforge-2.4.1 → zettelforge-2.5.0}/skills/openclaw-skill.md +0 -0
  243. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/__main__.py +0 -0
  244. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/backend_factory.py +0 -0
  245. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/detection/__init__.py +1 -1
  246. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/detection/consumers.py +0 -0
  247. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/edition.py +0 -0
  248. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/integrations/__init__.py +0 -0
  249. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/mcp/__init__.py +0 -0
  250. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/mcp/__main__.py +0 -0
  251. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/sigma/__init__.py +1 -1
  252. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/sigma/cli.py +0 -0
  253. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/sigma/parser.py +0 -0
  254. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/sigma/schemas/NOTICE.md +0 -0
  255. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/sigma/schemas/__init__.py +0 -0
  256. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/sigma/schemas/sigma-correlation-rules-schema.json +0 -0
  257. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/sigma/schemas/sigma-detection-rule-schema.json +0 -0
  258. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/sigma/schemas/sigma-filters-schema.json +0 -0
  259. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/yara/__init__.py +0 -0
  260. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/yara/cccs_metadata.py +2 -2
  261. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/yara/cli.py +0 -0
  262. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/yara/parser.py +0 -0
  263. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/yara/schemas/CCCS_YARA.yml +0 -0
  264. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/yara/schemas/CCCS_YARA_values.yml +0 -0
  265. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/yara/schemas/NOTICE.md +0 -0
  266. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/yara/schemas/__init__.py +0 -0
  267. {zettelforge-2.4.1 → zettelforge-2.5.0}/src/zettelforge/yara/tags.py +0 -0
  268. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/__init__.py +0 -0
  269. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/benchmark_scale.py +0 -0
  270. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/conftest.py +0 -0
  271. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/fixtures/sigma/cloud_example.yml +0 -0
  272. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/fixtures/sigma/correlation_example.yml +0 -0
  273. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/fixtures/sigma/process_creation_example.yml +0 -0
  274. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/fixtures/sigma/tagged_example.yml +0 -0
  275. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/fixtures/yara/malware_hash.yar +0 -0
  276. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/fixtures/yara/technique_loader.yar +0 -0
  277. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/fixtures/yara/webshell.yar +0 -0
  278. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_basic.py +0 -0
  279. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_causal_extraction.py +0 -0
  280. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_config.py +0 -0
  281. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_conversational_entities.py +0 -0
  282. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_core.py +0 -0
  283. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_cti_integration.py +0 -0
  284. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_detection_explainer.py +0 -0
  285. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_detection_rule_entities.py +0 -0
  286. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_edition.py +0 -0
  287. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_embedding.py +0 -0
  288. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_extensions.py +0 -0
  289. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_fact_extractor.py +0 -0
  290. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_governance.py +0 -0
  291. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_graph_retriever.py +0 -0
  292. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_human_eval_sampler.py +0 -0
  293. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_intent_classifier.py +0 -0
  294. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_json_parse.py +0 -0
  295. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_langchain_retriever.py +0 -0
  296. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_llm_client.py +0 -0
  297. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_mcp_server.py +0 -0
  298. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_memory_evolver.py +0 -0
  299. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_memory_updater.py +0 -0
  300. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_performance.py +0 -0
  301. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_recall_integration.py +0 -0
  302. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_sigma_entities.py +0 -0
  303. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_sigma_ingest.py +0 -0
  304. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_sigma_parser.py +0 -0
  305. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_sqlite_backend.py +0 -0
  306. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_sqlite_integration.py +0 -0
  307. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_storage_backend.py +0 -0
  308. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_telemetry_aggregator.py +0 -0
  309. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_telemetry_collector.py +0 -0
  310. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_telemetry_dashboard.py +0 -0
  311. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_telemetry_integration.py +0 -0
  312. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_temporal_graph.py +0 -0
  313. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_two_phase_e2e.py +0 -0
  314. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_typedb_client.py +0 -0
  315. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_yara_entities.py +0 -0
  316. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_yara_ingest.py +0 -0
  317. {zettelforge-2.4.1 → zettelforge-2.5.0}/tests/test_yara_parser.py +0 -0
  318. {zettelforge-2.4.1 → zettelforge-2.5.0}/web/app.py +0 -0
  319. {zettelforge-2.4.1 → zettelforge-2.5.0}/web/auth.py +0 -0
  320. {zettelforge-2.4.1 → zettelforge-2.5.0}/web/mcp_server.py +0 -0
@@ -0,0 +1,8 @@
1
+ # Default rule: require @rolandpg for all changes
2
+ * @rolandpg
3
+
4
+ # Critical security-sensitive paths
5
+ .github/workflows/ @rolandpg
6
+ .github/ @rolandpg
7
+ pyproject.toml @rolandpg
8
+ setup.py @rolandpg
@@ -0,0 +1,158 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ lint:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
17
+
18
+ - name: Set up Python
19
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
20
+ with:
21
+ python-version: '3.12'
22
+
23
+ - name: Install linting tools
24
+ run: pip install ruff
25
+
26
+ - name: Lint with ruff
27
+ run: ruff check src/zettelforge/
28
+
29
+ - name: Format check with ruff
30
+ run: ruff format --check src/zettelforge/
31
+
32
+ # GOV-009 §"Vulnerability Response": runs on every PR, fails on
33
+ # HIGH/CRITICAL. Token-free complement to Snyk (which gates on
34
+ # SNYK_TOKEN being set as a repo secret). Audit H-5.
35
+ pip-audit:
36
+ runs-on: ubuntu-latest
37
+ steps:
38
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
39
+ - name: Set up Python
40
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
41
+ with:
42
+ python-version: '3.12'
43
+ - name: Install pip-audit
44
+ run: pip install pip-audit
45
+ - name: Audit dependencies (any reported vuln blocks)
46
+ run: |
47
+ pip install -e ".[dev]" || pip install -e "."
48
+ # pip-audit fails non-zero on any reported vuln. Add
49
+ # --ignore-vuln=CVE-... with a citation when the finding is
50
+ # explicitly accepted per GOV-009 §"Vulnerability Response".
51
+ #
52
+ # CVE-2026-3219: vulnerability in `pip` itself (the package
53
+ # manager), not a project dependency. The runner's pip is
54
+ # supplied by GitHub's setup-python image and is not something
55
+ # ZettelForge's pyproject can pin or upgrade. Risk-accepted
56
+ # because the pip vulnerability surface is exposed during
57
+ # install, not at runtime; CI builds in ephemeral runners with
58
+ # no persistent state. Re-evaluate when GitHub's images ship a
59
+ # patched pip.
60
+ pip-audit --strict --vulnerability-service=osv \
61
+ --ignore-vuln=CVE-2026-3219
62
+
63
+ test:
64
+ runs-on: ubuntu-latest
65
+ needs: lint
66
+ strategy:
67
+ fail-fast: false
68
+ matrix:
69
+ python-version: ['3.12', '3.13']
70
+
71
+ steps:
72
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
73
+
74
+ - name: Set up Python ${{ matrix.python-version }}
75
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
76
+ with:
77
+ python-version: ${{ matrix.python-version }}
78
+
79
+ - name: Install dependencies
80
+ run: |
81
+ python -m pip install --upgrade pip
82
+ # If [dev] install fails, fall back to bare install + manually
83
+ # add the pytest deps. Parenthesizing the fallback prevents shell
84
+ # precedence from running the "pytest pytest-cov pytest-asyncio"
85
+ # step when [dev] already succeeded (audit L-4).
86
+ pip install -e ".[dev]" || (pip install -e "." && pip install pytest pytest-cov pytest-asyncio)
87
+
88
+ - name: Pre-download fastembed model
89
+ run: |
90
+ python -c "from fastembed import TextEmbedding; TextEmbedding('nomic-ai/nomic-embed-text-v1.5-Q')"
91
+
92
+ - name: Test with pytest
93
+ env:
94
+ ZETTELFORGE_BACKEND: sqlite
95
+ ZETTELFORGE_EMBEDDING_PROVIDER: fastembed
96
+ run: |
97
+ # GOV-007 §"Coverage Requirements" mandates ≥80% line / ≥70% branch.
98
+ # We start the ratchet at 67 (matches governance/controls.yaml's
99
+ # current declaration) so today's pipeline does not break, and #51
100
+ # tracks raising it toward 80% across v2.5.x. Audit finding H-2.
101
+ pytest tests/ -v --cov=zettelforge --cov-report=xml --cov-report=term-missing --cov-fail-under=67
102
+
103
+ - name: Upload coverage
104
+ if: matrix.python-version == '3.12'
105
+ uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2
106
+ with:
107
+ file: ./coverage.xml
108
+ fail_ci_if_error: false
109
+
110
+ governance:
111
+ runs-on: ubuntu-latest
112
+ needs: lint
113
+ steps:
114
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
115
+
116
+ - name: Set up Python
117
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
118
+ with:
119
+ python-version: '3.12'
120
+
121
+ - name: Install dependencies
122
+ run: |
123
+ python -m pip install --upgrade pip
124
+ # See "Install dependencies" comment above (audit L-4).
125
+ pip install -e ".[dev]" || (pip install -e "." && pip install pytest pytest-cov)
126
+
127
+ - name: GOV-012 — Logging compliance tests
128
+ env:
129
+ ZETTELFORGE_BACKEND: sqlite
130
+ run: |
131
+ pytest tests/test_logging_compliance.py -v
132
+
133
+ - name: Governance spec-drift check
134
+ run: |
135
+ pytest tests/test_governance_spec_drift.py -v
136
+
137
+ build:
138
+ runs-on: ubuntu-latest
139
+ needs: [test, governance]
140
+
141
+ steps:
142
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
143
+
144
+ - name: Set up Python
145
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
146
+ with:
147
+ python-version: '3.12'
148
+
149
+ - name: Install build dependencies
150
+ run: |
151
+ python -m pip install --upgrade pip
152
+ pip install build twine
153
+
154
+ - name: Build package
155
+ run: python -m build
156
+
157
+ - name: Check package
158
+ run: twine check dist/*
@@ -14,8 +14,8 @@ jobs:
14
14
  deploy:
15
15
  runs-on: ubuntu-latest
16
16
  steps:
17
- - uses: actions/checkout@v6
18
- - uses: actions/setup-python@v6
17
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
18
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
19
19
  with:
20
20
  python-version: '3.12'
21
21
  - run: pip install mkdocs-material
@@ -11,10 +11,10 @@ jobs:
11
11
  id-token: write # trusted publishing
12
12
 
13
13
  steps:
14
- - uses: actions/checkout@v6
14
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
15
15
 
16
16
  - name: Set up Python
17
- uses: actions/setup-python@v6
17
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
18
18
  with:
19
19
  python-version: '3.12'
20
20
 
@@ -25,4 +25,4 @@ jobs:
25
25
  run: python -m build
26
26
 
27
27
  - name: Publish to PyPI
28
- uses: pypa/gh-action-pypi-publish@release/v1
28
+ uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b
@@ -17,10 +17,10 @@ jobs:
17
17
  actions: read
18
18
  runs-on: ubuntu-latest
19
19
  steps:
20
- - uses: actions/checkout@v6
20
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
21
21
 
22
22
  - name: Set up Python
23
- uses: actions/setup-python@v6
23
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
24
24
  with:
25
25
  python-version: '3.12'
26
26
 
@@ -30,7 +30,7 @@ jobs:
30
30
  pip install -e ".[dev]" || pip install -e "."
31
31
 
32
32
  - name: Set up Snyk CLI
33
- uses: snyk/actions/setup@master
33
+ uses: snyk/actions/setup@9adf32b1121593767fc3c057af55b55db032dc04
34
34
  env:
35
35
  SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
36
36
 
@@ -44,21 +44,28 @@ jobs:
44
44
  echo "has_token=true" >> "$GITHUB_OUTPUT"
45
45
  fi
46
46
 
47
+ # GOV-009 §"Vulnerability Response" + GOV-011 §"Testing Phase":
48
+ # HIGH/CRITICAL Snyk findings must fail the gate. Audit H-5 found
49
+ # both Snyk steps suffixed with `|| true`, so real findings shipped
50
+ # silently. Now: --severity-threshold=high so MEDIUM stays advisory
51
+ # and only HIGH/CRITICAL break the build. SARIF is still emitted via
52
+ # --sarif-file-output even when the test fails (snyk-code) so the
53
+ # subsequent Upload SARIF step has artifacts to publish.
47
54
  - name: Snyk Code test (SAST)
48
55
  if: steps.check_token.outputs.has_token == 'true'
49
- run: snyk code test --sarif > snyk-code.sarif || true
56
+ run: snyk code test --sarif-file-output=snyk-code.sarif --severity-threshold=high
50
57
  env:
51
58
  SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
52
59
 
53
60
  - name: Snyk Open Source test (SCA)
54
61
  if: steps.check_token.outputs.has_token == 'true'
55
- run: snyk test --all-projects || true
62
+ run: snyk test --all-projects --severity-threshold=high
56
63
  env:
57
64
  SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
58
65
 
59
66
  - name: Upload SARIF to GitHub
60
67
  if: steps.check_token.outputs.has_token == 'true'
61
- uses: github/codeql-action/upload-sarif@v4
68
+ uses: github/codeql-action/upload-sarif@b25d0ebf40e5b63ee81e1bd6e5d2a12b7c2aeb61
62
69
  with:
63
70
  sarif_file: snyk-code.sarif
64
71
  continue-on-error: true
@@ -6,6 +6,152 @@ Versioning follows [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.5.0] - 2026-04-25
10
+
11
+ Compliance-driven minor release. Closes every CRITICAL and HIGH audit
12
+ finding except H-3 (mypy strict) and the ANN slice of H-1, both of
13
+ which need per-module ratchet plans. Also adds two new optional LLM
14
+ backends, a Presidio PII detector, and supply-chain hardening.
15
+
16
+ ### Added
17
+
18
+ - **RFC-011 — Local LLM backend selection** (#104). New `local_backend`
19
+ config knob picks between `llama-cpp-python` (GGUF) and
20
+ `onnxruntime-genai` (ONNX) at runtime. Both ship as optional extras
21
+ (`pip install zettelforge[local]` or `[local-onnx]`).
22
+ - **RFC-012 — LiteLLM unified provider** (#108). Routes to 100+
23
+ upstream LLM providers via the LiteLLM SDK. Optional extra
24
+ (`pip install zettelforge[litellm]`); the base package never imports
25
+ it unless the SDK is present.
26
+ - **RFC-013 — Microsoft Presidio PII detection** (#118). Optional PII
27
+ validator with three policies (`log` / `redact` / `block`),
28
+ configurable via `governance.pii.*`. CTI allowlist excludes
29
+ `IP_ADDRESS` / `URL` / `DOMAIN_NAME` from detection so legitimate
30
+ threat-intel indicators flow through unmodified. Soft dependency —
31
+ `pip install zettelforge[pii]` to activate; the base package never
32
+ imports `presidio_analyzer` unless the SDK is present.
33
+ - **GOV-009 Snyk SCA + SAST declared in `controls.yaml`** (#114). The
34
+ spec-drift validator now walks every `.github/workflows/*.yml` so
35
+ controls whose CI step lives outside `ci.yml` (Snyk's separate
36
+ workflow) can be honestly declared.
37
+ - **GOV-006 solo-maintainer compensating controls** (#117). New
38
+ `controls.yaml` entry pins the existing CI gates (lint, tests,
39
+ governance spec-drift) as compensating controls for the GOV-006
40
+ two-person review rule that cannot be physically satisfied with one
41
+ human maintainer. CODEOWNERS updated with explanatory comment.
42
+ - **`SECURITY.md` + CODEOWNERS** added to the repo root for vulnerability
43
+ disclosure and review attribution.
44
+
45
+ ### Changed
46
+
47
+ - **All GitHub Actions are now SHA-pinned** (audit H-5 hardening). Every
48
+ `uses: org/repo@vX` reference replaced with `uses: org/repo@<full-sha> # vX.Y.Z`
49
+ to prevent supply-chain attacks via tag rewrites.
50
+ - **Ruff rule set ratcheted to GOV-003 §"Tooling and Automation" minus
51
+ ANN** (#106 + #107 + #109 + #111 + #113). Active `select` list:
52
+ `{E, F, I, W, N, T20, B, UP, SIM, RUF, S}`. Per-line `# noqa: SXXX`
53
+ annotations document each accepted exception (best-effort fallbacks,
54
+ non-crypto RNG, `?`-bound SQL with constant column lists).
55
+ `RUF002`/`RUF003` ignored globally for stylistic en-dash and ×.
56
+ - **CI install-step shell precedence fixed** (#112). The
57
+ `pip install -e ".[dev]" || pip install -e "." && pip install pytest...`
58
+ chain parsed as `(A || B) && C`, so the pytest install ran on
59
+ every success path including when `[dev]` already provided pytest.
60
+ Wrapped the fallback in parentheses.
61
+ - **CONTRIBUTING.md accuracy** (#115). Documents `ruff format`
62
+ (project hasn't used black for a while) and lists what CI actually
63
+ enforces so new contributors have a green-build target.
64
+
65
+ ### Compliance audit closure (`tasks/compliance-audit-2026-04-25.md`)
66
+
67
+ | Severity | Finding | Status |
68
+ |---|---|---|
69
+ | CRITICAL | C-1 branch protection | CLOSED (with required status checks) |
70
+ | CRITICAL | C-2 fabricated `no_hardcoded_secrets` claim | CLOSED (#100) |
71
+ | HIGH | H-1 ruff full select per GOV-003 | CLOSED for {E,F,I,W,N,T20,B,UP,SIM,RUF,S}; ANN ratcheting per-module |
72
+ | HIGH | H-2 coverage threshold not enforced | CLOSED (#100) |
73
+ | HIGH | H-4 GOV-006 / CODEOWNERS solo-maintainer | CLOSED on the zettelforge side (#117); GOV-006 doc amendment in `rolandpg/governance` repo is separate scope |
74
+ | HIGH | H-5 SCA gate + SHA-pinned actions | CLOSED (#102 + #114 + SHA-pin commit) |
75
+ | MEDIUM | M-1 bare `except:` in production | CLOSED (#100) |
76
+ | MEDIUM | M-3 OCSF `timezone_offset` field | CLOSED (#100) |
77
+ | LOW | L-4 CI install-step shell precedence | CLOSED (#112) |
78
+
79
+ Outstanding: H-3 (mypy --strict in CI; needs per-module ratchet plan
80
+ for 393 errors across 38 files), M-2 (rewrite GOV-016 to match the
81
+ YAML-frontmatter practice already in use), M-4 (lock file), H-1 ANN
82
+ ratchet (121 findings across 38 files).
83
+
84
+ ## [2.4.3] - 2026-04-25
85
+
86
+ Patch release. Three small but consequential fixes that landed during the post-v2.4.2 Vigil live-test session, plus the standalone `compact_lance` maintenance script and Nexus's Tier 0/1/2 LLM observability instrumentation.
87
+
88
+ ### Added
89
+
90
+ - **OCSF `metadata.product.version` self-correct** (#96). `ocsf.py:_resolve_product_version()` now prefers the source `pyproject.toml` reachable from `__file__` and falls back to `importlib.metadata.version("zettelforge")`. Editable installs — where `git checkout vX.Y.Z` updates the source tree but not the installed-metadata record — no longer emit stale version strings. Observed live on Vigil 2026-04-24: v2.4.2 source was emitting `product.version=2.4.1` events because the editable-install metadata hadn't been refreshed.
91
+ - **`ZETTELFORGE_LOG_LEVEL` env var honored** (#96). `log.py:get_logger()` now resolves the log level via env var → `config.yaml log.level` → INFO default. Operators can flip DEBUG without editing code or restarting agent boot order. Resolves the "config.yaml `log.level=DEBUG` was dead code" trap hit on Vigil 2026-04-24, where the auto-configure hardcoded INFO and locked `_configured=True` before any caller could read config.
92
+ - **Fastembed preload** (#96). New `vector_memory.preload_embedding_model()` invoked from `MemoryManager.__init__`. Moves the ~800 ms fastembed model-load cost off the first `remember()` and onto agent startup. Best-effort, no-op when `provider != fastembed`. Phase 0.5 measurement: cold `construct=799ms` vs warm `construct=37ms`.
93
+ - **`compact_lance` maintenance script** (#94). New `python -m zettelforge.scripts.compact_lance` for offline LanceDB shard maintenance. Discovers all `<name>.lance/` tables under `<data-dir>/vectordb/`, supports `--dry-run` / `--table` / `--all` / `--mode {compact,optimize}` / `--force`, emits a per-table JSON report with before/after fragment count, on-disk bytes, row count, and elapsed seconds. Operationalized the Phase 0.5 cleanup intervention (see "Vigil incident response" below).
94
+ - **Tier 0/1/2 LLM observability** (#95, Nexus). `ollama_provider.py` now logs every LLM call (model, prompt_chars, response_chars, response_preview, prompt_preview, duration_ms, eval_count, prompt_eval_count, done_reason). `memory_evolver.py` retries log prompt and raw response previews instead of just `neighbor_id`. `fact_extractor.py` empty completions now emit `parse_failed{schema="fact_extraction", reason="empty_completion"}` (`fact_extractor.py:69-71`) instead of silently returning `[]`. `entity_indexer.py` LLM extractions log prompt previews. `structlog.contextvars`-based `trace_id` propagates through `remember()` so every event in a single note's pipeline shares one correlation key.
95
+
96
+ ### Operational notes
97
+
98
+ The 2026-04-24/25 Vigil live-test session — driven by the v2.4.2 Phase 0.5 instrumentation — found and fixed a 5.66 GB LanceDB version-history bloat on Vigil's `notes_cti` shard. `cleanup_old_versions()` shrank it 5.69 GB → 29 MB and collapsed `remember()` p95 from 49.8 s → ~250 ms. Full evidence in `docs/superpowers/research/2026-04-25-phase-0.5-attribution.md`. The periodic-cleanup feature itself ships in v2.5.0 as RFC-009 Phase 1.5; the v2.4.3 `compact_lance` script supports the one-shot operator workflow until then.
99
+
100
+ ## [2.4.2] - 2026-04-24
101
+
102
+ Patch release bundling the RFC-010 enrichment-pipeline hotfix with the
103
+ RFC-009 Phase 0.5 latency-attribution instrumentation. Response to the
104
+ 2026-04-24 Vigil telemetry audit.
105
+
106
+ ### Fixed
107
+
108
+ - **RFC-010 hotfix — `OllamaProvider` timeout plumbing** (#88). The
109
+ constructor's `**_: Any` absorbed the configured `timeout` kwarg, so
110
+ `ollama.Client(host=...)` was built with no timeout and `remember()`
111
+ could hang up to 66.5s on a slow backend. `timeout` is now a
112
+ first-class parameter (default 60.0s) threaded through to the client.
113
+ - **RFC-010 hotfix — consolidation shutdown race** (#88). A third
114
+ `iterate_notes()` site at `consolidation.py:224` was not covered by
115
+ PR #84's two-site guard. Added a two-layer defense: fast-path
116
+ `_accepting` pre-check plus a narrow `BackendClosedError` catch on
117
+ the iterator itself. Clean skip instead of `consolidation_failed`
118
+ log noise during `atexit`.
119
+
120
+ ### Added
121
+
122
+ - **RFC-009 Phase 0.5 — per-phase timers in `remember()`** (#90).
123
+ `memory_manager.remember()` now wraps each direct-store phase
124
+ (`construct`, `write_note`, `lance_index`, `entity_index`,
125
+ `consolidation_observe`, `supersession`, `kg_update`,
126
+ `enrichment_dispatch`) in `time.perf_counter()` and emits the
127
+ breakdown inside the existing `ocsf_api_activity` event as
128
+ `phase_timings_ms`. Pure observability. Enables Vigil-side latency
129
+ attribution without host-side profilers, which do not apply to a
130
+ library-per-turn deployment. `enrichment_dispatch` is intentionally
131
+ skipped in `sync=True` runs so inline LLM work cannot corrupt the
132
+ dispatch bucket.
133
+ - **Phase 0.5 preliminary attribution artifact** (#91) —
134
+ `docs/superpowers/research/2026-04-24-phase-0.5-attribution-prelim.md`.
135
+ Analyses 961 real `remember()` calls from Vigil's v2.4.1 OCSF log
136
+ and finds **98.4% of `remember()` wall-clock is one LanceDB `Update`
137
+ on the `notes_cti` shard**, which has 7,356 uncompacted fragments
138
+ versus 458 on the healthy `notes_general` shard. Reshapes RFC-009's
139
+ Phase 1–6 priority ordering: those phases target the LLM / queue /
140
+ consolidation paths, which are not what drives the 5.7s average.
141
+ To be refined or falsified with `phase_timings_ms` data from this
142
+ release.
143
+
144
+ ### Does NOT address
145
+
146
+ - The ~2,329 enrichment-job drops/day are still present. Those are
147
+ caused by HTTP 200 + empty Ollama responses (Ollama returns
148
+ successfully but with no parseable body), not by hangs — RFC-010's
149
+ timeout fix does not touch them. The durable outbox + circuit
150
+ breaker in RFC-009 Phases 1–3 (v2.5.0) is the real fix.
151
+ - LanceDB fragment accumulation on `notes_cti` is identified here but
152
+ not fixed here. RFC-009 is being revised to add periodic compaction
153
+ to Phase 1 scope.
154
+
9
155
  ## [2.4.1] - 2026-04-24
10
156
 
11
157
  Operational telemetry (RFC-007), TypeDB authentication hardening, and a
@@ -0,0 +1,13 @@
1
+ # ZettelForge Code Owners
2
+ # These users are automatically requested for review on PRs.
3
+ #
4
+ # Solo-maintainer mode (see governance/controls.yaml GOV-006): the
5
+ # project currently has one human maintainer, so the GOV-006 §"Approval
6
+ # Requirements" two-person rule cannot be physically satisfied. Until a
7
+ # second maintainer is added, the compensating controls declared under
8
+ # GOV-006 in controls.yaml (CI-green required, lint, governance
9
+ # spec-drift, plus GOV-009 SCA/SAST gates) substitute for a second set
10
+ # of human eyes. The audit trail of compensating controls is recoverable
11
+ # from CI logs and branch-protection settings.
12
+
13
+ * @rolandpg
@@ -18,10 +18,16 @@ No external services (Ollama, TypeDB, Docker) are required for development. Zett
18
18
  2. Make your changes
19
19
  3. Run tests: `pytest tests/ -v`
20
20
  4. Run linting: `ruff check src/zettelforge/`
21
- 5. Run formatting: `black src/zettelforge/`
22
- 6. Commit with clear messages
21
+ 5. Run formatting: `ruff format src/zettelforge/`
22
+ 6. Commit with a Conventional Commits message (see "Commit Messages" below)
23
23
  7. Push and create a pull request
24
24
 
25
+ CI enforces the same `ruff check` and `ruff format --check` invocations
26
+ plus `pytest --cov-fail-under=67`, `pip-audit`, governance spec-drift,
27
+ and Snyk SCA/SAST. The full active rule set is `{E, F, I, W, N, T20,
28
+ B, UP, SIM, RUF, S}` per GOV-003 §"Tooling and Automation"; only ANN
29
+ remains and is being ratcheted per-module.
30
+
25
31
  ## Where to contribute
26
32
 
27
33
  All of `src/zettelforge/` is MIT-licensed and open to contributions.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zettelforge
3
- Version: 2.4.1
3
+ Version: 2.5.0
4
4
  Summary: ZettelForge: Agentic Memory System with vector search, knowledge graph, and synthesis
5
5
  Project-URL: Homepage, https://github.com/rolandpg/zettelforge
6
6
  Project-URL: Documentation, https://docs.threatrecall.ai
@@ -46,8 +46,19 @@ Provides-Extra: extensions
46
46
  Requires-Dist: zettelforge-enterprise>=2.1.0; extra == 'extensions'
47
47
  Provides-Extra: langchain
48
48
  Requires-Dist: langchain-core>=0.2.0; extra == 'langchain'
49
+ Provides-Extra: litellm
50
+ Requires-Dist: litellm>=1.60.0; extra == 'litellm'
49
51
  Provides-Extra: local
50
52
  Requires-Dist: llama-cpp-python>=0.3.0; extra == 'local'
53
+ Provides-Extra: local-all
54
+ Requires-Dist: llama-cpp-python>=0.3.0; extra == 'local-all'
55
+ Requires-Dist: onnxruntime-genai>=0.4.0; extra == 'local-all'
56
+ Provides-Extra: local-onnx
57
+ Requires-Dist: onnxruntime-genai>=0.4.0; extra == 'local-onnx'
58
+ Provides-Extra: pii
59
+ Requires-Dist: presidio-analyzer>=2.2.0; extra == 'pii'
60
+ Requires-Dist: presidio-anonymizer>=2.2.0; extra == 'pii'
61
+ Requires-Dist: spacy>=3.5.0; extra == 'pii'
51
62
  Provides-Extra: web
52
63
  Requires-Dist: fastapi>=0.100.0; extra == 'web'
53
64
  Requires-Dist: uvicorn>=0.20.0; extra == 'web'
@@ -0,0 +1,25 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a Vulnerability
4
+
5
+ This is a solo-maintainer project. For security-related issues:
6
+ - Open a GitHub Security Advisory in the repository
7
+ - Tag with `security` label
8
+ - Expect acknowledgement within 48 hours
9
+
10
+ ## Supported Versions
11
+
12
+ | Version | Supported |
13
+ |---------|-----------|
14
+ | latest release | ✅ |
15
+ | master branch | ✅ (CI gates) |
16
+ | older releases | ❌ |
17
+
18
+ ## Supply Chain Security
19
+
20
+ This project implements:
21
+ - SHA-pinned GitHub Actions (all third-party actions pinned by commit SHA)
22
+ - PyPI trusted publishing (OIDC, no long-lived tokens)
23
+ - pip-audit on every CI run (HIGH/CRITICAL must pass)
24
+ - Dependabot for weekly dependency updates
25
+ - Snyk SAST scanning on every push/PR