Skip to content

Commit 3b5d4b1

Browse files
feat: bitemporal recall quality evidence
Merges verified PR #88 after all required checks passed and review threads were resolved.
1 parent 54c9985 commit 3b5d4b1

119 files changed

Lines changed: 19522 additions & 1440 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude-plugin/skill-assets.sha256

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
a972f840492bf1041f1e9525452127a6d5d117d5fcd231230b1d2ae656d85d13 .claude-plugin/marketplace.json
22
dba3e0713559b267581f45cfd5907aae4689df77790b02bbcf22309d9ffa73ef .claude-plugin/plugin.json
3-
89bf2728e44a3c877e31982d387fcfab10fbe065eb6441b2792375ca5105c07c skills/engraphis-memory/SKILL.md
4-
a295b0448e2ff372ddd8ea4e0bc8dc53f3d4bd56ff1fbd0d88cf4b6179511ce1 skills/engraphis-memory/references/CONVENTIONS.md
3+
656caf07c9064b219eb974e018180e6a7a88f2c058fb1b1c6a8a36074d67e9cc skills/engraphis-memory/SKILL.md
4+
9751b6e7310151c14e6bb7f5d683943a53a95951ff207876053d082e65eecfd5 skills/engraphis-memory/references/CONVENTIONS.md
55
45f4b4ad9dbfd39f2b377083d9b3eec5eed7cba7cb8fa139e3f420bdd6105343 skills/engraphis-memory/references/SCOPING.md
6-
12980f16face01fee5f65cde0c4aa2297200b2252861b341ec7762e32600da60 skills/engraphis-memory/references/TOOLS.md
6+
dc83c48d1a57122e7b58da29d32ae3b8ebd4ffff0b6d0570a8833e920e365109 skills/engraphis-memory/references/TOOLS.md

.github/workflows/ci.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,10 @@ jobs:
161161
run: |
162162
python -m pip install --upgrade pip build pip-audit
163163
python -m build
164+
python scripts/verify_distribution_contents.py dist/*
164165
python -m venv .audit-venv
165166
.audit-venv/bin/python -m pip install --upgrade "pip>=26.1.2" "setuptools>=83"
166167
.audit-venv/bin/python -m pip install dist/*.whl
167168
AUDIT_SITE=$(.audit-venv/bin/python -c "import site; print(site.getsitepackages()[0])")
168169
python -m pip_audit --path "$AUDIT_SITE"
169-
.audit-venv/bin/python -c "import engraphis; print('wheel import OK')"
170+
.audit-venv/bin/python -c "import engraphis, eval.harness; print('wheel imports OK')"

.github/workflows/release.yml

Lines changed: 100 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,18 @@ jobs:
6161
ruff check .
6262
python -c "import fastapi, httpx, mcp, multipart, pydantic, uvicorn"
6363
python -m pytest -o addopts="" tests/ -q -rs
64+
python -m pytest -o addopts="" tests/test_public_research_boundary.py -q
65+
python -m pytest -o addopts="" tests/test_compact_recall.py tests/test_eval_performance.py -q
66+
python -m pytest -o addopts="" tests/test_eval_harness.py tests/test_benchmark_evidence.py -q
6467
python -m eval.harness --dataset eval/datasets/sample.jsonl --k 5
6568
python -m eval.harness --dataset eval/datasets/codemem.jsonl --k 5
6669
python -m eval.ablation
6770
python -m pip_audit --local
6871
6972
- name: Build source and universal wheel distributions
70-
run: python -m build
73+
run: |
74+
python -m build
75+
python scripts/verify_distribution_contents.py dist/*
7176
7277
- name: Validate distributions
7378
run: python -m twine check dist/*
@@ -134,7 +139,7 @@ jobs:
134139
npm ci
135140
npx playwright install --with-deps chromium
136141
- name: Playwright desktop/mobile, keyboard, CSP, console, and axe checks
137-
run: npx playwright test
142+
run: npm run test:e2e
138143

139144
docker-smoke:
140145
name: Production image release gate
@@ -176,9 +181,58 @@ jobs:
176181
if: always()
177182
run: docker rm -f engraphis-release || true
178183

184+
release-evidence:
185+
name: Generate public release evidence
186+
needs: [build, python-matrix, browser-accessibility, docker-smoke]
187+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
188+
runs-on: ubuntu-latest
189+
permissions:
190+
contents: read
191+
192+
steps:
193+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
194+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
195+
with:
196+
python-version: "3.11"
197+
- name: Install SBOM generator and project dependencies
198+
run: >-
199+
python -m pip install --upgrade "pip>=26.1.2" "setuptools>=83"
200+
cyclonedx-bom==7.3.0 ".[all,test]"
201+
- name: Download distributions
202+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
203+
with:
204+
name: python-package-distributions
205+
path: dist/
206+
- name: Generate evidence and reproducible SBOM after all release gates
207+
shell: bash
208+
run: |
209+
mkdir release-evidence
210+
sbom="release-evidence/engraphis-${GITHUB_REF_NAME#v}.cdx.json"
211+
cyclonedx-py environment --output-reproducible --of JSON --pyproject pyproject.toml -o "$sbom"
212+
python scripts/release_evidence.py --dist dist --commit "$GITHUB_SHA" \
213+
--tag "$GITHUB_REF_NAME" \
214+
--sbom "$sbom" \
215+
--verified-check ruff \
216+
--verified-check pytest \
217+
--verified-check privacy-boundary \
218+
--verified-check token-efficiency \
219+
--verified-check benchmark-schema-evidence \
220+
--verified-check browser-e2e \
221+
--verified-check dependency-audit \
222+
--verified-check container-smoke \
223+
--verified-check retrieval-sample \
224+
--verified-check retrieval-codemem \
225+
--verified-check retrieval-ablation \
226+
--output release-evidence/release-evidence.json
227+
- name: Store public release evidence
228+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
229+
with:
230+
name: public-release-evidence
231+
path: release-evidence/
232+
179233
publish:
180234
name: Publish to PyPI
181-
needs: [build, python-matrix, browser-accessibility, docker-smoke]
235+
needs: release-evidence
182236
# Manual dispatch is intentionally build/check-only. Publication requires a pushed
183237
# semver tag, whose value was matched to pyproject.toml in the build job above.
184238
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
@@ -236,6 +290,12 @@ jobs:
236290
name: python-package-distributions
237291
path: dist/
238292

293+
- name: Download public release evidence
294+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
295+
with:
296+
name: public-release-evidence
297+
path: release-evidence/
298+
239299
- name: Create GitHub Release
240300
env:
241301
GH_TOKEN: ${{ github.token }}
@@ -246,11 +306,11 @@ jobs:
246306
# A previous partial attempt may have created the release before every
247307
# canonical package asset uploaded. Reconcile same-named assets from the
248308
# exact aggregate that passed the publish gate.
249-
gh release upload "$GITHUB_REF_NAME" dist/* \
309+
gh release upload "$GITHUB_REF_NAME" dist/* release-evidence/release-evidence.json release-evidence/*.cdx.json \
250310
--repo "$GH_REPO" \
251311
--clobber
252312
else
253-
gh release create "$GITHUB_REF_NAME" dist/* \
313+
gh release create "$GITHUB_REF_NAME" dist/* release-evidence/release-evidence.json release-evidence/*.cdx.json \
254314
--repo "$GH_REPO" \
255315
--verify-tag \
256316
--generate-notes \
@@ -319,11 +379,44 @@ jobs:
319379
(.conclusion == "success" or
320380
.conclusion == "failure"))] | length' \
321381
<<<"$jobs")" -eq 1
382+
test "$(jq '[.jobs[] | select(.name == "Generate public release evidence" and
383+
.conclusion == "success")] | length' \
384+
<<<"$jobs")" -eq 1
322385
gh run download "$run_id" \
323386
--repo "$GH_REPO" \
324387
--name python-package-distributions \
325388
--dir dist
326389
390+
gh run download "$run_id" \
391+
--repo "$GH_REPO" \
392+
--name public-release-evidence \
393+
--dir release-evidence
394+
python - "$RELEASE_TAG" "$tag_sha" <<'PY'
395+
import hashlib
396+
import json
397+
import sys
398+
from pathlib import Path
399+
400+
tag, commit = sys.argv[1:]
401+
with open("release-evidence/release-evidence.json", encoding="utf-8") as handle:
402+
evidence = json.load(handle)
403+
assert evidence.get("format") == "engraphis-release-evidence/2"
404+
assert evidence.get("package", {}).get("version") == tag.removeprefix("v")
405+
assert evidence.get("tag") == tag
406+
assert evidence.get("commit") == commit
407+
assert evidence.get("provenance", {}).get("source") == {"tag": tag, "commit": commit}
408+
expected = {
409+
item["filename"]: item["sha256"]
410+
for item in evidence.get("artifacts", [])
411+
}
412+
actual = {
413+
path.name: hashlib.sha256(path.read_bytes()).hexdigest()
414+
for path in Path("dist").iterdir()
415+
if path.is_file() and (path.name.endswith(".whl") or path.name.endswith(".tar.gz"))
416+
}
417+
assert expected == actual
418+
PY
419+
327420
- name: Verify any previously published subset
328421
env:
329422
RELEASE_TAG: ${{ inputs.release_tag }}
@@ -361,11 +454,11 @@ jobs:
361454
shell: bash
362455
run: |
363456
if gh release view "$RELEASE_TAG" --repo "$GH_REPO" >/dev/null 2>&1; then
364-
gh release upload "$RELEASE_TAG" dist/* \
457+
gh release upload "$RELEASE_TAG" dist/* release-evidence/release-evidence.json release-evidence/*.cdx.json \
365458
--repo "$GH_REPO" \
366459
--clobber
367460
else
368-
gh release create "$RELEASE_TAG" dist/* \
461+
gh release create "$RELEASE_TAG" dist/* release-evidence/release-evidence.json release-evidence/*.cdx.json \
369462
--repo "$GH_REPO" \
370463
--verify-tag \
371464
--generate-notes \

AGENTS.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ most common mistake here.
2020
| Status | Primary scoped, bi-temporal, interface-driven implementation. | Compatibility/reference implementation with flat namespaces. |
2121
| Model | Scoped + bi-temporal + typed; interface-driven. | Single flat `namespace` string per memory. |
2222
| Code | `engraphis/core/`, `engraphis/backends/`, `eval/`, `tests/`, `scripts/migrate_to_v2.py` | `engraphis/app.py`, `config.py`, `models.py`, `routes/`, `stores/`, `engines/`, `llm/`, `static/` |
23-
| Data | new v2 schema (`SCHEMA_VERSION = 4`) | `engraphis_v1.db` |
23+
| Data | new v2 schema (`SCHEMA_VERSION = 6`) | `engraphis_v1.db` |
2424
| Entry | `MemoryEngine.create()``core/engine.py` | `python -m scripts.start_server` → FastAPI on :8700 |
2525

2626
**Rule:** build new capability on **v2** (`core/` + `backends/`) behind the interfaces.
@@ -79,8 +79,6 @@ python -m scripts.cli recall "what do we know about X" -n vault # CLI: ingest
7979
python -m scripts.migrate_to_v2 --old engraphis_v1.db --new engraphis_v2.db --dry-run
8080
python -m scripts.migrate_to_v2 --old engraphis_v1.db --new engraphis_v2.db
8181

82-
# ── Seed memories from an Obsidian/markdown vault (v1) ───────────────────────
83-
python -m scripts.seed_from_obsidian "C:/path/to/Vault" --namespace vault
8482
```
8583

8684
`requires-python >= 3.9` (ruff targets `py39`); CI and the recommended dev environment use **3.11**.
@@ -93,15 +91,17 @@ python -m scripts.seed_from_obsidian "C:/path/to/Vault" --namespace vault
9391

9492
```
9593
query
96-
└─ SearchFilter (scope + as_of time anchor) core/interfaces.py
97-
└─ 3 retrieval arms (run in parallel, then fused):
94+
└─ SearchFilter (scope + valid_at/known_at anchors) core/interfaces.py
95+
└─ 4 retrieval arms (run in parallel, then fused):
9896
• vector — VectorIndex.search (cosine) backends/vector_*.py
9997
• lexical — Store.fts_search (FTS5/BM25 + LIKE fallback) core/store.py
10098
• graph — Personalized PageRank over entities+links core/recall.py + core/graphrank.py
10199
(graph_mode="1hop" keeps the old expansion for ablation)
100+
• code — symbols/files/calls with memory bridges core/engine.py
102101
└─ RRF fusion + six-term weighted score core/scoring.py
103102
└─ rerank top-N backends/reranker.py
104-
└─ context packing (token budget) + reinforce() core/recall.py / core/store.py
103+
└─ context packing (token budget) + optional explicit reinforcement
104+
core/recall.py / core/store.py
105105
```
106106

107107
Backends are selected by `get_embedder()` / `get_vector_index()` / `get_reranker()` and
@@ -177,7 +177,7 @@ These are pure, unit-tested functions — change them only with a corresponding
177177

178178
---
179179

180-
## 5. Data model cheat-sheet (`core/interfaces.py`, `core/schema.py``SCHEMA_VERSION = 4`)
180+
## 5. Data model cheat-sheet (`core/interfaces.py`, `core/schema.py``SCHEMA_VERSION = 6`)
181181

182182
- **Scope hierarchy:** `workspace → repo → session → memory`. Scopes: `session|repo|workspace|user`.
183183
- **Bi-temporal validity on every record:** world-time `valid_from/valid_to` +
@@ -188,7 +188,8 @@ These are pure, unit-tested functions — change them only with a corresponding
188188
Lexicographic sort == chronological.
189189
- **Tables:** `workspaces`, `repos`, `sessions`, `memories`, `mem_vectors`,
190190
`mem_fts` (FTS5 + plain-table fallback), `entities`, `edges` (bi-temporal), `mem_links`,
191-
`symbols`, `code_edges`, `code_files`, `code_memory_links`, `operation_receipts`,
191+
`memory_entities`, `symbols`, `code_edges`, `code_files`, `code_memory_links`,
192+
`operation_receipts`,
192193
`events`, `audit`, `schema_migrations`.
193194
- **Vectors are stored L2-normalized** so cosine similarity == dot product.
194195

@@ -221,7 +222,7 @@ These are pure, unit-tested functions — change them only with a corresponding
221222
- **`README.md`** — installation, product surfaces, configuration, and public API usage.
222223
- **`CHANGELOG.md`** — shipped capability and release history. Keep phase/status ledgers out of
223224
this operating manual.
224-
- **`docs/SYNC.md`** — cloud sync (Pro): architecture, the convergent merge, CLI usage, the
225+
- **`docs/SYNC.md`** — cloud sync (Pro): architecture, the convergent merge, CLI usage, and the
225226
untrusted-bundle security model.
226227
- **`AGENTS.md`** (this file) + **`CLAUDE.md`** — how to work in the repo.
227228
- **`skills/engraphis-memory/`** — portable Agent Skill (SKILL.md + `references/`) that teaches any

0 commit comments

Comments
 (0)