data-olympus 0.4.2__tar.gz → 0.6.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 (94) hide show
  1. {data_olympus-0.4.2 → data_olympus-0.6.0}/.gitignore +1 -0
  2. {data_olympus-0.4.2 → data_olympus-0.6.0}/CHANGELOG.md +155 -1
  3. {data_olympus-0.4.2 → data_olympus-0.6.0}/PKG-INFO +27 -15
  4. {data_olympus-0.4.2 → data_olympus-0.6.0}/README.md +22 -13
  5. {data_olympus-0.4.2 → data_olympus-0.6.0}/SPEC.md +12 -3
  6. {data_olympus-0.4.2 → data_olympus-0.6.0}/benchmarks/README.md +5 -0
  7. {data_olympus-0.4.2 → data_olympus-0.6.0}/pyproject.toml +13 -2
  8. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/cli/main.py +2 -0
  9. data_olympus-0.6.0/src/data_olympus/cli/migrate_cmd.py +105 -0
  10. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/config.py +54 -0
  11. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/health.py +11 -0
  12. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/index.py +78 -8
  13. data_olympus-0.6.0/src/data_olympus/metrics.py +223 -0
  14. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/models.py +11 -0
  15. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/refresh.py +50 -3
  16. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/rest_api.py +36 -1
  17. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/server.py +155 -7
  18. data_olympus-0.6.0/src/data_olympus/status_migrate.py +151 -0
  19. data_olympus-0.6.0/src/data_olympus/tool_discovery.py +42 -0
  20. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/tools_enforce.py +34 -12
  21. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/tools_read.py +6 -0
  22. data_olympus-0.6.0/src/data_olympus/version_check.py +89 -0
  23. {data_olympus-0.4.2 → data_olympus-0.6.0}/LICENSE +0 -0
  24. {data_olympus-0.4.2 → data_olympus-0.6.0}/NOTICE +0 -0
  25. {data_olympus-0.4.2 → data_olympus-0.6.0}/bin/_kb_detect_workspace.sh +0 -0
  26. {data_olympus-0.4.2 → data_olympus-0.6.0}/bin/_kb_enforce.py +0 -0
  27. {data_olympus-0.4.2 → data_olympus-0.6.0}/bin/_kb_fallback.py +0 -0
  28. {data_olympus-0.4.2 → data_olympus-0.6.0}/bin/kb +0 -0
  29. {data_olympus-0.4.2 → data_olympus-0.6.0}/bin/kb-enforce-hook +0 -0
  30. {data_olympus-0.4.2 → data_olympus-0.6.0}/bin/kb-session-recap-hook +0 -0
  31. {data_olympus-0.4.2 → data_olympus-0.6.0}/bin/opencode/data-olympus-gate.ts +0 -0
  32. {data_olympus-0.4.2 → data_olympus-0.6.0}/deploy/k8s/README.md +0 -0
  33. {data_olympus-0.4.2 → data_olympus-0.6.0}/deploy/k8s/read-replica/README.md +0 -0
  34. {data_olympus-0.4.2 → data_olympus-0.6.0}/docs/releases/README.md +0 -0
  35. {data_olympus-0.4.2 → data_olympus-0.6.0}/example-bundle/projects/acme-app/README.md +0 -0
  36. {data_olympus-0.4.2 → data_olympus-0.6.0}/example-bundle/projects/acme-app/components/api/README.md +0 -0
  37. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/__init__.py +0 -0
  38. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/audit_log.py +0 -0
  39. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/audit_trailers.py +0 -0
  40. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/auth.py +0 -0
  41. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/cli/__init__.py +0 -0
  42. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/cli/import_cmd.py +0 -0
  43. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/cli/indexgen.py +0 -0
  44. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/cli/init_cmd.py +0 -0
  45. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/cli/report_cmd.py +0 -0
  46. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/cli/validity_report_cmd.py +0 -0
  47. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/cli/verify_cmd.py +0 -0
  48. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/cooccurrence.py +0 -0
  49. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/dedup.py +0 -0
  50. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/durable.py +0 -0
  51. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/embeddings.py +0 -0
  52. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/enforce_policy.py +0 -0
  53. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/format/__init__.py +0 -0
  54. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/format/document.py +0 -0
  55. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/format/frontmatter.py +0 -0
  56. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/format/lint.py +0 -0
  57. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/format/validate.py +0 -0
  58. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/git_ops.py +0 -0
  59. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/governed_lane.py +0 -0
  60. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/importer/__init__.py +0 -0
  61. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/importer/adr.py +0 -0
  62. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/importer/flat.py +0 -0
  63. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/importer/model.py +0 -0
  64. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/importer/okf.py +0 -0
  65. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/importer/run.py +0 -0
  66. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/importer/stamp.py +0 -0
  67. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/maintenance.py +0 -0
  68. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/markdown_parse.py +0 -0
  69. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/onboarding.py +0 -0
  70. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/onboarding_inflight.py +0 -0
  71. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/onboarding_playbook.py +0 -0
  72. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/pending.py +0 -0
  73. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/principals.py +0 -0
  74. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/prompts.py +0 -0
  75. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/push_queue.py +0 -0
  76. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/query_expansion.py +0 -0
  77. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/rate_limit.py +0 -0
  78. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/report.py +0 -0
  79. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/safe_id.py +0 -0
  80. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/scaffold.py +0 -0
  81. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/search_gate.py +0 -0
  82. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/search_shortcut.py +0 -0
  83. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/session_metrics.py +0 -0
  84. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/setup_wizard.py +0 -0
  85. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/thin_pointer.py +0 -0
  86. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/tools_audit.py +0 -0
  87. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/tools_onboarding.py +0 -0
  88. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/tools_recap.py +0 -0
  89. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/tools_write.py +0 -0
  90. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/trigram.py +0 -0
  91. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/viewer/__init__.py +0 -0
  92. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/viewer/generator.py +0 -0
  93. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/worktrees.py +0 -0
  94. {data_olympus-0.4.2 → data_olympus-0.6.0}/src/data_olympus/write_gate.py +0 -0
@@ -6,6 +6,7 @@ __pycache__/
6
6
  *.egg-info/
7
7
  dist/
8
8
  build/
9
+ /to-delete/
9
10
  # benchmark index artifact (regenerated by benchmarks/generate_artifacts.py)
10
11
  benchmarks/bench.db*
11
12
  # secrets hardening — never commit decrypted secrets or keys
@@ -12,6 +12,158 @@ This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
12
12
 
13
13
  ## [Unreleased]
14
14
 
15
+ ## [0.6.0] - 2026-07-18
16
+
17
+ ### Added
18
+
19
+ * **Added searchable MCP discovery.** `tools/list` now exposes seven core tools
20
+ plus `tool_search` and `call_tool` by default. Operators can set
21
+ `KB_TOOL_DISCOVERY_MODE=all` for the complete native catalog. Hidden tools
22
+ remain directly callable and retain the same authorization checks.
23
+ * **Added executable OKF interoperability checks.** CI verifies both Data
24
+ Olympus consuming the pinned Google Knowledge Orchestration Framework sample
25
+ and the pinned upstream reference consumer reading the Data Olympus example
26
+ bundle. The immutable upstream revision and fixture checksums are recorded in
27
+ the repository.
28
+ * **Added complete release candidates across every public channel.** One exact
29
+ source SHA now produces a PyPI prerelease wheel and sdist, GHCR image, GitHub
30
+ prerelease, and `release-provenance.json`. Stable promotion is an explicit
31
+ human approved dispatch that accepts only the highest complete candidate.
32
+ * **Added deterministic benchmark provenance receipts.** The committed receipt
33
+ records source, corpus and query hashes, dependency lock, environment,
34
+ tokenizer and model identities, exact commands, seeds, result hashes, and
35
+ metric summaries. The documentation drift guard verifies it before checking
36
+ generated benchmark tables.
37
+
38
+ ### Security
39
+
40
+ - **Bumped transitive dependency `mcp` 1.28.0 to 1.28.1** to close
41
+ CVE-2026-59950 / GHSA-vj7q-gjh5-988w (Dependabot #18, high severity).
42
+ The advisory covers the MCP Python SDK WebSocket server transport, which
43
+ data-olympus does not use (Streamable HTTP only); the bump is applied as
44
+ a precaution and to clear the release security gate. No API surface change.
45
+ (KNA-146)
46
+ - **Bumped transitive benchmark dependency `torch` 2.12.1 to 2.13.0** to
47
+ close CVE-2025-3000 / GHSA-rrmf-rvhw-rf47 (Dependabot #19, low severity).
48
+ The affected `torch.jit.script` path is available only through the optional
49
+ `bench` extra and is not used by the production embedding implementation.
50
+ The patched dependency remains compatible with `sentence-transformers`.
51
+
52
+ ### Changed
53
+
54
+ * **Made PyPI the primary installation and onboarding path.** The README and
55
+ quickstart now lead with `uvx` and `uv tool install`. Every packaging workflow
56
+ runs clean wheel and source distribution smoke tests at the expected version.
57
+ They exercise both console entry points, packaged enforcement files, REST
58
+ health, setup doctor, compact discovery, hidden direct calls, and complete
59
+ catalog mode.
60
+ * **Hardened candidate to stable provenance.** Candidate and stable Python
61
+ artifacts are rebuilt from the same exact source, compared with only version
62
+ metadata normalized, and published through Trusted Publishing with no stored
63
+ PyPI credential. Stable OCI tags reuse the verified candidate digest and
64
+ never rebuild the image.
65
+
66
+ - **Updated the supported runtime and development dependency baseline.**
67
+ FastMCP is now locked to 3.4.4 and requires `>=3.4.4,<4`, guaranteeing the
68
+ catalog search transform used by the default MCP tool-discovery mode. Regex
69
+ is updated to 2026.7.10 with the secret-scanning timeout and false-positive
70
+ regressions green. Mypy, types-regex, and Ruff were updated to their current
71
+ Dependabot revisions and pass the strict type and lint gates. (gh #159, #160,
72
+ #161, #162, #163)
73
+
74
+ - **Added Glama related server metadata and maintenance notes.** `glama.json`
75
+ now names adjacent knowledge and memory MCP servers, and `docs/glama.md`
76
+ records the maintainer response and usage seeding steps for the Glama
77
+ maintenance profile. (gh #155 / KNA-145)
78
+
79
+ - **Improved tool definitions for 7 tools (`kb_gate_check`, `kb_onboarding_status`,
80
+ `kb_compliance`, `kb_cleanup_plan`, `kb_get`, `kb_list`, `kb_outline`).** Each
81
+ docstring now includes a "Use when / use X instead when Y" guidance sentence.
82
+ `kb_gate_check` also discloses its audit-log side effect (`readOnlyHint=false`
83
+ is intentional). (gh #154 / KNA-144)
84
+
85
+ - **Improved `kb_record_event` tool definition.** The docstring now discloses
86
+ behavior (durable, non-destructive audit append; requires write capability),
87
+ documents both event_type values (`gate_bypass`, `gate_degraded`) and all
88
+ required parameters, and gives explicit usage guidance on when to call vs.
89
+ when to use `kb_gate_check`, `kb_consult`, `kb_audit`, or `kb_compliance`
90
+ instead. (gh #153 / KNA-143)
91
+
92
+ ### Fixed
93
+
94
+ * **Closed the remaining release verification gaps.** Every PyPI publishing
95
+ path now fails closed and verifies remote file hashes. Candidate provenance
96
+ validates its source, candidate tag, and image digest before publication.
97
+ Stable promotion derives its version from the requested complete candidate
98
+ and verifies that version against the candidate source commit. OKF freshness
99
+ reports only upstream fixture changes rather than unrelated repository commits.
100
+
101
+ * **Corrected exact SHA CI readiness for conditional jobs.** Completed skipped
102
+ jobs are now non-blocking only when they are not required. Missing, pending,
103
+ failed, neutral, or skipped required checks still fail closed. This lets the
104
+ release gate accept a fully green pull request whose publishing workflow
105
+ intentionally skips upload and manual release paths.
106
+
107
+ - **Hardened read tools against present SQLite indexes without tables.**
108
+ `kb_search`, `kb_get`, `kb_list`, `kb_outline`, onboarding status, and
109
+ cleanup planning now degrade to empty results or empty health instead of
110
+ surfacing raw `sqlite3.Error` failures. The Glama Docker sandbox now serves
111
+ the bundled `example-bundle` corpus so catalog introspection starts with a
112
+ populated, safe index. (gh #156 / KNA-142)
113
+
114
+ ## [0.5.0] - 2026-07-12
115
+
116
+ ### Added
117
+
118
+ - **Version-immutability release guard (`scripts/check_version_free.py`).** A
119
+ published version (PyPI, the ghcr `:vX.Y.Z` image tag, or a GitHub
120
+ release/tag) is immutable, so the release process now refuses to republish an
121
+ existing version. The guard runs as the first step of `tag-release.yml`'s
122
+ `decide` job (before the tag is pushed, so a duplicate never leaves an
123
+ orphaned public tag) and in PR CI (to catch a duplicate declared version
124
+ before merge). A legitimate reconcile (local tag `vX.Y.Z` already at HEAD) is
125
+ allowed and skips the registry lookups; a registry outage fails closed. The
126
+ operator can override a stuck registry with `KB_BYPASS_VERSION_CHECK=1`.
127
+ (gh #148 / KNA-67)
128
+ - **First-class reverse-proxy Host allowlist (`KB_PUBLIC_HOSTNAMES`).** New
129
+ config knob mapped onto fastmcp's Host-header allowlist when the HTTP app is
130
+ built, so operators configure data-olympus directly instead of reaching for
131
+ the dependency's `FASTMCP_HTTP_ALLOWED_HOSTS` env var (both are honoured and
132
+ merged). The server now emits a startup WARN when Host protection is on, it
133
+ binds a non-loopback address, and no public hostname is allowed: the exact
134
+ silent-breakage shape (readiness green, every proxied request 421) behind the
135
+ 2026-07-09 kn-dev outage. A regression test boots the app with a configured
136
+ public hostname and asserts the good Host reaches the route while a foreign
137
+ Host is answered 421. (gh #139 / KNA-70)
138
+ - **Prometheus `/metrics` endpoint (optional `metrics` extra).**
139
+ `prometheus-client` is an OPTIONAL dependency; with it installed, `GET
140
+ /metrics` serves the standard exposition format (pending/push queue depths,
141
+ frozen count, push-failure counter, staleness, live sessions, per-tool call
142
+ counters, index-build duration + last-build timestamp). Without the extra the
143
+ route returns `501` and every metric update inside the core background loops
144
+ is a silent no-op, so a standard deployment is unaffected. (gh #69 / KNA-71)
145
+ - **Cached update-available signal.** The server now checks PyPI/GitHub for a
146
+ newer published `data-olympus` version in a background task and surfaces
147
+ `latest_version` / `update_available` in `kb_health` and
148
+ `GET /api/v1/health`. The health request path reads the cache only, and
149
+ compact health includes `latest_version` only when `update_available` is true.
150
+ Air-gapped deployments can set `KB_DISABLE_VERSION_CHECK=on` to make zero
151
+ outbound version-check calls. (gh #146 / KNA-68)
152
+ - **Legacy corpus status migration.** Status-less documents from pre-0.4.0
153
+ corpora now default to `active` in the SQLite index when
154
+ `KB_STATUS_AUTOFILL=on` (the default), preserving in-force retrieval without
155
+ mutating source markdown during index builds. Operators can persist the same
156
+ default explicitly with the idempotent `data-olympus migrate status --apply`
157
+ command. (gh #147 / KNA-69)
158
+
159
+ ### Fixed
160
+
161
+ - **`kb_consult` demoted_writes CTA count.** The maintenance CTA now counts only
162
+ the session's live pending entries and is omitted once none remain, instead of
163
+ reporting stale "N write(s) awaiting operator review" after every demoted entry
164
+ had been resolved (the demoted_writes / pending_actions surface shipped since
165
+ v0.4.0 via #131). (gh #137 / KNA-72)
166
+
15
167
  ## [0.4.2] - 2026-07-11
16
168
 
17
169
  ### Added
@@ -1551,7 +1703,9 @@ This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
1551
1703
  - `docs/adoption.md`: bring-your-own-KB guide (author, lint, index, serve, wire an agent).
1552
1704
  - `docs/comparison.md`: how data-olympus relates to OKF, enterprise catalogs, markdown KB tools, agent-context conventions, RAG, and ADR tooling.
1553
1705
 
1554
- [Unreleased]: https://github.com/knaisoma/data-olympus/compare/v0.4.1...HEAD
1706
+ [Unreleased]: https://github.com/knaisoma/data-olympus/compare/v0.6.0...HEAD
1707
+ [0.6.0]: https://github.com/knaisoma/data-olympus/compare/v0.5.0...v0.6.0
1708
+ [0.5.0]: https://github.com/knaisoma/data-olympus/compare/v0.4.2...v0.5.0
1555
1709
  [0.4.1]: https://github.com/knaisoma/data-olympus/compare/v0.4.0...v0.4.1
1556
1710
  [0.4.0]: https://github.com/knaisoma/data-olympus/compare/v0.3.5...v0.4.0
1557
1711
  [0.3.5]: https://github.com/knaisoma/data-olympus/compare/v0.3.4...v0.3.5
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: data-olympus
3
- Version: 0.4.2
3
+ Version: 0.6.0
4
4
  Summary: Governance-grade knowledge-base format (OKF-compatible) plus CLI and single-writer MCP server
5
5
  Project-URL: Homepage, https://github.com/knaisoma/data-olympus
6
6
  Project-URL: Repository, https://github.com/knaisoma/data-olympus
@@ -21,7 +21,7 @@ Classifier: Topic :: Software Development :: Documentation
21
21
  Classifier: Topic :: Software Development :: Libraries
22
22
  Classifier: Typing :: Typed
23
23
  Requires-Python: >=3.13
24
- Requires-Dist: fastmcp<4,>=3.2.0
24
+ Requires-Dist: fastmcp<4,>=3.4.4
25
25
  Requires-Dist: pydantic>=2.9
26
26
  Requires-Dist: pyyaml>=6.0
27
27
  Requires-Dist: regex>=2024.5
@@ -33,6 +33,7 @@ Provides-Extra: dev
33
33
  Requires-Dist: fastembed<0.9,>=0.8; extra == 'dev'
34
34
  Requires-Dist: httpx>=0.27; extra == 'dev'
35
35
  Requires-Dist: mypy>=1.13; extra == 'dev'
36
+ Requires-Dist: prometheus-client>=0.20; extra == 'dev'
36
37
  Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
37
38
  Requires-Dist: pytest-cov>=5.0; extra == 'dev'
38
39
  Requires-Dist: pytest>=8.3; extra == 'dev'
@@ -41,6 +42,8 @@ Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
41
42
  Requires-Dist: types-regex>=2024.5; extra == 'dev'
42
43
  Provides-Extra: embeddings
43
44
  Requires-Dist: fastembed<0.9,>=0.8; extra == 'embeddings'
45
+ Provides-Extra: metrics
46
+ Requires-Dist: prometheus-client>=0.20; extra == 'metrics'
44
47
  Description-Content-Type: text/markdown
45
48
 
46
49
  # data-olympus
@@ -52,11 +55,11 @@ problem we kept hitting with coding agents, what data-olympus does differently,
52
55
  it relates to Google's Open Knowledge Format, and where our benchmarks say it is
53
56
  strong and where it is not. The rest of this README is the technical reference.
54
57
 
55
- data-olympus is a governance-grade knowledge-base format and server for agent workforces. It is designed to be readable by [Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog/tree/main/okf) (OKF) consumers: it inherits OKF's directory structure, frontmatter conventions, reserved filenames, and link model, then layers governance extensions on top (stable `id`, controlled `type`/`status`/`tier` fields, `supersedes` chains) plus a single-writer MCP server and a CLI. Formal conformance testing against the OKF reference tooling is not yet in place (tracked in [issue #82](https://github.com/knaisoma/data-olympus/issues/82)). The result is a git-native, version-controlled document graph of engineering standards, architectural decisions, and project knowledge that agents and humans can read, search, and extend without any proprietary service.
58
+ data-olympus is a governance-grade knowledge-base format and server for agent workforces. It is readable by [Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog/tree/main/okf) (OKF) consumers: it inherits OKF's directory structure, frontmatter conventions, reserved filenames, and link model, then layers governance extensions on top (stable `id`, controlled `type`/`status`/`tier` fields, `supersedes` chains) plus a single-writer MCP server and a CLI. CI proves two concrete directions against official Google OKF commit `d44368c15e38e7c92481c5992e4f9b5b421a801d`: its reference visualization consumer reads every concept in `example-bundle`, and data-olympus imports, lints, indexes, searches, and retrieves the pinned official Bitcoin sample. This is fixture-scoped interoperability evidence, not a blanket guarantee for every OKF bundle or future upstream revision. The result is a git-native, version-controlled document graph of engineering standards, architectural decisions, and project knowledge that agents and humans can read, search, and extend without any proprietary service.
56
59
 
57
60
  It governs *decisions*, not code. When an agent is about to make a choice (a library, a pattern, a migration), data-olympus surfaces the established standard or decision that should govern that choice. It is deliberately **not** a code-search, reference-finding, or "where is X used" tool: LSP, grep, and Sourcegraph already do that well. The retrieval task it targets is coding-intent to governing-rule, and it helps where current model interaction during vibe-coding is weakest: keeping the model aligned to patterns the team has already established as correct.
58
61
 
59
- **Status: pre-1.0 beta. Latest release: v0.4.1.**
62
+ **Status: pre-1.0 beta. Stable releases are distributed through PyPI and GHCR.**
60
63
 
61
64
  ## Why
62
65
 
@@ -65,27 +68,36 @@ It governs *decisions*, not code. When an agent is about to make a choice (a lib
65
68
  - **Agent and human readable.** Plain markdown with YAML frontmatter. No SDK required to read or author a document.
66
69
  - **Governed multi-agent writes.** The single-writer MCP pipeline (advisory locks, per-session worktrees, durable push queue) prevents concurrent write races without requiring distributed locking infrastructure.
67
70
  - **Queryable by status, tier, and type.** Filter by `status: accepted`, `tier: T1`, or `type: decision` without post-processing. The `supersedes` chain makes it possible to trace decision history across the graph.
68
- - **Designed to be OKF-readable.** Built on OKF's directory structure, frontmatter conventions, reserved filenames, and link model; formal conformance testing against OKF reference tooling is tracked in [issue #82](https://github.com/knaisoma/data-olympus/issues/82), not yet implemented.
71
+ - **Tested with official OKF tooling.** CI pins an exact Google OKF revision and proves both consumption directions over committed fixtures. The pin, fixture checksum, and Apache 2.0 license provenance live in `tests/okf/reference.json`.
69
72
 
70
73
  ## Quickstart
71
74
 
72
- Requires Python 3.13+ and [`uv`](https://docs.astral.sh/uv/).
75
+ Requires Python 3.13+ and [`uv`](https://docs.astral.sh/uv/). Run the stable CLI
76
+ directly from PyPI:
73
77
 
74
78
  ```bash
75
- # Install
76
- uv venv && uv pip install -e '.[dev]'
79
+ uvx --from data-olympus data-olympus --help
80
+ ```
81
+
82
+ Install it persistently when you are ready to create a bundle and run the
83
+ server:
77
84
 
78
- # Lint the example bundle
79
- uv run data-olympus lint example-bundle
85
+ ```bash
86
+ uv tool install data-olympus
87
+ data-olympus init my-kb
88
+ data-olympus-mcp --help
89
+ ```
80
90
 
81
- # ...or scaffold your own bundle instead of copying example-bundle/
82
- uv run data-olympus init my-kb
91
+ An announced candidate remains opt in through its exact PyPI version:
83
92
 
84
- # Start the MCP server against the example bundle
85
- ./scripts/run-local.sh
93
+ ```bash
94
+ uvx --from 'data-olympus==0.6.0rc3' data-olympus --help
86
95
  ```
87
96
 
88
- See `docs/quickstart.md` for the full local-run walkthrough, including curl and `kb` CLI queries. See `docs/adoption.md` for the full bundle-authoring guide.
97
+ See `docs/quickstart.md` for bundle initialization, server startup, readiness,
98
+ agent registration, and the contributor source installation.
99
+
100
+ See `docs/adoption.md` for the full bundle authoring guide.
89
101
 
90
102
  ## Documentation
91
103
 
@@ -7,11 +7,11 @@ problem we kept hitting with coding agents, what data-olympus does differently,
7
7
  it relates to Google's Open Knowledge Format, and where our benchmarks say it is
8
8
  strong and where it is not. The rest of this README is the technical reference.
9
9
 
10
- data-olympus is a governance-grade knowledge-base format and server for agent workforces. It is designed to be readable by [Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog/tree/main/okf) (OKF) consumers: it inherits OKF's directory structure, frontmatter conventions, reserved filenames, and link model, then layers governance extensions on top (stable `id`, controlled `type`/`status`/`tier` fields, `supersedes` chains) plus a single-writer MCP server and a CLI. Formal conformance testing against the OKF reference tooling is not yet in place (tracked in [issue #82](https://github.com/knaisoma/data-olympus/issues/82)). The result is a git-native, version-controlled document graph of engineering standards, architectural decisions, and project knowledge that agents and humans can read, search, and extend without any proprietary service.
10
+ data-olympus is a governance-grade knowledge-base format and server for agent workforces. It is readable by [Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog/tree/main/okf) (OKF) consumers: it inherits OKF's directory structure, frontmatter conventions, reserved filenames, and link model, then layers governance extensions on top (stable `id`, controlled `type`/`status`/`tier` fields, `supersedes` chains) plus a single-writer MCP server and a CLI. CI proves two concrete directions against official Google OKF commit `d44368c15e38e7c92481c5992e4f9b5b421a801d`: its reference visualization consumer reads every concept in `example-bundle`, and data-olympus imports, lints, indexes, searches, and retrieves the pinned official Bitcoin sample. This is fixture-scoped interoperability evidence, not a blanket guarantee for every OKF bundle or future upstream revision. The result is a git-native, version-controlled document graph of engineering standards, architectural decisions, and project knowledge that agents and humans can read, search, and extend without any proprietary service.
11
11
 
12
12
  It governs *decisions*, not code. When an agent is about to make a choice (a library, a pattern, a migration), data-olympus surfaces the established standard or decision that should govern that choice. It is deliberately **not** a code-search, reference-finding, or "where is X used" tool: LSP, grep, and Sourcegraph already do that well. The retrieval task it targets is coding-intent to governing-rule, and it helps where current model interaction during vibe-coding is weakest: keeping the model aligned to patterns the team has already established as correct.
13
13
 
14
- **Status: pre-1.0 beta. Latest release: v0.4.1.**
14
+ **Status: pre-1.0 beta. Stable releases are distributed through PyPI and GHCR.**
15
15
 
16
16
  ## Why
17
17
 
@@ -20,27 +20,36 @@ It governs *decisions*, not code. When an agent is about to make a choice (a lib
20
20
  - **Agent and human readable.** Plain markdown with YAML frontmatter. No SDK required to read or author a document.
21
21
  - **Governed multi-agent writes.** The single-writer MCP pipeline (advisory locks, per-session worktrees, durable push queue) prevents concurrent write races without requiring distributed locking infrastructure.
22
22
  - **Queryable by status, tier, and type.** Filter by `status: accepted`, `tier: T1`, or `type: decision` without post-processing. The `supersedes` chain makes it possible to trace decision history across the graph.
23
- - **Designed to be OKF-readable.** Built on OKF's directory structure, frontmatter conventions, reserved filenames, and link model; formal conformance testing against OKF reference tooling is tracked in [issue #82](https://github.com/knaisoma/data-olympus/issues/82), not yet implemented.
23
+ - **Tested with official OKF tooling.** CI pins an exact Google OKF revision and proves both consumption directions over committed fixtures. The pin, fixture checksum, and Apache 2.0 license provenance live in `tests/okf/reference.json`.
24
24
 
25
25
  ## Quickstart
26
26
 
27
- Requires Python 3.13+ and [`uv`](https://docs.astral.sh/uv/).
27
+ Requires Python 3.13+ and [`uv`](https://docs.astral.sh/uv/). Run the stable CLI
28
+ directly from PyPI:
28
29
 
29
30
  ```bash
30
- # Install
31
- uv venv && uv pip install -e '.[dev]'
31
+ uvx --from data-olympus data-olympus --help
32
+ ```
33
+
34
+ Install it persistently when you are ready to create a bundle and run the
35
+ server:
32
36
 
33
- # Lint the example bundle
34
- uv run data-olympus lint example-bundle
37
+ ```bash
38
+ uv tool install data-olympus
39
+ data-olympus init my-kb
40
+ data-olympus-mcp --help
41
+ ```
35
42
 
36
- # ...or scaffold your own bundle instead of copying example-bundle/
37
- uv run data-olympus init my-kb
43
+ An announced candidate remains opt in through its exact PyPI version:
38
44
 
39
- # Start the MCP server against the example bundle
40
- ./scripts/run-local.sh
45
+ ```bash
46
+ uvx --from 'data-olympus==0.6.0rc3' data-olympus --help
41
47
  ```
42
48
 
43
- See `docs/quickstart.md` for the full local-run walkthrough, including curl and `kb` CLI queries. See `docs/adoption.md` for the full bundle-authoring guide.
49
+ See `docs/quickstart.md` for bundle initialization, server startup, readiness,
50
+ agent registration, and the contributor source installation.
51
+
52
+ See `docs/adoption.md` for the full bundle authoring guide.
44
53
 
45
54
  ## Documentation
46
55
 
@@ -10,7 +10,7 @@
10
10
 
11
11
  Knowledge that lives in plain markdown with YAML frontmatter is version-controllable, portable, and readable by both humans and automated agents without any special runtime. A git repository becomes the primary audit trail: every change is a commit, rollback is `git revert`, and the full history ships with the bundle.
12
12
 
13
- This specification is **designed to be readable by consumers of Google's Open Knowledge Format (OKF)**: it inherits OKF's directory structure, frontmatter conventions, reserved filenames, and link model. Formal conformance testing against the OKF reference tooling is not yet in place ([issue #82](https://github.com/knaisoma/data-olympus/issues/82) tracks it); the claim today rests on shared structure by construction, not on an executable check. On top of that baseline we layer **governance extensions**: a stable `id` field decoupled from path, a controlled type vocabulary, explicit `status` and `tier` fields, ADR chain links, and a single-writer MCP server that enforces propose/review/commit safety across multiple concurrent agents.
13
+ This specification is **readable by consumers of Google's Open Knowledge Format (OKF)**: it inherits OKF's directory structure, frontmatter conventions, reserved filenames, and link model. Executable CI checks pin official Google OKF commit `d44368c15e38e7c92481c5992e4f9b5b421a801d`. The pinned reference visualization consumer reads every concept in the data-olympus example bundle, and data-olympus imports, lints, indexes, searches, and retrieves the pinned official sample bundle. This proves those two fixture-scoped interoperability directions; it does not claim that every possible OKF bundle or future upstream revision has been tested. On top of that baseline we layer **governance extensions**: a stable `id` field decoupled from path, a controlled type vocabulary, explicit `status` and `tier` fields, ADR chain links, and a single-writer MCP server that enforces propose/review/commit safety across multiple concurrent agents.
14
14
 
15
15
  The result is a format that is portable and human-readable at rest (plain files, no database required) while supporting structured queries, multi-agent write safety, and progressive disclosure when served through the data-olympus MCP.
16
16
 
@@ -60,7 +60,7 @@ The bundle may be organized into subdirectories of any depth. Subdirectory names
60
60
 
61
61
  ### 4.1 Base layer (inherited from OKF)
62
62
 
63
- The following conventions are inherited from OKF for interoperability. They are designed so an OKF consumer can read a data-olympus bundle; this is not yet backed by an executable conformance test against OKF reference tooling (see section 11 and [issue #82](https://github.com/knaisoma/data-olympus/issues/82)).
63
+ The following conventions are inherited from OKF for interoperability. The exact executable evidence and its limits are described in section 11.
64
64
 
65
65
  - Documents are UTF-8 encoded markdown files.
66
66
  - Structured metadata is expressed as a YAML frontmatter block at the top of the file, opened and closed by a bare `---` line.
@@ -281,6 +281,13 @@ The serving transport MUST be streamable HTTP (not stdio). The MCP endpoint is `
281
281
 
282
282
  **Readiness probes MUST NOT target `/api/v1/health`.** A load balancer or orchestrator readiness check MUST use `GET /readyz` (200 once the process is up and the index is loaded, independent of data staleness). `/api/v1/health` keeps a 503-on-degraded contract for data-freshness alerting; wiring it as a readiness probe would eject a healthy single replica from its Service on a transient git-remote staleness. See [`docs/serving.md`](docs/serving.md).
283
283
 
284
+ **Update-available signal.** A server MAY surface cached `latest_version` and
285
+ `update_available` fields in `kb_health` / `GET /api/v1/health` when a newer
286
+ data-olympus package is published. These are informational serving-layer fields
287
+ only: they MUST NOT affect `degraded` or readiness, and the health request path
288
+ MUST read a cache rather than perform outbound registry calls. Deployments MAY
289
+ disable the check entirely for air-gapped operation.
290
+
284
291
  **Enforcement endpoints.** A server MAY expose an enforcement surface that turns the advisory KB into a gated consultation proxy for code and architectural decisions. The endpoints are:
285
292
 
286
293
  - `POST /api/v1/consult`: record a consultation for a `(source_session, workspace)` pair and return the governing rules for the supplied intent.
@@ -351,11 +358,13 @@ The `spec_version` field is optional in bundles targeting this `0.1` draft. It b
351
358
 
352
359
  **Issue #114 (write-path `status` enforcement) does NOT bump this version.** `status` has been a required field under section 4.2 — and a `kb lint` error when absent — since the `0.1` draft; no prior version of this document ever described it as recommended, so there is no required-field-semantics change to record here. What issue #114 adds is a reference-implementation write-path check (section 8): a NEWLY created document missing `status` is now rejected at commit time, closing a gap where the write path was more permissive than `kb lint`. This does not affect any already-conformant bundle (which by definition already has `status` on every document) and does not change how an existing bundle is read, parsed, or validated — only how a brand-new document is admitted through the write path. Per the minor/major criteria above, that is neither: it is a reference-implementation enforcement-timing change, not a format change, so it is documented here rather than as a version increment. A bundle that is already non-conformant (missing `status` on one or more legacy documents) is unaffected in how it is READ — those documents keep being served, just never as in-force — see the maintenance ledger migration path in [`docs/operations.md`](docs/operations.md).
353
360
 
361
+ **Issue #147 / KNA-69 (legacy status autofill) also does NOT bump this version.** `#147` is a reference-implementation read-side default, not a format change: it does not alter what `status` means, its controlled vocabulary, or the requirement that documents carry it. It changes how the reference implementation treats a legacy document that is missing `status`. Under `#114` such a document was served but never in-force, so a pre-0.4.0 corpus silently lost its in-force guidance on upgrade. Under `#147` the index build treats a missing `status` as `active` by default (`KB_STATUS_AUTOFILL=on`), so the corpus keeps governing exactly as it did before the upgrade. This intentionally reverses the conservative "never guess status" stance `#114` took, and it does so for one deliberate reason: for the narrow legacy-upgrade case, a seamless default that preserves prior in-force behavior is worth more than conservatively flagging every legacy document as not-in-force and blocking it until a manual fix lands. The reversal is bounded and reversible: it applies only to documents with NO `status` (an explicit status is always honored verbatim), never rewrites the markdown source at index time (the build stays a read-only parse; the physical gap is still tracked by the maintenance ledger so the `missing_status` CTA keeps nagging), and is fully disabled by `KB_STATUS_AUTOFILL=off` for a deployment that prefers explicit flagging. Persisting the default into the markdown source is a separate, explicit operator action (`data-olympus migrate status --apply`), never an implicit side effect of indexing. See [`docs/operations.md`](docs/operations.md) section 5.2.
362
+
354
363
  ---
355
364
 
356
365
  ## 11. Relationship to other formats
357
366
 
358
- **OKF (Open Knowledge Format).** data-olympus is designed to be readable by OKF consumers: our governance extensions (`id`, `status`, `tier`, `supersedes`, `superseded_by`, `contradicts`, `owner`, and the write pipeline) are meant to be invisible to OKF consumers because OKF requires tolerating unknown keys. This is a design intent backed by shared structure (directory layout, frontmatter conventions, reserved filenames, link model), not by an executable conformance test against the OKF reference tooling; [issue #82](https://github.com/knaisoma/data-olympus/issues/82) tracks adding one. The two formats are complementary: OKF defines the interoperable baseline; data-olympus adds the governance layer needed for multi-agent write safety and ADR chain tracking. The relationship is analogous to how OpenAPI is a profile of JSON Schema. See [`docs/okf-profile.md`](docs/okf-profile.md) for the full field-by-field profile: which extensions are stable, which are runtime-only serving fields, and which are experimental candidates tracked against open OKF ecosystem discussions.
367
+ **OKF (Open Knowledge Format).** data-olympus is readable by OKF consumers: our governance extensions (`id`, `status`, `tier`, `supersedes`, `superseded_by`, `contradicts`, `owner`, and the write pipeline) are invisible to a permissive OKF consumer because OKF requires tolerating unknown keys. CI pins official Google OKF commit `d44368c15e38e7c92481c5992e4f9b5b421a801d`, verifies the vendored fixture and Apache 2.0 license checksums, runs the pinned reference visualization consumer over every concept in `example-bundle`, and runs the data-olympus importer, linter, index, search, and retrieval path over the pinned official sample. These checks prove the named fixtures and revision only. The two formats are complementary: OKF defines the interoperable baseline; data-olympus adds the governance layer needed for multi-agent write safety and ADR chain tracking. The relationship is analogous to how OpenAPI is a profile of JSON Schema. See [`docs/okf-profile.md`](docs/okf-profile.md) for the full field-by-field profile and the exact evidence boundary.
359
368
 
360
369
  **Obsidian and Notion.** Both support markdown files with YAML frontmatter and backlink graphs. data-olympus bundles can be opened in Obsidian as a vault; the frontmatter is visible in properties panels and the body renders normally. The difference is governance: Obsidian and Notion have no concept of propose/pending/resolve write pipelines, controlled-vocabulary enforcement, or tier-based access control. data-olympus complements these tools rather than replacing them: a team may author in Obsidian and commit conformant bundles to git for the MCP server to serve.
361
370
 
@@ -4,6 +4,11 @@ A reproducible, retrieval-only benchmark that measures token cost and retrieval
4
4
  accuracy of five methods over a synthetic committed corpus, plus a governance
5
5
  ablation and one reproducible run on a real (non-templated) corpus.
6
6
 
7
+ **Maintainer-produced; not independently reproduced.** The committed
8
+ [`results/receipt.json`](results/receipt.json) records exact source, inputs,
9
+ dependencies, commands, seeds, environment, and output hashes for independent
10
+ verification.
11
+
7
12
  ## What it measures
8
13
 
9
14
  For each (method, query) pair the harness records:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "data-olympus"
3
- version = "0.4.2"
3
+ version = "0.6.0"
4
4
  description = "Governance-grade knowledge-base format (OKF-compatible) plus CLI and single-writer MCP server"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13"
@@ -21,7 +21,7 @@ classifiers = [
21
21
  ]
22
22
  dependencies = [
23
23
  "pyyaml>=6.0",
24
- "fastmcp>=3.2.0,<4",
24
+ "fastmcp>=3.4.4,<4",
25
25
  "pydantic>=2.9",
26
26
  # The secret-scanning gate (issue #71) runs operator-supplied
27
27
  # KB_SECRET_SCAN_EXTRA_PATTERNS through the `regex` engine because it
@@ -46,6 +46,14 @@ Changelog = "https://github.com/knaisoma/data-olympus/blob/main/CHANGELOG.md"
46
46
  embeddings = [
47
47
  "fastembed>=0.8,<0.9",
48
48
  ]
49
+ # Optional Prometheus /metrics endpoint (issue #69). NOT a core dependency: the
50
+ # metrics registry is a no-op shim when prometheus-client is absent (its inc/
51
+ # set/observe calls live inside core background loops and tool wrappers, so a
52
+ # bare import must never crash a standard deployment). With the extra installed,
53
+ # /metrics serves the exposition format; without it, /metrics returns 501.
54
+ metrics = [
55
+ "prometheus-client>=0.20",
56
+ ]
49
57
  dev = [
50
58
  "pytest>=8.3",
51
59
  "pytest-asyncio>=0.24",
@@ -59,6 +67,9 @@ dev = [
59
67
  # runtime; the tests opt in via KB_EMBEDDINGS_MODE and skip if the model
60
68
  # cannot be fetched in the sandbox).
61
69
  "fastembed>=0.8,<0.9",
70
+ # Exercise the Prometheus /metrics path in CI (the exposition-format test
71
+ # skips when this is absent; the no-op-shim tests run regardless).
72
+ "prometheus-client>=0.20",
62
73
  ]
63
74
  bench = [
64
75
  "tiktoken>=0.8",
@@ -143,6 +143,8 @@ def build_parser() -> argparse.ArgumentParser:
143
143
  add_init_subparser(sub)
144
144
  from data_olympus.cli.verify_cmd import add_verify_subparser
145
145
  add_verify_subparser(sub)
146
+ from data_olympus.cli.migrate_cmd import add_migrate_subparser
147
+ add_migrate_subparser(sub)
146
148
  return parser
147
149
 
148
150
 
@@ -0,0 +1,105 @@
1
+ """`data-olympus migrate status`: persist the status autofill to disk (#147).
2
+
3
+ The `status` subcommand writes the `status` field into legacy (pre-0.4.0)
4
+ markdown docs that are missing it, using the default `active` (see
5
+ ``data_olympus.status_migrate``). This is the EXPLICIT counterpart to the
6
+ index build's VIRTUAL autofill (KB_STATUS_AUTOFILL): the build never touches
7
+ the markdown source, so an operator runs this once to make the change durable.
8
+
9
+ Without ``--apply`` the command is a DRY RUN: it reports which files would be
10
+ changed and exits 0, changing nothing. ``--apply`` performs the write and (when
11
+ an audit log path is configured) records one audited event per changed file.
12
+ """
13
+ from __future__ import annotations
14
+
15
+ import os
16
+ from pathlib import Path
17
+ from typing import TYPE_CHECKING
18
+
19
+ if TYPE_CHECKING:
20
+ import argparse
21
+
22
+
23
+ def add_migrate_subparser(
24
+ sub: argparse._SubParsersAction[argparse.ArgumentParser],
25
+ ) -> None:
26
+ """Wire the ``migrate`` command (with its ``status`` subcommand) in."""
27
+ p_migrate = sub.add_parser(
28
+ "migrate",
29
+ help="one-off corpus migrations (e.g. persist the status autofill)",
30
+ )
31
+ migrate_sub = p_migrate.add_subparsers(dest="migrate_command", required=True)
32
+ p_status = migrate_sub.add_parser(
33
+ "status",
34
+ help="write a default `status: active` into legacy docs missing it (#147)",
35
+ )
36
+ p_status.add_argument(
37
+ "path", nargs="?", default=".", help="corpus root (default: .)"
38
+ )
39
+ p_status.add_argument(
40
+ "--apply",
41
+ action="store_true",
42
+ help="write the change to disk (default: dry run, reports and changes nothing)",
43
+ )
44
+ p_status.add_argument(
45
+ "--audit-log",
46
+ default=None,
47
+ help="audit-log path for the applied writes (default: $KB_AUDIT_LOG_PATH; "
48
+ "omitted entirely if neither is set)",
49
+ )
50
+ p_status.set_defaults(func=_cmd_migrate_status)
51
+
52
+
53
+ def _cmd_migrate_status(args: argparse.Namespace) -> int:
54
+ import sys
55
+
56
+ from data_olympus.format import discover_bundle_files
57
+ from data_olympus.format.document import Document
58
+ from data_olympus.status_migrate import DEFAULT_STATUS, apply_status_autofill
59
+
60
+ root = Path(args.path)
61
+ if not root.is_dir():
62
+ print(f"error: {root} is not a directory", file=sys.stderr)
63
+ return 2
64
+
65
+ if not args.apply:
66
+ # Dry run: report the files that WOULD be rewritten, change nothing.
67
+ would_change: list[str] = []
68
+ for md in discover_bundle_files(root):
69
+ try:
70
+ doc = Document.load(md)
71
+ except ValueError:
72
+ continue # malformed frontmatter: a lint concern, not migrated
73
+ status = doc.frontmatter.get("status")
74
+ if not (isinstance(status, str) and status.strip()):
75
+ would_change.append(str(md.relative_to(root)))
76
+ for rel in would_change:
77
+ print(f"would set status: {DEFAULT_STATUS} {rel}")
78
+ print(
79
+ f"dry run: {len(would_change)} document(s) would be updated "
80
+ f"(re-run with --apply to write)"
81
+ )
82
+ return 0
83
+
84
+ audit_log = None
85
+ audit_path = args.audit_log or os.environ.get("KB_AUDIT_LOG_PATH")
86
+ if audit_path:
87
+ from data_olympus.audit_log import AuditLog
88
+
89
+ audit_log = AuditLog(
90
+ log_path=audit_path,
91
+ hmac_key=os.environ.get("KB_AUDIT_HMAC_KEY", ""),
92
+ )
93
+
94
+ result = apply_status_autofill(root, audit_log=audit_log)
95
+ for rel in result.changed_paths:
96
+ print(f"set status: {DEFAULT_STATUS} {rel}")
97
+ if result.skipped_malformed:
98
+ for rel in result.skipped_malformed:
99
+ print(f"skipped (malformed frontmatter, fix with `kb lint`): {rel}")
100
+ print(
101
+ f"applied: {result.changed} changed, {result.already_present} already had "
102
+ f"status, {len(result.skipped_malformed)} skipped "
103
+ f"({result.scanned} scanned)"
104
+ )
105
+ return 0