ochakai 0.12.0
Two vocabularies leave ochakai in this release. Types stop being internal slugs translated at every boundary and become the OKF spelling verbatim (design doc 0023, #96). Links stop being a hand-authored field and become what the body actually says (design doc 0024, #100). Both are the same correction: ochakai had invented structure that OKF deliberately left to the document, and paid for it with translation layers that could not round-trip.
Types are the OKF vocabulary (design doc 0023)
The same eight concepts had two names — the internal slug (tables) and the OKF display name (BigQuery Table) — bridged by four mechanisms and converted twice on every read and write. All of it is gone.
| Was | Is |
|---|---|
models |
Semantic Model |
metrics |
Metric |
queries |
Golden Query |
insights |
Insight |
terms |
Glossary Term |
datasets |
BigQuery Dataset |
tables |
BigQuery Table |
references |
Reference |
The original reason for slugs disappeared in 0017: they existed to match the knowledge-catalog reference bundles' directory layout, but paths come from ids alone now and a type never decides a directory name. Worse, the conversion was lossy — slugifyType flattened Data Contract to data-contract, and an okf_type attr existed solely to restore what the flattening destroyed. A mechanism to make round-trips work was cleaning up after a mechanism that broke them.
Import and export are now identity on type. Five mechanisms disappear with the translation: the okfType table, slugifyType, the okf_type attr, displayType/typeFromOKF, and the typeAlias compatibility table. ValidType relaxes to a one-line, slash-free, 128-byte free string, so a foreign bundle's non-ASCII type survives as itself. Matching is case-insensitive at every entry point (--type "bigquery table" works); the spelling you write is the one stored.
Links come from the body (design doc 0024)
Links were a structured field you filled in by hand, independent of the prose. OKF SPEC §5 defines cross-linking as plain markdown links and says the kind of relationship is carried by the surrounding text, not the link. Reading ochakai's own code settled it: nothing branched on Link.Rel — not the context expansion, not the semantic-model traversal (which goes through attrs.model). A typed edge had been introduced, and no machine ever read the type.
The body is the only source of edges. Write [revenue](/metrics/revenue.md) in the prose and the entry links to metrics/revenue. Five forms are read: bundle-absolute (/x.md), relative (./x.md), ochakai:// in a markdown link, autolinks (<ochakai://x>), and bare ochakai://x. External URLs are not entry links, and non-.md file references remain attachments (design doc 0008). Links inside fenced or inline code are examples, not edges, and are skipped.
rel becomes text — the anchor text, not a relationship type. It is optional: a bare ochakai:// reference has none, and then the target's last segment reads as the name, the same fallback titles use (design doc 0022).
The links column survives as a derived index, recomputed on every write, so backlinks and get_context are unchanged — the containment query they run still works exactly as before.
Renaming an entry now repairs the prose. This is a bug fix as much as a feature: Move used to rewrite the links column and attrs.model while leaving the author's markdown links pointing at an id that no longer existed. It now rewrites the body — each notation keeping its own form, code blocks untouched — and re-derives links from the repaired text. Relative targets normalize to bundle-absolute, since where a relative link resolves depends on the referring entry's own location.
Web UI
- The new-entry form takes one id field (#99), the way the address is one string and the way the Move panel already worked. The + on a tree directory seeds the folder and puts the caret past it.
- Breadcrumbs link to each ancestor up to the parent directory (#97, #99), and the detail header's actions are more compact.
- The Links tab is read-only — it shows what the body says, with a note pointing at the body editor. The links textarea is gone.
- Type comparisons left behind by 0023 are fixed (#98).
Breaking changes
typevalues change across API, MCP, and CLI. No aliases:--type tablesdoes not error, it returns zero results, because it is now a valid free type that nothing uses. Clients switching on type need updating.- Types contain spaces. Shell usage needs quoting (
--type "Golden Query"), and REST query parameters need URL encoding. Case-insensitive matching softens this in practice. okf_typeis no longer emitted.linksin a write payload is ignored. Move the relationship into the body as a markdown link. This applies to REST, MCP, and the Web UI alike.Link.relis nowLink.text, and its meaning changes from relationship type to anchor text.- Export no longer writes a
# Linkssection — the links are already in the body, and writing them again would duplicate them on re-import.
Migrations 0014 and 0015
Both applied automatically at startup.
0014 renames the eight stored type values and their revision snapshots. It is small because 0011 removed type from every key and path: link targets, URIs, and ids need no rewriting, primary-key collisions cannot occur, and existing embeddings stay valid (the embedding text never included type). Entries carrying an okf_type attr have that spelling promoted back to type first, so an author's original spelling wins over a slug rename.
0015 writes existing links back into the body before the column becomes a derived value, rendering each as - [<rel>](/<target>.md) — the old rel becoming the anchor text, which is exactly the reading 0024 gives it. Without this step those edges would vanish silently the next time an entry was written. An empty rel falls back to the target's last segment, so nothing renders as an empty [](). Revision snapshots are left alone: history should keep the shape it had, and unlike the ids 0013 rewrote, links are not a key.