docs(cookbook): add Change Management module notebook (#991)

* docs(cookbook): add Change Management module notebook

Add cookbook/introduction/24_Change_Management.ipynb covering the
change_management module with verified, executable examples:

- ChangeLogEntry with email-validated author field
- InMemoryVersionStorage save/get/list_all/exists/delete round trip
- named tags (save_tag/get_tag) for release pinning
- compute_checksum / verify_checksum integrity verification with
  tamper detection

The change_management module currently has no cookbook coverage. All
API calls and outputs were executed against
semantica/change_management/change_log.py and version_storage.py.

Signed-off-by: LeonSGP43 <LeonSGP43@users.noreply.github.com>

* docs(cookbook): clarify outputs verified against repo source, not PyPI release

Signed-off-by: LeonSGP43 <leonsgp43@users.noreply.github.com>

* docs(cookbook): execute change management notebook in Jupyter (real kernel run, stream outputs, execution counts)

Signed-off-by: LeonSGP43 <cine.dreamer.one@gmail.com>

---------

Signed-off-by: LeonSGP43 <LeonSGP43@users.noreply.github.com>
Signed-off-by: LeonSGP43 <leonsgp43@users.noreply.github.com>
Signed-off-by: LeonSGP43 <cine.dreamer.one@gmail.com>
Co-authored-by: LeonSGP43 <LeonSGP43@users.noreply.github.com>
This commit is contained in:
LeonSGP
2026-08-27 13:00:36 +05:00
committed by GitHub
co-authored by LeonSGP43
parent b13cc1cca2
commit 3d0ce55fd7
@@ -0,0 +1,299 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "8d7096ea",
"metadata": {},
"source": [
"[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/semantica-agi/semantica/blob/main/cookbook/introduction/24_Change_Management.ipynb)\n",
"\n",
"# Change Management — Practical Guide\n",
"\n",
"Semantica's `change_management` module provides versioning, audit trails, and data-integrity checks for knowledge graphs and ontologies:\n",
"\n",
"- **`ChangeLogEntry`** — standardized change metadata (validated timestamp/author)\n",
"- **`InMemoryVersionStorage` / `SQLiteVersionStorage`** — version snapshot storage with named tags\n",
"- **`compute_checksum` / `verify_checksum`** — SHA-256 integrity verification\n",
"\n",
"This notebook runs a complete save → tag → verify → tamper-detect cycle. All outputs are real executed results verified against the repository's `semantica/change_management/` source at the time of writing (the `pip install` cell may fetch a newer release with slightly different behavior)."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "7bdffec1",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-26T18:46:37.171333Z",
"iopub.status.busy": "2026-08-26T18:46:37.171183Z",
"iopub.status.idle": "2026-08-26T18:46:39.060860Z",
"shell.execute_reply": "2026-08-26T18:46:39.059594Z"
}
},
"outputs": [],
"source": [
"!pip install -q semantica"
]
},
{
"cell_type": "markdown",
"id": "169efee1",
"metadata": {},
"source": [
"## 1) A `ChangeLogEntry` records *who* changed *what*, *when*\n",
"\n",
"`author` must be a valid email — the dataclass validates on construction (`ValidationError` otherwise), which keeps audit trails clean."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "5b17acdb",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-26T18:46:39.064077Z",
"iopub.status.busy": "2026-08-26T18:46:39.063818Z",
"iopub.status.idle": "2026-08-26T18:46:39.321881Z",
"shell.execute_reply": "2026-08-26T18:46:39.321036Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"ChangeLogEntry(timestamp='2026-08-15T09:00:00Z', author='demo@example.com', description='initial version', change_id=None, related_changes=[])"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from semantica.change_management import ChangeLogEntry\n",
"\n",
"entry = ChangeLogEntry(\n",
" timestamp=\"2026-08-15T09:00:00Z\",\n",
" author=\"demo@example.com\",\n",
" description=\"initial version\",\n",
")\n",
"entry"
]
},
{
"cell_type": "markdown",
"id": "53d8df5c",
"metadata": {},
"source": [
"## 2) Save a versioned snapshot\n",
"\n",
"A snapshot is a dict with a required `label` plus your payload. Here we attach the KG data, the change log, and a SHA-256 `checksum` computed over everything except the checksum field itself."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "fec16f24",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-26T18:46:39.325528Z",
"iopub.status.busy": "2026-08-26T18:46:39.325140Z",
"iopub.status.idle": "2026-08-26T18:46:39.331480Z",
"shell.execute_reply": "2026-08-26T18:46:39.330586Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from semantica.change_management import InMemoryVersionStorage, compute_checksum\n",
"\n",
"storage = InMemoryVersionStorage()\n",
"\n",
"snapshot = {\n",
" \"label\": \"v1.0.0\",\n",
" \"data\": {\"entities\": {\"acme\": {\"type\": \"Company\"}}},\n",
" \"change_log\": {\n",
" \"timestamp\": entry.timestamp,\n",
" \"author\": entry.author,\n",
" \"description\": entry.description,\n",
" },\n",
"}\n",
"snapshot[\"checksum\"] = compute_checksum({k: v for k, v in snapshot.items() if k != \"checksum\"})\n",
"\n",
"storage.save(snapshot)\n",
"storage.exists(\"v1.0.0\")"
]
},
{
"cell_type": "markdown",
"id": "0f1c603b",
"metadata": {},
"source": [
"## 3) Named tags pin a version for releases\n",
"\n",
"`save_tag` / `get_tag` map stable names (e.g. `release`) to version labels, decoupling consumers from label churn."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "62f7643e",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-26T18:46:39.335182Z",
"iopub.status.busy": "2026-08-26T18:46:39.334886Z",
"iopub.status.idle": "2026-08-26T18:46:39.339586Z",
"shell.execute_reply": "2026-08-26T18:46:39.338568Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"('v1.0.0', ['v1.0.0'])"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"storage.save_tag(\"release\", \"v1.0.0\")\n",
"\n",
"storage.get_tag(\"release\"), [s[\"label\"] for s in storage.list_all()]"
]
},
{
"cell_type": "markdown",
"id": "96df12da",
"metadata": {},
"source": [
"## 4) Verify integrity — and catch tampering\n",
"\n",
"`verify_checksum(snapshot)` recomputes the SHA-256 over the snapshot (minus its `checksum` field) and compares. A single mutated character in the data flips the result to `False`."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "26d0de85",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-26T18:46:39.342653Z",
"iopub.status.busy": "2026-08-26T18:46:39.342466Z",
"iopub.status.idle": "2026-08-26T18:46:39.346714Z",
"shell.execute_reply": "2026-08-26T18:46:39.345623Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"intact: True\n",
"tampered: False\n"
]
}
],
"source": [
"from semantica.change_management import verify_checksum\n",
"\n",
"stored = storage.get(\"v1.0.0\")\n",
"print(\"intact:\", verify_checksum(stored))\n",
"\n",
"tampered = storage.get(\"v1.0.0\")\n",
"tampered[\"data\"][\"entities\"][\"acme\"][\"note\"] = \"mutated after the fact\"\n",
"print(\"tampered:\", verify_checksum(tampered))"
]
},
{
"cell_type": "markdown",
"id": "bd14c3e4",
"metadata": {},
"source": [
"## 5) Retiring a version\n",
"\n",
"`delete(label)` removes a snapshot; tags pointing at it are your responsibility to update."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "de9fe3e5",
"metadata": {
"execution": {
"iopub.execute_input": "2026-08-26T18:46:39.349814Z",
"iopub.status.busy": "2026-08-26T18:46:39.349513Z",
"iopub.status.idle": "2026-08-26T18:46:39.354710Z",
"shell.execute_reply": "2026-08-26T18:46:39.353669Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"storage.delete(\"v1.0.0\")\n",
"storage.exists(\"v1.0.0\")"
]
},
{
"cell_type": "markdown",
"id": "ab667b32",
"metadata": {},
"source": [
"## Summary\n",
"\n",
"| Task | API |\n",
"|---|---|\n",
"| Record audit metadata | `ChangeLogEntry(timestamp, author=email, description)` |\n",
"| Persist a version | `InMemoryVersionStorage().save({\"label\": ..., ...})` |\n",
"| Pin a release name | `save_tag(\"release\", \"v1.0.0\")` / `get_tag(\"release\")` |\n",
"| Integrity check | `compute_checksum(snap)` / `verify_checksum(snap)` |\n",
"| Persistent backend | `SQLiteVersionStorage(path)` — same interface |\n",
"\n",
"See also `semantica/change_management/change_management_usage.md` for the manager classes (`TemporalVersionManager`, `OntologyVersionManager`)."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}