Two version numbers exist in this project and are easy to confuse: kb_schema_version (the content contract, in wiki/index.md) and VERSION (the tooling layer). Until now neither had a written history, and the page schema was documented in four places at three levels of detail. CHANGELOG.md / CHANGELOG.pl.md consolidate both: the current schema in full (frontmatter for all pages and for decisions, the three reserved body sections, the closed edge vocabulary with a "since" column, the reserved scaffold), then the schema history 1.1-1.5 and the template history 1.0.0-1.8.0. The history is reconstructed from git rather than from memory, so it records what actually happened rather than a tidied version of it: - There was never a schema 1.0; versioning began at 1.1 on 2026-07-13. - Template 1.4.0 and 1.5.0 were never published — VERSION jumped from 1.3.0 to 1.6.0 on 2026-09-01. - Connector-backed libs shipped as tooling in 1.1.0, but the schema only recorded them at 1.2 nine days later. The schema column shows what was in effect after each release, with a footnote on the lag. Registered with ckb-init (copied verbatim into a new KB) and ckb-upgrade (taken wholesale from upstream rather than merged, since upstream is authoritative about its own history). Cross-linked from both READMEs and both MANUALs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
334 lines
16 KiB
Markdown
334 lines
16 KiB
Markdown
# Changelog & Schema Reference
|
||
|
||
*Read this in: **English** | [Polski](CHANGELOG.pl.md)*
|
||
|
||
This file tracks two things: the page schema exactly as it stands today, and
|
||
how this project arrived at its current version numbers.
|
||
|
||
There are **two independent version numbers**, and they are not the same
|
||
thing:
|
||
|
||
| Number | Lives in | Describes | Who bumps it |
|
||
|---|---|---|---|
|
||
| `kb_schema_version` | frontmatter of `wiki/index.md` | the **content contract** — what a page may contain and what those fields mean | `ckb-upgrade` (on a confirmed migration), `ckb-module` (additively, on install) |
|
||
| Template version | [`VERSION`](VERSION) | the **tooling layer** — `AGENTS.md`, the skills, the scripts, the docs | `ckb-upgrade`, when it pulls a newer template |
|
||
|
||
They move independently on purpose. You can take a newer set of skills
|
||
without touching a single wiki page, and a wiki authored against an older
|
||
schema keeps working — that is what the schema version is for.
|
||
|
||
**Versioning policy.** Bump the **minor** version for an additive change: a
|
||
new optional field, a new optional body section, a new optional scaffold
|
||
file. Bump the **major** version for a breaking one: changing or removing a
|
||
required field, or changing an existing reserved filename convention. There
|
||
has never been a major bump; every schema version to date has been additive,
|
||
so any page written since 2026-07-13 is still valid today.
|
||
|
||
---
|
||
|
||
## Contents
|
||
|
||
1. [Current page schema (1.5)](#current-page-schema-kb_schema_version-15)
|
||
2. [KB schema version history](#kb-schema-version-history)
|
||
3. [Template version history](#template-version-history)
|
||
4. [Migrating between versions](#migrating-between-versions)
|
||
|
||
---
|
||
|
||
## Current page schema (`kb_schema_version: "1.5"`)
|
||
|
||
### Frontmatter — every non-reserved page
|
||
|
||
Every `.md` file under `wiki/` except the reserved ones (`index.md`,
|
||
`log.md`) carries YAML frontmatter. Only `type` is required; the rest are
|
||
optional, and preferred where meaningful. The parser is deliberately simple —
|
||
flat `key: value` pairs only, no nesting.
|
||
|
||
| Field | Required | Meaning |
|
||
|---|---|---|
|
||
| `type` | **yes** | Open string: `person`, `project`, `concept`, `library`, `decision`, `playbook`, `repository`, `component`, … New values are always valid; readers tolerate unrecognised ones. |
|
||
| `resource` | no | Canonical URI of the authoritative external source this page describes, kept separate from the wiki's own commentary. |
|
||
| `tldr` | no | One-sentence summary optimised for LLM reading. This is what the index shows and what decides whether a page gets opened at all. |
|
||
| `confidence` | no | `0.0`–`1.0`. Source corroboration. Set on write, decays if nothing reinforces it, raised by a new source that agrees. |
|
||
| `quality` | no | `0.0`–`1.0`. Self-evaluation of the page's own structure and citations. Below `0.7` is flagged for review. |
|
||
| `supersedes` | no | Path to the older page this one replaces. |
|
||
| `superseded_by` | no | Path to the newer page that replaced this one. **Always set both sides.** |
|
||
| `last_updated` | no | `YYYY-MM-DD`. When the *page* last changed. |
|
||
| `freshness_window_days` | no | Days before lint flags the page as stale. Typical: 90 for a wiki page, 365 for a decision, 30 for a connector-indexed document. |
|
||
| `retention` | no | `high` / `medium` / `low`. A `low` page is archived (never deleted) after 2× its freshness window. |
|
||
| `source_fingerprint` | no | *(1.5)* Digest of the source this page was built from — `sha256:<8 hex>` for a local file, or `etag:<value>` / `mtime:<iso8601>` for a connector item. |
|
||
| `source_checked` | no | *(1.5)* `YYYY-MM-DD` — when that digest was last verified. Distinct from `last_updated`: a re-check that finds nothing changed advances this and leaves `last_updated` alone. |
|
||
|
||
`wiki/index.md` alone carries `kb_schema_version`. It is a bundle-level
|
||
declaration, not a per-page one — individual pages never carry it.
|
||
|
||
### Frontmatter — decision pages
|
||
|
||
Pages with `type: decision` live in `wiki/decisions/` as `NNNN-slug.md` and
|
||
add:
|
||
|
||
| Field | Required | Meaning |
|
||
|---|---|---|
|
||
| `status` | **yes** | `proposed` / `accepted` / `rejected` / `superseded` / `reversed`. The vocabulary is defined in `wiki/decisions/index.md` and validated by lint. |
|
||
| `decided_on` | for `accepted`/`rejected`/`reversed` | `YYYY-MM-DD`, the date the call was made. |
|
||
| `decided_by` | when known | Comma-separated names. Where genuinely unknown, write `unknown` rather than omitting the field — "we don't know who decided this" is itself worth recording. |
|
||
| `affects` | no | Comma-separated wiki paths this decision constrains. |
|
||
| `review_on` | no | `YYYY-MM-DD` to revisit. Lint reports these once the date passes. |
|
||
|
||
Decision records are **append-only**. A decision is never rewritten to match
|
||
a later change of mind: record a new one that supersedes it, and both stay on
|
||
the record.
|
||
|
||
### Reserved body sections
|
||
|
||
*(New in 1.5.)* Four `##` headings mean the same thing on every page in every
|
||
layer of the cascade. All are optional; where present, they mean exactly this
|
||
and nothing else.
|
||
|
||
#### `## Sources`
|
||
|
||
Where the page came from. One bullet per source, each carrying a fingerprint:
|
||
|
||
```markdown
|
||
## Sources
|
||
|
||
- `raw/archive/2026-09-21/kickoff-notes.md` — sha256:3f9a2c1e (checked 2026-09-21)
|
||
```
|
||
|
||
A freshness window is a guess that a source *might* have moved. A fingerprint
|
||
is a fact about whether it *did*. Lint recomputes local digests and flags what
|
||
actually changed, which is a different and more urgent finding than a page
|
||
that has merely aged.
|
||
|
||
#### `## Crux`
|
||
|
||
Verbatim excerpts from those sources — evidence, never paraphrase — attributed
|
||
to the source bullet they came from:
|
||
|
||
```markdown
|
||
## Crux
|
||
|
||
> FDEs need the VDI *and* a Jira account before day one; the VDI request
|
||
> alone takes ten working days.
|
||
— `raw/archive/2026-09-21/kickoff-notes.md`, under "Access"
|
||
```
|
||
|
||
Three to ten lines is the working range. A Crux approaching the length of the
|
||
summary above it has stopped being evidence and become a second copy of the
|
||
source. Two things follow from quoting rather than paraphrasing: a question
|
||
can often be answered from the page instead of the archive, and drift becomes
|
||
visible — a summary can wander from its source silently, a quote either still
|
||
matches or it does not.
|
||
|
||
A page with no quotable source simply has no `## Crux`. An empty or
|
||
paraphrased one is worse than none, because it looks like evidence.
|
||
|
||
#### `## Notes`
|
||
|
||
Human-authored, and **protected**. No skill may rewrite, reflow, summarise or
|
||
drop this section; regeneration preserves it byte-for-byte.
|
||
|
||
```markdown
|
||
## Notes
|
||
|
||
<!-- Yours. Never rewritten by any skill. -->
|
||
```
|
||
|
||
This matters most on pages the agent *regenerates* — connector indexes, code
|
||
maps — where everything else is discarded and rebuilt on the next run. It is
|
||
the only place an annotation survives. Decision pages deliberately have no
|
||
`## Notes`: nothing regenerates them, and an append-only record with a freely
|
||
editable annotation block invites exactly the retroactive revision the
|
||
append-only rule exists to prevent.
|
||
|
||
### Edge vocabulary
|
||
|
||
Relationships live in `wiki/graph/edges.json` (and each connector index's own
|
||
`graph/edges.json`). The vocabulary is closed, and each verb is defined by the
|
||
question it answers — if a proposed edge answers none of them, it belongs in
|
||
the page's prose instead.
|
||
|
||
| Verb | Question it answers | Since |
|
||
|---|---|---|
|
||
| `part_of` | Where does this live? What is it a piece of? | 1.5 |
|
||
| `uses` | What does this reach for at runtime? | 1.1 |
|
||
| `depends_on` | What breaks if I change this? | 1.1 |
|
||
| `produces` | Where does this output come from? | 1.5 |
|
||
| `configures` | What changes this thing's behaviour? | 1.5 |
|
||
| `validates` | What checks, tests, or judges this? | 1.5 |
|
||
| `implements` | What contract must this honour? | 1.5 |
|
||
| `caused` | Why did this happen? | 1.1 |
|
||
| `contradicts` | What disagrees with this, unresolved? | 1.1 |
|
||
| `supersedes` | What replaced this, and what did it replace? | 1.1 |
|
||
| `decided_by` | Who made this call? | 1.4 |
|
||
| `affects` | What does this decision constrain? | 1.4 |
|
||
| `has_expertise_in` | Who can answer questions on this? | 1.3 |
|
||
| `owns` | Who is responsible for this? | 1.3 |
|
||
| `mentioned_in` | Which source document discusses this? | 1.2 (lib indexes only) |
|
||
|
||
Record one direction per relationship — `part_of`, `supersedes`,
|
||
`depends_on` and `uses` are canonical, and the inverse is not stored as a
|
||
second edge. Record edges only from demonstrated evidence; an absent edge
|
||
beats a fabricated one, and a padded graph degrades retrieval rather than
|
||
improving it (in-degree is used as a ranking signal).
|
||
|
||
### Reserved scaffold
|
||
|
||
| Path | Since | Purpose |
|
||
|---|---|---|
|
||
| `wiki/index.md` | 1.1 | Routing table; the only page carrying `kb_schema_version` |
|
||
| `wiki/overview.md` | 1.1 | High-level map of the KB |
|
||
| `wiki/log.md` | 1.1 | Reverse-chronological change log for `wiki/` |
|
||
| `wiki/error-book.md` | 1.1 | Systemic issues with root cause and fix |
|
||
| `wiki/entities/` | 1.1 | Typed entity pages |
|
||
| `wiki/graph/` | 1.1 | `edges.json` plus the vocabulary in `index.md` |
|
||
| `wiki/query-gaps.md` | 1.2 | Questions the wiki could not answer, driving demand-driven ingest |
|
||
| `wiki/projects/` | 1.2 | Optional local query scopes |
|
||
| `wiki/decisions/` | 1.4 | Numbered, append-only decision records, with their own `log.md` |
|
||
|
||
Every subdirectory that groups pages carries its own `index.md`, so
|
||
navigation stays lazy.
|
||
|
||
---
|
||
|
||
## KB schema version history
|
||
|
||
### 1.5 — 2026-09-21 · evidence, fingerprints, and a completed edge vocabulary
|
||
|
||
Adopted from an analysis of [trailhq/Graft](https://github.com/trailhq/Graft),
|
||
a context layer for coding agents that keeps a derived code graph in sync via
|
||
content hashes rather than dates, and protects a user-authored block on every
|
||
regenerated node. Graft's store is disposable and regenerable; this one is not,
|
||
so most of its design does not transfer — but several mechanisms do, and two
|
||
of them closed real gaps here.
|
||
|
||
**Added:**
|
||
|
||
- **`## Crux`** — verbatim source excerpts alongside the synthesis. Lets
|
||
`ckb-retrieve` ground an answer without a round-trip to the archive (when
|
||
the fingerprint still matches), and makes drift detectable.
|
||
- **`## Notes`** — human-authored and protected everywhere. This closed a real
|
||
gap: `ckb-index-external` regenerates connector pages wholesale, so an
|
||
annotation written there was previously destroyed on the next refresh.
|
||
- **`## Sources`** — formalised as a reserved section with one fingerprinted
|
||
bullet per source. Previously an informal convention that `ckb-retrieve`
|
||
relied on but no skill actually specified.
|
||
- **`source_fingerprint` / `source_checked`** frontmatter.
|
||
- **Edge verbs** `part_of`, `produces`, `configures`, `validates`,
|
||
`implements`. `part_of` fixed a live inconsistency: `ckb-code-map` had been
|
||
writing it since template 1.7.0 while the schema never declared it.
|
||
|
||
**Changed:**
|
||
|
||
- `wiki/graph/index.md` rewritten as a question-per-verb table with
|
||
conventions on edge direction and evidence.
|
||
- `ckb-ingest` gained a blast-radius step: before writing, walk the graph
|
||
backwards from touched entities to find what the incoming material
|
||
confirms, extends or contradicts, and name the owners of affected pages.
|
||
Ingest had been additive-first, which is how a wiki accumulates two pages
|
||
that quietly disagree.
|
||
- `ckb-retrieve` fuses graph in-degree as one ranked list among several,
|
||
weighted below 1.0 — centrality is a prior, not evidence.
|
||
- Rule E (session start) now runs `lint_report.py --quick` alongside
|
||
`git status`: a deterministic one-line knowledge-rot signal costing no
|
||
model tokens.
|
||
- Lint gained checks 12 (fingerprint drift), 13 (crux verbatimness) and 14
|
||
(the protected-`## Notes` rule).
|
||
|
||
**Compatibility:** fully additive. A 1.4 page with none of the new sections or
|
||
fields is valid 1.5. A migration will never manufacture a `## Crux` —
|
||
inventing quotes is precisely the failure that section exists to prevent.
|
||
|
||
### 1.4 — 2026-09-01 · decision records
|
||
|
||
**Added:** `type: decision` pages under `wiki/decisions/` as `NNNN-slug.md`,
|
||
with `status`, `decided_on`, `decided_by`, `affects`, `review_on`; the
|
||
`decided_by` and `affects` edge verbs; `wiki/decisions/index.md` and its own
|
||
`log.md`; the append-only rule. Answers "why is it like this", "who decided",
|
||
and "what changed that decision" as direct lookups instead of a full-text
|
||
guess. Owned by the `ckb-decide` skill.
|
||
|
||
### 1.3 — 2026-08-06 · people-to-topic edges
|
||
|
||
**Added:** the `has_expertise_in` and `owns` edge verbs, making "who knows
|
||
about X" and "who owns X" a graph lookup rather than a full-text search.
|
||
Recorded only from demonstrated evidence — attending a meeting is not
|
||
expertise, and a job title is not ownership.
|
||
|
||
### 1.2 — 2026-07-29 · query scopes, gaps, and connector-backed libs
|
||
|
||
**Added:** `wiki/projects/` (optional local query scopes grouping related
|
||
pages, sources and graph areas); `wiki/query-gaps.md` (failed searches
|
||
recorded as future ingest targets); `raw/archive/<YYYY-MM-DD>/` as the
|
||
agent-maintained filing destination; connector-backed `libs/<name>/` with a
|
||
user-authored `source.yaml`, an agent-owned generated index, and the
|
||
`mentioned_in` edge verb used inside those indexes.
|
||
|
||
### 1.1 — 2026-07-13 · initial schema
|
||
|
||
The first versioned contract, shipped with the initial commit. Established
|
||
the frontmatter field set (`type`, `resource`, `tldr`, `confidence`,
|
||
`quality`, `supersedes`/`superseded_by`, `last_updated`,
|
||
`freshness_window_days`, `retention`), the core edge verbs (`uses`,
|
||
`depends_on`, `caused`, `contradicts`, `supersedes`), the `wiki/` scaffold,
|
||
the cascade priority rule, and the recursive index-and-log convention.
|
||
|
||
There was never a 1.0: versioning began with the first published schema.
|
||
|
||
---
|
||
|
||
## Template version history
|
||
|
||
The tooling layer — `AGENTS.md`/`CLAUDE.md`, the skills, the scripts, the
|
||
docs. Independent of the content schema above.
|
||
|
||
| Version | Date | What landed | Schema |
|
||
|---|---|---|---|
|
||
| **1.8.0** | 2026-09-21 | Seven ideas adopted from Graft: crux/notes/fingerprints, `--quick` lint mode, in-degree ranking, ingest blast radius, completed edge vocabulary | → 1.5 |
|
||
| 1.7.0 | 2026-09-20 | Opt-in modules (`.agents/modules/`, `ckb-module`, `ckb.yaml`); the `software` module with `ckb-code-map` and `ckb-spec`; `ckb-reset`; OpenSpec docs | 1.4 |
|
||
| 1.6.1 | 2026-09-01 | Fixed false-positive broken-edge findings in the lint graph check | 1.4 |
|
||
| 1.6.0 | 2026-09-01 | `ckb-decide`; detection half of lint moved into `lint_report.py`; OKF export moved into `export_okf.py` | → 1.4 |
|
||
| 1.3.0 | 2026-08-06 | Rank fusion, dedupe and rerank in `ckb-retrieve`; expertise and ownership lookups | → 1.3 |
|
||
| 1.2.1 | 2026-07-29 | `AGENTS.md` compressed — workflows moved out into skills, leaving a small always-loaded rule set | 1.2 |
|
||
| 1.2.0 | 2026-07-29 | Project scopes, query gaps, source-verified retrieval | → 1.2 |
|
||
| 1.1.0 | 2026-07-20 | Connector-backed `libs/` with self-contained external source indexing (`ckb-index-external`) | 1.1 \* |
|
||
| 1.0.0 | 2026-07-17 | First tagged template: full skill set, `LICENSE`, `MANUAL`, bilingual docs | 1.1 |
|
||
|
||
\* Connector-backed libs shipped as tooling in 1.1.0, but the schema only
|
||
recorded them — the `source.yaml` contract, the generated index shape, the
|
||
`mentioned_in` verb — at 1.2, nine days later. The two numbers catching up
|
||
with each other like this is normal, and is why the schema column shows what
|
||
was in effect *after* each template release rather than what the release was
|
||
about.
|
||
|
||
Versions 1.4.0 and 1.5.0 were never published — the template jumped from
|
||
1.3.0 to 1.6.0 on 2026-09-01.
|
||
|
||
---
|
||
|
||
## Migrating between versions
|
||
|
||
Say **"upgrade the wiki"** or **"check for a newer template version"**. The
|
||
`ckb-upgrade` skill checks the canonical template repo, updates the tooling
|
||
layer in place, and — separately, and only after you explicitly confirm —
|
||
migrates existing `wiki/` content up to the current schema while preserving
|
||
every fact already collected.
|
||
|
||
The two halves are deliberately separate. Taking newer skills never rewrites
|
||
your pages, and a content migration is never silent: it reports what it
|
||
intends to change, batches anything it had to infer (such as a missing `type`)
|
||
for your confirmation, and logs every touched page in `wiki/log.md` marked as
|
||
a schema-migration backfill rather than new knowledge.
|
||
|
||
Because every schema version so far has been additive, an older wiki keeps
|
||
working unmigrated. Migration is worth doing to make the newer checks
|
||
meaningful — backfilled fingerprints are what give lint anything to verify —
|
||
not because anything is broken without it.
|
||
|
||
---
|
||
|
||
## Version & License
|
||
|
||
Current template version: [VERSION](VERSION). Current schema version: the
|
||
`kb_schema_version` field in `wiki/index.md`. Licensed under the
|
||
[Apache License 2.0](LICENSE).
|