Skip to content

Commit a62e251

Browse files
committed
docs: add v3.6.1 serving-multiversion-unpack content
- Add versioning.md: git model, tag prefixes, Git2PROV/DOAP provenance, .git-ref stamps, bare repo architecture - Update operator.md: version materialisation section covering serving.json retirement, CK.Project spec.versions, deploy.materialise step, per-version PVs/HTTPRoutes, GC, backward compatibility - Update introduction.md: v3.6.1 in release train, version-pinned design principle updated (CR replaces serving.json) - Update changelog.md: full v3.6.1 entry with D1-D9 coverage - Update config.mts: Versioning page in v3.6 sidebar
1 parent 92b5858 commit a62e251

5 files changed

Lines changed: 353 additions & 2 deletions

File tree

docs/.vitepress/config.mts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ export default withMermaid(defineConfig({
112112
{ text: 'ConceptKernel CRD', link: '/v3.6/crd' },
113113
{ text: 'Evidence-Based Proof', link: '/v3.6/proof' },
114114
{ text: 'Reconciliation & Logging', link: '/v3.6/reconciliation' },
115+
{ text: 'Versioning', link: '/v3.6/versioning' },
115116
]
116117
},
117118
{

docs/v3.6/changelog.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,59 @@ v3.5-alpha6 was the last deployed incremental release. v3.6 adds:
4141

4242
---
4343

44+
## v3.6.1 -- serving-multiversion-unpack <Badge type="info" text="SPEC" />
45+
46+
**Date:** 2026-04-06 | **Implements:** CK.Operator v1.3.0
47+
48+
Version materialisation moves from `serving.json` on disk to the CK.Project custom resource. The CK volume becomes purely immutable -- no write-through exceptions.
49+
50+
### What Changes
51+
52+
- **serving.json retired** -- no longer exists on disk. The three problems it created (write-through hack, inert file, decorative git refs) are dissolved.
53+
- **CK.Project `spec.versions`** -- named versions with git commit ref and URL route prefix. Version state is in etcd, not the filesystem.
54+
- **`spec.repo`** -- upstream git URL. The operator clones to scratch space and runs `git archive` locally (FUSE mounts cannot host bare repos).
55+
- **`deploy.materialise` step** -- new reconciliation step between `deploy.namespace` and `deploy.storage`. Streams `git archive` output to filer at `/ck/v/{tag}/{kernel}/`.
56+
- **`.git-ref` stamp** -- each materialised directory contains the exact commit hash. Implements `prov:wasGeneratedBy` from Git2PROV.
57+
- **Per-version PVs** -- `ck-{project}-{kernel}-{tag}`, each pointing to `/ck/v/{tag}/{kernel}`. When a tag's ref changes, content updates without PV recreation.
58+
- **Per-version HTTPRoutes** -- longest-prefix-first routing. Each version gets its own deployment and route rule.
59+
- **Garbage collection** -- filer paths under `/ck/v/` not referenced by any CK.Project version are deleted after reconciliation.
60+
- **Shared kernel optimisation** -- identical tree hashes across versions share one filer copy.
61+
- **Backward compatible** -- no `spec.versions` means flat layout, existing projects unchanged.
62+
63+
### Git Model (D9)
64+
65+
- One repo per project. CK + TOOL in same repo, DATA never in git.
66+
- Tag prefix convention: `ck/{kernel}/vX.Y.Z`, `tool/{kernel}/vX.Y.Z` for independent loop versioning.
67+
- Per-loop overrides: `ck_ref` and `tool_ref` in version declarations for split CK/TOOL tags.
68+
- Ontological grounding: DOAP for repo metadata, Git2PROV (PROV-O) for commit provenance.
69+
70+
### Deficiencies Resolved
71+
72+
| Deficiency | Resolution |
73+
|-----------|-----------|
74+
| D1: No version materialisation | `git archive` from bare repo, commit-pinned |
75+
| D3: No serving.json write-through | serving.json retired, version state in CR |
76+
| D6: No git integration on filer | Bare repo on scratch, `.git-ref` traceability |
77+
78+
### New CK.Project CRD Fields
79+
80+
| Field | Type | Required | Description |
81+
|-------|------|----------|-------------|
82+
| `spec.repo` | string | MUST (if versions declared) | Upstream git URL |
83+
| `spec.versions` | array | SHOULD | Version declarations |
84+
| `spec.versions[].name` | string | MUST | Tag name (used in PV names, filer paths, routes) |
85+
| `spec.versions[].ref` | string | MUST | Git commit hash to materialise |
86+
| `spec.versions[].route` | string | MUST | URL path prefix |
87+
| `spec.versions[].ck_ref` | string | MAY | CK loop tag override |
88+
| `spec.versions[].tool_ref` | string | MAY | TOOL loop tag override |
89+
90+
### New Ontology Classes
91+
92+
- `VersionDeclaration` -- named version pinned to a git commit, mapped to a URL route
93+
- `GitRepoConfig` -- upstream git repository location
94+
95+
---
96+
4497
## Incremental Versions (v3.5.x)
4598

4699
All notable changes in the development increments that compose v3.6. Each version was an independently shippable increment. Versions marked DEPLOYED have running proof on the reference cluster.

docs/v3.6/introduction.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ All inter-kernel communication MUST use NATS messaging. HTTP is for static web s
7373

7474
### 4. Version-Pinned
7575

76-
Containers SHALL see only the versions declared in `serving.json`. No arbitrary version access. This prevents version drift and ensures reproducible behaviour across the fleet.
76+
Containers SHALL see only the versions declared in the CK.Project CR (`spec.versions`). No arbitrary version access. This prevents version drift and ensures reproducible behaviour across the fleet. Version state lives in the Kubernetes control plane, not on the filesystem.
7777

7878
### 5. Provenance-Mandatory
7979

@@ -174,6 +174,11 @@ v3.5.15 Task execution engine PLANNED
174174
v3.5.16 Agent Teams PLANNED
175175
---------------------------------------------------------------------
176176
v3.6 Full release -- sum of all above
177+
178+
v3.6.1 serving-multiversion-unpack (CK.Operator v1.3.0) SPEC
179+
Version materialisation via CK.Project CR
180+
serving.json retired, git archive -> filer pipeline
181+
Per-version PVs, HTTPRoutes, garbage collection
177182
```
178183

179184
### Why This Model
@@ -282,6 +287,7 @@ The v3.6 docs are organized by capability, not by version number. Each page expl
282287
| [Sessions](/v3.6/sessions) | Multi-user NATS sessions (v3.5.14, planned) |
283288
| [Task Engine](/v3.6/task-engine) | Consensus-driven headless execution (v3.5.15, planned) |
284289
| [Agent Teams](/v3.6/agent-teams) | Multi-kernel coordination (v3.5.16, planned) |
290+
| [Versioning](/v3.6/versioning) | Git model, tag prefixes, .git-ref provenance (v3.6.1) |
285291
| [Changelog](/v3.6/changelog) | Full version-by-version changelog |
286292

287293
::: info Logical Analysis Note

docs/v3.6/operator.md

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,133 @@ The `project.deploy` action follows a deterministic 10-step sequence. Each step
7878

7979
For the full step-by-step breakdown, see [Reconciliation Lifecycle](./reconciliation).
8080

81+
## Version Materialisation (v3.6.1)
82+
83+
::: info v3.6.1 -- serving-multiversion-unpack
84+
This section documents the version materialisation model introduced in v3.6.1, implemented in CK.Operator v1.3.0. See [Versioning](./versioning) for the full git model.
85+
:::
86+
87+
### serving.json Is Retired
88+
89+
Prior to v3.6.1, `serving.json` was the sole exception to the CK loop's read-only policy. It declared which version was active via `ck_ref` and `tool_ref` fields. This created three problems that could not be cleanly solved:
90+
91+
1. **Write-through hack** -- the CK volume had to be writable for one file, breaking the separation axiom.
92+
2. **Inert file** -- `serving.json` existed on disk but was not enforced by the runtime, making it decorative.
93+
3. **Decorative refs** -- the git branch names in `serving.json` had no mechanism to resolve to actual commit hashes.
94+
95+
v3.6.1 dissolves all three problems by moving version state from the filesystem to the Kubernetes control plane. `serving.json` no longer exists on disk. The CK volume is purely ReadOnlyMany with no exceptions.
96+
97+
### Version State in CK.Project CR
98+
99+
Version declarations live in the CK.Project custom resource:
100+
101+
```yaml
102+
spec:
103+
repo: https://github.com/ConceptKernel/kernels.git
104+
versions:
105+
- name: live
106+
ref: abc123f
107+
route: /
108+
- name: staging
109+
ref: def4567
110+
route: /staging
111+
- name: review-pr-42
112+
ref: 789feda
113+
route: /review/pr-42
114+
```
115+
116+
The operator reads `spec.versions`, materialises each version from the git repository, and creates per-version PVs and HTTPRoute rules. A version promotion is a CK.Project resource update -- `kubectl patch`, NATS command, or operator API. Standard Kubernetes-native workflow with etcd history.
117+
118+
### Materialisation Pipeline
119+
120+
The reconciliation lifecycle gains a new step, `deploy.materialise`, inserted between `deploy.namespace` and `deploy.storage`:
121+
122+
```
123+
Reconciliation lifecycle (v3.6.1):
124+
125+
1. deploy.namespace
126+
2. deploy.materialise -- NEW: git archive -> filer
127+
3. deploy.storage.ck
128+
4. deploy.storage.data
129+
5. deploy.processors
130+
6. deploy.web
131+
7. deploy.routing
132+
8. deploy.conceptkernels
133+
9. deploy.auth
134+
10. deploy.graph
135+
11. deploy.endpoint
136+
```
137+
138+
For each version in `spec.versions`, the materialise step:
139+
140+
1. Checks if `/ck/v/{tag}/{kernel}/.git-ref` exists on filer
141+
2. If it exists and contains the same ref -- skip (already current)
142+
3. If missing or different ref:
143+
- Runs `git archive {ref}:{kernel}/` from the bare repo
144+
- Uploads the archive to filer at `/ck/v/{tag}/{kernel}/`
145+
- Writes the commit hash to `/ck/v/{tag}/{kernel}/.git-ref`
146+
4. Ensures PV `ck-{project}-{kernel}-{tag}` exists pointing to `/ck/v/{tag}/{kernel}`
147+
5. Ensures PVC is bound
148+
149+
### Per-Version PVs and HTTPRoutes
150+
151+
Each declared version gets its own PersistentVolume and routing rule:
152+
153+
```yaml
154+
# Per-version CK volume
155+
apiVersion: v1
156+
kind: PersistentVolume
157+
metadata:
158+
name: ck-delvinator-core-live
159+
spec:
160+
accessModes: [ReadOnlyMany]
161+
capacity:
162+
storage: 50Gi
163+
csi:
164+
driver: seaweedfs-csi-driver
165+
volumeHandle: ck-delvinator-core-live
166+
volumeAttributes:
167+
path: "/ck/v/live/Delvinator.Core"
168+
```
169+
170+
HTTPRoute rules are ordered longest-prefix first, so `/staging` matches before `/`:
171+
172+
```yaml
173+
spec:
174+
hostnames: [delvinator.tech.games]
175+
rules:
176+
- matches:
177+
- path: { type: PathPrefix, value: /staging }
178+
backendRefs:
179+
- name: delvinator-staging
180+
- matches:
181+
- path: { type: PathPrefix, value: / }
182+
backendRefs:
183+
- name: delvinator-live
184+
```
185+
186+
When a tag's ref changes, the PV is not recreated -- the filer path is stable (keyed by tag name). Content changes when the operator re-materialises. Pods pick up new content on rolling restart.
187+
188+
### Version Lifecycle via CR
189+
190+
| CR Change | Operator Action |
191+
|-----------|-----------------|
192+
| Add version | Materialise, create deployment + PV/PVC + route rule |
193+
| Change version ref | Re-materialise, roll pods |
194+
| Remove version | Delete deployment, PV/PVC, route rule, GC filer path |
195+
196+
### Garbage Collection
197+
198+
After reconciliation, the operator scans `/ck/v/` on the filer and deletes directories not referenced by any active version in any CK.Project resource. GC logs every deletion and never removes directories referenced by other projects.
199+
200+
### Shared Kernel Optimisation
201+
202+
When two versions reference the same git tree hash for a kernel (e.g., the CK loop has not changed between live and staging), the operator reuses one filer copy. The PV for the second version points to the first version's filer path -- no duplicate storage.
203+
204+
### Backward Compatibility
205+
206+
If `spec.versions` is absent from a CK.Project resource, the operator falls back to the current flat layout (`/ck/{KernelName}/`). Existing projects deployed without version declarations continue to work unchanged.
207+
81208
### What Each Step Creates
82209

83210
**deploy.namespace**: Namespace `ck-{subdomain}`, ServiceAccount `ckp-runtime`, NetworkPolicies (default-deny, allow-nats, allow-dns, allow-gateway).
@@ -361,7 +488,7 @@ The v3.5.7 `patch` addition was necessary for idempotent updates. Without it, `k
361488

362489
**Contradiction identified:** The v3.5.2 delta spec says "13 checks" for the initial deployment, but the v3.5.5 changelog says "13 infra + 2 auth" totaling 15. The v3.5.2 deployment output shows 13/13 checks passing (before auth existed). After v3.5.5, the count became 15/15. The documentation is consistent -- the count increased when auth was added. Not a contradiction, but worth noting for readers comparing version outputs.
363490

364-
**Gap identified:** The operator does not currently support canary deployments. `serving.json` defines stable/canary/develop versions with weights, but the operator does not create weighted route rules. This is documented in the v3.5-alpha6 operator roadmap as a future version.
491+
**Gap resolved (v3.6.1):** The operator now supports multi-version deployments via `spec.versions` in the CK.Project CR. `serving.json` has been retired. Each named version gets its own deployment, PV, and HTTPRoute rule. Weighted canary routing is not yet supported -- versions are routed by URL path prefix, not traffic weight.
365492
:::
366493

367494
## Conformance Requirements

0 commit comments

Comments
 (0)