Skip to content

Commit 6f9c348

Browse files
Remove em dashes from public docs
1 parent 33599b0 commit 6f9c348

17 files changed

Lines changed: 312 additions & 296 deletions

BENCHMARKS.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,30 @@ been written; when this and the code disagree, the code wins (CLAUDE.md).
99
Engraphis's eval harness scores **retrieval**, not end-to-end QA. That distinction is deliberate
1010
and stated everywhere the numbers appear (`eval/external.py`).
1111

12-
- **Correctness gate** `eval/harness.py` over `eval/datasets/sample.jsonl` and
12+
- **Correctness gate**: `eval/harness.py` over `eval/datasets/sample.jsonl` and
1313
`codemem.jsonl` (conflict resolution) and `graph_multihop.jsonl` (multi-hop graph recall).
1414
Runs on the deterministic embedder, so it is a plumbing/regression floor, not a public
1515
performance claim. This is the gate CI enforces.
16-
- **Ablation** `eval/ablation.py`: vector-only vs. 1-hop graph vs. Personalized-PageRank arm,
16+
- **Ablation**: `eval/ablation.py`: vector-only vs. 1-hop graph vs. Personalized-PageRank arm,
1717
to show the graph arm actually earns its place.
18-
- **External benchmarks** `eval/external.py` loads **LoCoMo** and **LongMemEval** and pushes
18+
- **External benchmarks**: `eval/external.py` loads **LoCoMo** and **LongMemEval** and pushes
1919
them through the *real* `MemoryEngine` write path (conflict resolution + evolution) and hybrid
2020
recall with a real sentence-transformers embedder. It reports `recall_at_k` / `hit_at_k` /
21-
`answer_token_recall` i.e. *did the evidence come back*, not *did an LLM answer correctly*.
21+
`answer_token_recall`: i.e. *did the evidence come back*, not *did an LLM answer correctly*.
2222
It retains source categories and abstention/no-evidence questions as explicit exclusions from
2323
retrieval-only aggregates rather than silently dropping them. `eval.longmemeval_v2` is a local,
2424
text-only adapter for the official LongMemEval-V2 `insert(trajectory)` / `query(query,
2525
query_image=None)` memory interface; it does not download data or call a model.
26-
- **Grounded** `eval/grounded.py`: answerable → cite, off-topic → abstain.
27-
- **Chunking (quality per token)** `eval/chunking_eval.py` over `eval/datasets/longdoc.jsonl`
28-
ingests a multi-topic corpus twiceone memory per document (`whole`) vs. sub-file
29-
`ChunkingExtractor` (`chunked`) — and queries both through the real recall pipeline. This is
26+
- **Grounded**: `eval/grounded.py`: answerable → cite, off-topic → abstain.
27+
- **Chunking (quality per token)**: `eval/chunking_eval.py` over `eval/datasets/longdoc.jsonl`
28+
ingests a multi-topic corpus twice: once as one memory per document (`whole`) and once with
29+
sub-file `ChunkingExtractor` (`chunked`), then queries both through the real recall pipeline. This is
3030
the first cut of the context-reduction metric (item 3 below). On the deterministic embedder:
3131
**recall@5 1.000 for both, at ~73% fewer context tokens (809 → 219) and ~4× smaller
3232
tokens-to-evidence (162 → 42).** Pass `--embed-model sentence-transformers/all-MiniLM-L6-v2`
3333
for a real retrieval number (recall should then favour chunked on larger corpora, not just
3434
tie).
35-
- **Full-pipeline latency + quality** `eval/performance.py` times the shipped semantic +
35+
- **Full-pipeline latency + quality**: `eval/performance.py` times the shipped semantic +
3636
lexical + graph + fusion + scoring + rerank + packing path after warmup, with reinforcement
3737
disabled so repeated measurements do not mutate their corpus. It reports p50/p95/p99 latency,
3838
retrieval quality, and packed context tokens in one JSON-safe schema. `--filler-memories`

CHANGELOG.md

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -116,21 +116,21 @@ Public 1.1.0 hosted-connect and graph-experience release.
116116

117117
### Added
118118

119-
- **`engraphis connect --token engr_ct_…`** the missing client half of device connect.
119+
- **`engraphis connect --token engr_ct_…`**: the missing client half of device connect.
120120
`cloud_session.save_bootstrap()` is the only writer of `~/.engraphis/cloud_session.json`,
121121
and it had no production caller: the docs told paying customers to prefer a file nothing
122122
created, so a purchased installation could not be connected without hand-writing state.
123123
The new command redeems the one-time connect token from the account portal against
124124
`POST /v1/devices/connect`, saves the returned session with owner-only permissions, and
125125
verifies `cloud_session.configured()` before reporting success. The token is sent in the
126-
request body and nowhere elsenever printed, logged, or written to disk and every
126+
request body and nowhere else; it is never printed, logged, or written to disk, and every
127127
refusal maps to fixed, actionable copy (an expired or already-used token is not confused
128128
with a lapsed subscription). Session storage is pre-flighted before the exchange, so an
129129
unwritable state directory or a `cloud_session.json` replaced by a link fails the command
130-
*without* spending the single-use token the customer fixes the path and retries with the
130+
*without* spending the single-use token; the customer fixes the path and retries with the
131131
same token instead of returning to the portal for a new one. Faults that can only happen
132-
*after* the exchange a reply truncated mid-body (`http.client.IncompleteRead`), or an
133-
endpoint that stops resolving before the session is written (`CloudUrlUnresolved`) are
132+
*after* the exchange: a reply truncated mid-body (`http.client.IncompleteRead`), or an
133+
endpoint that stops resolving before the session is written (`CloudUrlUnresolved`) are
134134
reported as errors that say the token was already used, rather than escaping as tracebacks
135135
that leave the customer unable to tell whether to retry. Also installed as
136136
`engraphis-connect`.
@@ -328,7 +328,7 @@ and safe hosted deployment.
328328

329329
### Security
330330

331-
- Every entrypoint sends baseline response headers CSP, `X-Frame-Options: DENY`,
331+
- Every entrypoint sends baseline response headers: CSP, `X-Frame-Options: DENY`,
332332
`X-Content-Type-Options`, `Referrer-Policy`, `Permissions-Policy`, and HSTS over HTTPS
333333
only. Override with `ENGRAPHIS_CSP` / `ENGRAPHIS_HSTS`; set either to an empty string to
334334
omit that header where a fronting proxy supplies its own.
@@ -422,10 +422,10 @@ and safe hosted deployment.
422422
insert sequence (engine-level write lock): concurrent near-duplicate writes can no
423423
longer both resolve ADD and store duplicates instead of NOOP/INVALIDATE.
424424
- The Inspector's `/api/auth/login`/`setup` no longer run PBKDF2 (600k iterations)
425-
on the asyncio event loop password hashing moved to a worker thread, so a burst
425+
on the asyncio event loop; password hashing moved to a worker thread, so a burst
426426
of logins can't stall every other request.
427427
- A failed vector-index upsert on the write path is now logged and audited
428-
(`index_upsert_failed`) instead of silently swallowed — previously the memory
428+
(`index_upsert_failed`) instead of silently swallowed. Previously, the memory
429429
stayed invisible to semantic recall with no trace.
430430
- URLs built from a bind host are now IPv6-safe and connectable (`engraphis.netutil`):
431431
`ENGRAPHIS_HOST=::` no longer yields the malformed `http://:::8700` in the printed
@@ -468,7 +468,7 @@ and safe hosted deployment.
468468

469469
### Fixed
470470
- 1-hop graph recall (and the PPR large-graph fallback) now honors `graph_layers`, matching
471-
the PPR arm `Store.neighbors()` gained a `layers` filter.
471+
the PPR arm: `Store.neighbors()` gained a `layers` filter.
472472
- `FolderTransport.push()` no longer follows peer-planted symlinks in the shared sync folder
473473
(unpredictable temp name + `O_CREAT|O_EXCL|O_NOFOLLOW`), closing an arbitrary-file-write
474474
vector that mirrored the already-hardened read side.
@@ -477,7 +477,7 @@ and safe hosted deployment.
477477
- Caller-supplied `metadata.retention_supervision` is stripped at the service boundary; only
478478
the validated `retention_class` presets can influence importance/stability.
479479
- `merge_workspaces()` no longer duplicates symbols/code edges when both workspaces indexed
480-
the same file in a same-named repo the losing snapshot's rows are cleared, and its
480+
the same file in a same-named repo: the losing snapshot's rows are cleared, and its
481481
memory↔code links are re-pointed at the surviving same-fqname symbols.
482482
- `engraphis-graph impact/prs` reject leading-dash git revisions (git option injection), and
483483
graph exports refuse a symlinked output directory and are written atomically without
@@ -486,7 +486,7 @@ and safe hosted deployment.
486486
(`limit`-derived cap) so a large workspace graph or indexed repo can't produce unbounded
487487
viewer-role responses.
488488
- Relay sync fails closed when a workspace's settings are unreadable rather than treating a
489-
possibly-personal folder as shared in the sync CLI and in the dashboard/background
489+
possibly-personal folder as shared: in the sync CLI and in the dashboard/background
490490
`_sync_all` path; resource extraction enforces its own raw-size cap.
491491

492492
## [0.9.6] - 2026-07-16
@@ -574,22 +574,22 @@ and safe hosted deployment.
574574
### Changed
575575
- **Team mode is now ON by default (opt-out).** `ENGRAPHIS_TEAM_MODE` defaults to on;
576576
set `ENGRAPHIS_TEAM_MODE=0` (or false/no/off) to disable. The per-user login wall is
577-
no longer raised just because the mode flag is on — it now requires a *live* `team`
577+
no longer raised just because the mode flag is on. It now requires a *live* `team`
578578
feature entitlement (`licensing.has_feature("team")`), checked at request time in
579579
`dashboard_app.py` and reflected in `/api/auth/state`. Solo / no-license installs stay
580-
fully open, and the wall appears the moment a team license key is added even via the
580+
fully open, and the wall appears the moment a team license key is added, even via the
581581
dashboard UI at runtime. A `team` license is still required to *add seats* beyond the
582582
first admin (bootstrap admin is created unconditionally). Docs (`.env.example`,
583583
`AGENTS.md`, `README.md`, `SECURITY.md`, `scripts/init.py`) and team-mode test fixtures
584584
updated.
585585
- **Team-invite email rewritten to separate "join" from "activate a key".** The old
586586
invite conflated the two, so members pasted the shared team key into the hosted/Railway
587587
dashboard, saw it "work" (it just re-activated a license already active there), and
588-
thought they'd joined when joining means signing in with email + password. The email
588+
thought they'd joined, when joining means signing in with email + password. The email
589589
now frames two distinct options: **Option 1** (required to join) sign in to the team
590-
dashboard with email + the admin-set password explicitly *no license key needed here,
590+
dashboard with email + the admin-set password, with explicitly *no license key needed here,
591591
don't paste one*; **Option 2** (optional) run Engraphis on your own machine and access
592-
the team's memories locally that is what the shared team key is for (LOCAL
592+
the team's memories locally; that is what the shared team key is for (LOCAL
593593
`http://127.0.0.1:8700` → Settings → License, then Settings → Cloud Sync to pull the
594594
converged team store down to a local offline copy). Invites now always carry a
595595
clickable sign-in link: `dashboard_url` resolves explicit arg → `ENGRAPHIS_DASHBOARD_URL`
@@ -625,7 +625,7 @@ and safe hosted deployment.
625625
- **The dashboard (`engraphis-dashboard` / `http://127.0.0.1:8700`) would not start.**
626626
`scripts/start_dashboard.py` runs uvicorn against `engraphis.dashboard_app:app`, but
627627
`dashboard_app.py` only defined the `create_app()` factory and never built a module-level
628-
`app` instance so uvicorn aborted with `Attribute "app" not found` and nothing bound
628+
`app` instance, so uvicorn aborted with `Attribute "app" not found` and nothing bound
629629
port 8700. The missing `app = create_app()` (present in `engraphis/app.py` and
630630
`engraphis/redirector.py`, but dropped from `dashboard_app.py`) is now restored. The
631631
background autosync/dreaming/revalidation loops inside `create_app()` are pytest-guarded,
@@ -649,7 +649,7 @@ and safe hosted deployment.
649649
`tests/test_online_only_enforcement.py`.
650650
- **Deterministic, offline sub-file chunking on the write path (`ENGRAPHIS_EXTRACTOR=chunk`).**
651651
A third `Extractor` alongside passthrough/LLM: `ChunkingExtractor` splits a document into
652-
retrieval-sized `ExtractedFact` chunks that preserve meaning markdown headings start new
652+
retrieval-sized `ExtractedFact` chunks that preserve meaning: markdown headings start new
653653
chunks and become the title, fenced code blocks stay intact, prose is packed to a token
654654
budget (`ENGRAPHIS_CHUNK_TOKENS`, default 256) with a sentence-level overlap
655655
(`ENGRAPHIS_CHUNK_OVERLAP`, default 32); a hard per-document cap
@@ -667,7 +667,7 @@ and safe hosted deployment.
667667
- **Chunking eval + `longdoc` dataset.** `eval/chunking_eval.py` +
668668
`eval/datasets/longdoc.jsonl` compare whole-file vs chunked ingestion through the real
669669
recall pipeline. On the offline embedder: identical recall@5 (1.000) at **~73% fewer
670-
context tokens** (809 → 219) and ~4× smaller tokens-to-evidence (162 → 42) the "quality per token"
670+
context tokens** (809 → 219) and ~4× smaller tokens-to-evidence (162 → 42); the "quality per token"
671671
number `BENCHMARKS.md` calls for. `tests/test_chunking_eval.py`.
672672
- **"Dreaming" trigger for automated maintenance.** `automation.should_dream` / `dream_due`
673673
run a consolidation sweep *before* the cadence when enough new episodic memories have
@@ -676,7 +676,7 @@ and safe hosted deployment.
676676
cron behaviour is unchanged; still Pro-gated. `tests/test_dreaming_trigger.py`.
677677
- **Associative cross-cluster inference (dream pass 4).** `consolidate.infer_links` /
678678
`consolidate(infer=True)` proposes evidence-only links between memories in *different,
679-
dissimilar* subject clusters that share a bridging entity the "connect distant dots" step
679+
dissimilar* subject clusters that share a bridging entity: the "connect distant dots" step
680680
same-subject distillation never reaches. **Off by default** (`infer=False`); the pass
681681
follows the sweep's own `dry_run` flag, so a dry-run proposes into the report and a real
682682
run applies. Applied inferences are low-salience (`importance=0.25`), `trusted:false`,
@@ -686,13 +686,13 @@ and safe hosted deployment.
686686
`rediscovered`) and the per-sweep text scan is computed once, not per entity.
687687
`tests/test_inference.py`.
688688
- **Inference is reachable from the maintenance path.** A new `infer` policy knob (off
689-
by default) runs the inference pass inside `run_maintenance` manual *or* the dream loop
690-
following the sweep's `dry_run`. `/api/consolidate` takes `infer` (`false` by default);
689+
by default) runs the inference pass inside `run_maintenance`, whether manual or from the dream loop,
690+
following the sweep's `dry_run`. `/api/consolidate` takes `infer` (`false` by default);
691691
`/api/automation` round-trips `infer`; the dashboard Automation tab has an Inference
692692
toggle. `tests/test_dashboard_v2.py` (policy round-trip + `/maintenance/run` proposes the
693693
Redis bridge), `tests/test_dashboard_dream_ui.py`.
694694
- **Dreaming runs without cron.** A dashboard background loop (`_maybe_start_dreaming`,
695-
mirroring auto-sync) runs a maintenance sweep whenever `automation.dream_due` fires opt-in,
695+
mirroring auto-sync) runs a maintenance sweep whenever `automation.dream_due` fires. It is opt-in,
696696
Pro-gated, fault-isolated, with an `ENGRAPHIS_DREAM_LOOP=0` kill switch. The `/api/automation`
697697
policy round-trips the `dream` / `dream_min_new` / `dream_idle_minutes` knobs, and the
698698
dashboard's Automation tab surfaces them as form controls (toggle + thresholds). The
@@ -710,7 +710,7 @@ and safe hosted deployment.
710710
instance no longer deadlocks on the team-feature gate with no way to proceed.
711711
No backend change; frontend-only.
712712
- `MemoryService.create` now defaults `extractor` from `settings.extractor`
713-
(`ENGRAPHIS_EXTRACTOR`) when unsetmirroring the existing `graph_extractor` fallback so
713+
(`ENGRAPHIS_EXTRACTOR`) when unset, mirroring the existing `graph_extractor` fallback so
714714
the dashboard and automated-maintenance front ends honor the config knob, not just the MCP
715715
server and CLI. An explicit `extractor="none"` still overrides the environment.
716716

@@ -733,12 +733,12 @@ and safe hosted deployment.
733733
### Added
734734
- **Personal vs. shared folders + a redesigned Team dashboard.** A folder can now be
735735
created `visibility='personal'` (owned by, and visible/usable only to, the creating
736-
dashboard user) or `shared` (the whole team the previous, still-default behaviour).
736+
dashboard user) or `shared` (the whole team, the previous, still-default behaviour).
737737
Enforcement runs through a single workspace-authorization chokepoint, so every scoped
738738
read/write inherits it and a non-owner cannot access another user's personal folder.
739739
Personal folders are excluded from relay sync so they stay on-device. The **Team
740740
dashboard** gains a team overview (seat usage + activity), a Folders panel that creates
741-
and manages shared/personal folders (folder creation now lives here the Workspaces
741+
and manages shared/personal folders (folder creation now lives here: the Workspaces
742742
tab is selection-only in team mode), members with last-active, and a team audit log with
743743
CSV export. New/updated: `service.py`, `routes/v2_api.py`, `dashboard_app.py`,
744744
`static/index.html`; tests in `tests/test_personal_folders.py`,
@@ -761,7 +761,7 @@ and safe hosted deployment.
761761
with auth/license/trial routes instead of a permanently signed-out UI.
762762
`engraphis-server` remains available as an explicit override for single-user
763763
deployments.
764-
- **CI**: ruff lint errors and core-floor (numpy-only) test collection
764+
- **CI**: ruff lint errors and core-floor (numpy-only) test collection.
765765
fastapi-dependent tests now skip cleanly on the minimal core floor. `loads_strict`
766766
now rejects pathologically deep JSON on every Python version (3.12's JSON scanner
767767
no longer raises RecursionError for ~1000-deep input, which had broken the
@@ -825,14 +825,14 @@ and safe hosted deployment.
825825
### Fixed
826826
- Static package discovery: `engraphis/static/__init__.py` added
827827
- Vendor glob: recursive pattern so `static/vendor/` bundles ship in wheel
828-
- Dashboard 500 on `GET /` `static/index.html` was missing from wheel (packaging bug)
829-
- Dashboard 500 on fresh install `GET /api/memories` crashed on empty workspace
828+
- Dashboard 500 on `GET /`: `static/index.html` was missing from wheel (packaging bug)
829+
- Dashboard 500 on fresh install: `GET /api/memories` crashed on empty workspace
830830

831831
---
832832

833833
## Earlier versions (condensed)
834834

835-
### 0.5.x 0.7.x
835+
### Versions 0.5.x to 0.7.x
836836
- MCP server with 18 tools
837837
- Memory Inspector product UI (`engraphis-inspector`, port 8710)
838838
- Dashboard rebuilt on v2 engine with recall, governance, consolidate, analytics
@@ -846,7 +846,7 @@ and safe hosted deployment.
846846
- Docker + docker-compose deployment
847847
- 300+ tests, eval harness, ablation suite
848848

849-
### 0.1.0 2026-07-09
849+
### [0.1.0] - 2026-07-09
850850
- Initial public release: local-first AI memory engine for agents
851851
- Ebbinghaus decay, interaction-aware recall, bi-temporal facts
852852
- Background consolidation; you bring the LLM

0 commit comments

Comments
 (0)