diff --git a/AGENTS.md b/AGENTS.md index ac96665..5d7d8e0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,7 +4,7 @@ LLM hub for this system repo. Prefer in-repo skills and docs over ad-hoc inventi ## Mission -**MemNet** (Net of Memory) is **mission working memory** — a session graph (GQL **node**/vertex, **edge**/relationship, **property**) **between** LLM call pipelines and data search, not the corpus and not GraphRAG. Agents read a bounded **live pin map** each turn and write in the same **GQL (openCypher-shaped)** family — redefined **Write = display** via shaped subgraph emit ([`docs/grammar/gql-wire-profile.md`](docs/grammar/gql-wire-profile.md)). In-session recall is **serial**: kind/keyword cue, then `pin_map` neighbourhood. Primary read: MCP `pin_map` / CLI `query pin-map`; leftover `query_warm` / `query warm` are leftover aliases. Aims (MN-REQ-00): save wall-clock time and tokens while keeping factual accuracy. Aids **system**, **programme**, **software**, **firmware**, **hardware**, and **documentation**. Transport: **in-process first** (single-agent; TCP fallback). **Multitask** requires TCP serve or streamable-http MCP — see Multitask policy below. This repo is **engine + generic memnet-mcp** only — novel-writer dropped. Repo product **0.19.19** (Hatch SSOT; last published PyPI **`memnet-llm==0.19.18`** until this cut is uploaded; 0.19.19 honesty `c`: one-session-per-document serve readiness probe (#201) and lossless snapshot round-trip, one decoded value cap, honoured-or-refused WHERE, ACL who on save/load/close, and expire-save failures kept live (#202). Earlier `c` cuts include 0.19.18 snap_model bounded session grain (#199), 0.19.17 product-gate cap contract (#196) and admin-only serve usage report (#197), 0.19.16 shared Path-B ingest defaults 2000 nodes / 2000 edges, 0.19.15 storage role labels (#186), Path-B SysML ingest kinds (#188), Neo4j retired (#189), 0.19.14 TTL expire restore by known sid, and 0.19.11 catalog cross-session satisfy locators + CousinSysMLEdge mustNotInventUploadBind). **1.0** = 0.5–0.8 claimed (unclaimed). See `README.md`, [`docs/SHAPE.md`](docs/SHAPE.md), and `docs/grammar/`. +**MemNet** (Net of Memory) is **mission working memory** — a session graph (GQL **node**/vertex, **edge**/relationship, **property**) **between** LLM call pipelines and data search, not the corpus and not GraphRAG. Agents read a bounded **live pin map** each turn and write in the same **GQL (openCypher-shaped)** family — redefined **Write = display** via shaped subgraph emit ([`docs/grammar/gql-wire-profile.md`](docs/grammar/gql-wire-profile.md)). In-session recall is **serial**: kind/keyword cue, then `pin_map` neighbourhood. Primary read: MCP `pin_map` / CLI `query pin-map`; leftover `query_warm` / `query warm` are leftover aliases. Aims (MN-REQ-00): save wall-clock time and tokens while keeping factual accuracy. Aids **system**, **programme**, **software**, **firmware**, **hardware**, and **documentation**. Transport: **in-process first** (single-agent; TCP fallback). **Multitask** requires TCP serve or streamable-http MCP — see Multitask policy below. This repo is **engine + generic memnet-mcp** only — novel-writer dropped. Repo product **0.19.20** (Hatch SSOT; last published PyPI **`memnet-llm==0.19.19`** until this cut is uploaded; 0.19.20 honesty `c`: memnet-mcp product gateway `--transport gateway` (#203, MN-REQ-06.12). Earlier `c` cuts include 0.19.19 doc-gate readiness (#201) and snapshot / value cap / WHERE / ACL who / expire-save fixes (#202), 0.19.18 snap_model bounded session grain (#199), 0.19.17 product-gate cap contract (#196) and admin-only serve usage report (#197), 0.19.16 shared Path-B ingest defaults 2000 nodes / 2000 edges, 0.19.15 storage role labels (#186), Path-B SysML ingest kinds (#188), Neo4j retired (#189), 0.19.14 TTL expire restore by known sid, and 0.19.11 catalog cross-session satisfy locators + CousinSysMLEdge mustNotInventUploadBind). **1.0** = 0.5–0.8 claimed (unclaimed). See `README.md`, [`docs/SHAPE.md`](docs/SHAPE.md), and `docs/grammar/`. ## Where to look diff --git a/CHANGELOG.md b/CHANGELOG.md index d26c63e..124c57d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,19 @@ This project uses Semantic Versioning as **interpreted for MemNet**: package `a. ## [Unreleased] -### Added -- **Product gateway on memnet-mcp (MN-REQ-06.12)** — `memnet-mcp --transport gateway` routes by product, house, or session to one owning `memnet serve`. Hashed per-product credentials, namespace isolation, verbatim GQL / stdin / `@ERR` `@WRN` `@STAT` pass-through, gateway refusals, health with failover only for a new unpinned session, version pin, loopback or tailnet bind, per-product admin counts. Single-backend stdio and streamable-http stay unchanged when no registry is configured. No SemVer bump. Not deployed. Wire: [`docs/operations/product-gateway-contract.md`](docs/operations/product-gateway-contract.md). - ### Changed - **Invent only — ClusterRoute vs SliceHandCarry (#191 / #47 cousin)** — `MemNetTwoMoves` outside `MemNetSystem` (`MN-REQ-06.9` + `MN-REQ-06.10` / `MN-VER-06-S08`). ClusterRoute = where the session lives (`MemNetLanMcpFront`; one owner; `pin_map` / `find` SHALL NOT span backends). SliceHandCarry = explicit copy into another session (`export_pin_map` or `session_save` → LAN file copy → dest import/`session_load`; `import_slice` same-serve only). Not a live hop. `import_slice(from_url)` not shipped. tip≠face. `inventOnly=true`; `implemented=false`; no engine code; no SemVer bump. Wire: [`docs/operations/cluster-route-vs-slice-hand-carry.md`](docs/operations/cluster-route-vs-slice-hand-carry.md). - **Invent only — LAN MCP front over several serves (#191)** — `MemNetLanMcpFront` outside `MemNetSystem` (`MN-REQ-06.9` / `MN-VER-06-S07`). One MCP catalogue, N LAN `memnet serve` backends; `SessionOwnerRegistry` is owner (explicit pin allowed; silent hash is not sole routing). One owner per session; `pin_map` / `find` SHALL NOT span backends. Cousin of #47 (peer sid handoff), not the same invent. tip≠face. `inventOnly=true`; `implemented=false`; no engine code; no SemVer bump. Wire: [`docs/operations/memnet-lan-mcp-front.md`](docs/operations/memnet-lan-mcp-front.md). +## [0.19.20] - 2026-10-08 + +### Added +- **Product gateway on memnet-mcp (MN-REQ-06.12)** — `memnet-mcp --transport gateway` routes by product, house, or session to one owning `memnet serve`. Hashed per-product credentials, namespace isolation, verbatim GQL / stdin / `@ERR` `@WRN` `@STAT` pass-through, gateway refusals, health with failover only for a new unpinned session, version pin, loopback or tailnet bind, per-product admin counts. Single-backend stdio and streamable-http stay unchanged when no registry is configured. Shipped in 0.19.20 (#203). Not deployed. Wire: [`docs/operations/product-gateway-contract.md`](docs/operations/product-gateway-contract.md). + +### Changed +- **Honesty `c` — product gateway summary (#203)** — `memnet-mcp --transport gateway` reads `MEMNET_GATEWAY_CONFIG` (JSON backend registry: backend id → tailnet `host:port`; products with ordered `backends`, `houses`, `pinned_version`, credentials). `POST /gateway` with `Authorization: Bearer `; credentials are stored as SHA-256 only, per product, revocable. Namespace isolation: a product only reaches its own backends and sessions; `session list` is filtered to that product. Only `args` and `stdin` are forwarded, byte for byte; engine `@ERR` / `@WRN` / `@STAT` come back verbatim. Gateway refusals are `@ERR: gateway_|` (`auth`, `forbidden_session`, `forbidden`, `backend_unreachable`, `backend_version_mismatch`, `body_too_large`, `bad_request`, `unconfigured`) with `exit_code` 2. Version pin: every forward checks `@VER: memnet|` (cache `version_cache_s`). Health and failover: TCP + version probe; a new session with no `house`/`backend` walks the product's backends in order; a pinned or owned session never moves. Bind is loopback (default `127.0.0.1`) or tailnet (`100.64.0.0/10`, `fd7a:115c:a1e0::/48`); public bind is refused unless `MEMNET_GATEWAY_ALLOW_PUBLIC=1`. Admin counts at `GET /gateway/admin/counts`. stdio and streamable-http are unchanged. MN-REQ-06.12. Not deployed. +- **Package identity 0.19.20** — Hatch / `project.toml` / `memnet.__version__` honesty cut on **0.19**. Agent loop (`cue → pin_map → mutate`) unchanged. + ## [0.19.19] - 2026-10-08 ### Added diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 0c488c1..b050418 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -4,9 +4,9 @@ **Audience:** product developers. Dialect teach = **GQL** ([`grammar/gql-wire-profile.md`](grammar/gql-wire-profile.md)). Product shape: [`SHAPE.md`](SHAPE.md). British English. -**Package now:** Hatch **0.19.19** (`memnet.__version__`). Last published PyPI wheel is **`memnet-llm==0.19.18`** until this cut is uploaded. Numbered extras **0.10–0.19** are in this package (unchanged). **0.19.19** honesty `c` is the one-session-per-document readiness probe (#201) plus lossless snapshot round-trip, one decoded value cap, honoured-or-refused WHERE, ACL who on save/load/close, and expire-save failures kept live (#202). **0.19.18** honesty `c` was snap_model bounded session grain (#199). **0.19.17** honesty `c` was the product-gate cap contract (#196) and admin-only serve usage report (#197). **0.19.16** honesty `c` was shared Path-B ingest defaults (2000 nodes / 2000 edges). **0.19.15** honesty `c` was storage role labels (#186), Path-B SysML ingest kinds (#188), and Neo4j retired (#189). **0.19.14** honesty `c` was TTL expire restore by known sid. **0.19.11** honesty `c` was the tip roll for [#168](https://github.com/chouswei/MemNet/pull/168) (catalog cross-session satisfy locators + `CousinSysMLEdge` `mustNotInventUploadBind`; do not claim tip=face). **0.19.10** honesty `c` keeps CueConflict for MATCH_L `|Q|>1` only; codebook miss emits CueMiss / Peak_L. **0.19.9** honesty `c` maps Path-B SysML `connection` / `link` to `:CON` (teach already said CON; ingest had mapped defs to PRT). **0.19.8** honesty `c` mints leftover nicknames on **all** snapshot records (not only catalog PKG) and accepts camelCase product relations (`inFile`) so `session_save` → `session_load` round-trips mission graphs. GraphGlot parse front is on master (#109 @ 73a63c9b). Neo4j cabinet is retired (#187); **0.7** is adapter + operator round trip (no runtime caller). **1.0** is still unclaimed (0.5–0.8). +**Package now:** Hatch **0.19.20** (`memnet.__version__`). Last published PyPI wheel is **`memnet-llm==0.19.19`** until this cut is uploaded. Numbered extras **0.10–0.19** are in this package (unchanged). **0.19.20** honesty `c` is the memnet-mcp product gateway (`--transport gateway`, #203, MN-REQ-06.12). **0.19.19** honesty `c` was the one-session-per-document readiness probe (#201) plus lossless snapshot round-trip, one decoded value cap, honoured-or-refused WHERE, ACL who on save/load/close, and expire-save failures kept live (#202). **0.19.18** honesty `c` was snap_model bounded session grain (#199). **0.19.17** honesty `c` was the product-gate cap contract (#196) and admin-only serve usage report (#197). **0.19.16** honesty `c` was shared Path-B ingest defaults (2000 nodes / 2000 edges). **0.19.15** honesty `c` was storage role labels (#186), Path-B SysML ingest kinds (#188), and Neo4j retired (#189). **0.19.14** honesty `c` was TTL expire restore by known sid. **0.19.11** honesty `c` was the tip roll for [#168](https://github.com/chouswei/MemNet/pull/168) (catalog cross-session satisfy locators + `CousinSysMLEdge` `mustNotInventUploadBind`; do not claim tip=face). **0.19.10** honesty `c` keeps CueConflict for MATCH_L `|Q|>1` only; codebook miss emits CueMiss / Peak_L. **0.19.9** honesty `c` maps Path-B SysML `connection` / `link` to `:CON` (teach already said CON; ingest had mapped defs to PRT). **0.19.8** honesty `c` mints leftover nicknames on **all** snapshot records (not only catalog PKG) and accepts camelCase product relations (`inFile`) so `session_save` → `session_load` round-trips mission graphs. GraphGlot parse front is on master (#109 @ 73a63c9b). Neo4j cabinet is retired (#187); **0.7** is adapter + operator round trip (no runtime caller). **1.0** is still unclaimed (0.5–0.8). -**Last updated:** 2026-10-08 (`a.b.c` law locked; package **0.19.19** honesty `c` — doc-gate readiness (#201) and snapshot/value-cap/WHERE/ACL/expire fixes (#202); extras **0.10–0.19** unchanged; Hatch **0.19.19**; last published PyPI **`memnet-llm==0.19.18`**; do not claim **1.0**; do not invent a **0.20** extra; do not claim tip=face). +**Last updated:** 2026-10-08 (`a.b.c` law locked; package **0.19.20** honesty `c` — memnet-mcp product gateway (#203); extras **0.10–0.19** unchanged; Hatch **0.19.20**; last published PyPI **`memnet-llm==0.19.19`**; do not claim **1.0**; do not invent a **0.20** extra; do not claim tip=face). Patch notes: [`../CHANGELOG.md`](../CHANGELOG.md). CHANGELOG still follows Keep a Changelog. This file is how MemNet **interprets** SemVer — not a silent switch to npm-strict major=breaking for 0.x extras. @@ -45,7 +45,7 @@ Pure efficiency / speed on the current loop is **`0.19.c`**, not `0.20`. ### Consequences -- Package is **0.19.19**. Extras **0.10–0.19** stay the owns table below. **1.0** stays unclaimed. +- Package is **0.19.20**. Extras **0.10–0.19** stay the owns table below. **1.0** stays unclaimed. - **1.0 does not wait** on 0.19.c, efficiency, HostSearch, Peak_L, catalog Snap, N-server, or GraphGlot. - A new cabinet adapter does **not** move `a`. Hosted Agens as a product service, first-class `PORT`, and full ACL modes / `session_token` stay Later / unnumbered until a cut exists. @@ -99,8 +99,8 @@ Handoff = **session id** (+ cue / write scope). Peers **re-`pin_map`** from labe | **0.7.0** | Adapter + operator round trip (no runtime caller); `liveCabinetClaimed=true`. Server not vendored. Fake + skip unless `MEMNET_AGENSGRAPH_URL`. No runtime hydrate/flush caller | **Shipped** (`v0.7.0`); claim narrowed (#187) | | **0.8.0** | GQL-only **teach** + product **shape for people** (`SHAPE.md`, playbook, application-note contract, Multitask honesty). Docs only. **No** engine cut. Cabinet stays claimed | **Shipped** (`v0.8.0`) | | **0.9.0** | Neo4j `DurableStoreAdapter` client (`memnet-llm[neo4j]`); factory both-URL rule; [`cabinet/neo4j-buffer.md`](cabinet/neo4j-buffer.md). Live round-trip claimed later as extra **0.14**. Cabinet extra, **not** a 1.0 gate | **Shipped** (`v0.9.0` era; extras later packaged as 0.19.0) | -| **0.10–0.19** | Numbered extras (table below). Each row is one `b` (usage-method revision). Same pattern as 0.9: **not** 1.0 gates | **Packaged** (Hatch **0.19.19**; last published PyPI **`memnet-llm==0.19.18`**; extras first shipped as 0.19.0) | -| **1.0.0** | **Claim** of **0.5 + 0.6 + 0.7 + 0.8**. Shape mature for people. Not GraphRAG. Not cabinet-only. Not a new engine. This is `a=1` | **Claim when coordinator tags** — package **0.19.19** does not claim 1.0 | +| **0.10–0.19** | Numbered extras (table below). Each row is one `b` (usage-method revision). Same pattern as 0.9: **not** 1.0 gates | **Packaged** (Hatch **0.19.20**; last published PyPI **`memnet-llm==0.19.19`**; extras first shipped as 0.19.0) | +| **1.0.0** | **Claim** of **0.5 + 0.6 + 0.7 + 0.8**. Shape mature for people. Not GraphRAG. Not cabinet-only. Not a new engine. This is `a=1` | **Claim when coordinator tags** — package **0.19.20** does not claim 1.0 | | **Later** | Grammar Open / hosted product / leftover ACL; N-server research (#47); LAN MCP front invent (#191). GraphGlot parse-front is **shipped**. If **1.0 tags first**, remaining extras become **1.1, 1.2, …** with the same owns (`b` after the claim) | **Out** of 1.0 | **1.0 MAY ship from 0.9** (claim only). **0.10+ MAY ship before 1.0** as extras (`b` on `a=0`). Do not wait for the other. User-pack GQL rewrite is **sibling** (`chouswei/cursor-user-skills`), not this repo. @@ -135,7 +135,7 @@ Do **not** treat leftover 0.9 identity as a live-Neo4j claim. Do **not** claim * ## Numbered extras (0.10–0.19) -One concern per **`b`** (usage-method revision). Dependency order. **In package 0.19.0** (git tag by coordinator). Skip a `b` only if the coordinator writes the skip in CHANGELOG; do not fuse two usage-method changes into one `b`. Cuts on the same method are **`c`** (0.19.1–0.19.19). There is **no** 0.20 extra row. +One concern per **`b`** (usage-method revision). Dependency order. **In package 0.19.0** (git tag by coordinator). Skip a `b` only if the coordinator writes the skip in CHANGELOG; do not fuse two usage-method changes into one `b`. Cuts on the same method are **`c`** (0.19.1–0.19.20). There is **no** 0.20 extra row. | Version | Owns | Depends on | MUST NOT | |---------|------|------------|----------| diff --git a/parts/common/memnet/memnet/__init__.py b/parts/common/memnet/memnet/__init__.py index 1462a38..42a2a0e 100644 --- a/parts/common/memnet/memnet/__init__.py +++ b/parts/common/memnet/memnet/__init__.py @@ -1,3 +1,3 @@ """MemNet — mission working memory for LLM agents (session graph + pin_map).""" -__version__ = "0.19.19" +__version__ = "0.19.20" diff --git a/project.toml b/project.toml index 39eee61..26c6874 100644 --- a/project.toml +++ b/project.toml @@ -1,7 +1,7 @@ [project] name = "memnet" repo = "MemNet" -version = "0.19.19" +version = "0.19.20" description = "Mission working memory for LLM agents: session graph + pin_map, not a RAG corpus" # No pcba-libs pins — software-only system (see LAYOUT.md). diff --git a/tests/test_doc_gate_readiness.py b/tests/test_doc_gate_readiness.py index 8e2c7a4..2cf038e 100644 --- a/tests/test_doc_gate_readiness.py +++ b/tests/test_doc_gate_readiness.py @@ -51,8 +51,8 @@ from memnet.snapshot import SNAPSHOT_MAGIC -def test_version_is_0_19_19(): - assert __version__ == "0.19.19" +def test_version_is_0_19_20(): + assert __version__ == "0.19.20" def test_cap_contract_needles_unchanged(): diff --git a/tests/test_sysml_cluster_vs_slice.py b/tests/test_sysml_cluster_vs_slice.py index 5a049b3..5ec6ad5 100644 --- a/tests/test_sysml_cluster_vs_slice.py +++ b/tests/test_sysml_cluster_vs_slice.py @@ -111,5 +111,5 @@ def test_teach_one_screen_contrast(): def test_no_semver_bump_in_this_invent(): text = _PROJECT.read_text(encoding="utf-8") - assert 'version = "0.19.19"' in text - assert "0.19.20" not in text + assert 'version = "0.19.20"' in text + assert "0.19.21" not in text diff --git a/tests/test_sysml_lan_mcp_front.py b/tests/test_sysml_lan_mcp_front.py index e5c080c..c03c720 100644 --- a/tests/test_sysml_lan_mcp_front.py +++ b/tests/test_sysml_lan_mcp_front.py @@ -120,5 +120,5 @@ def test_teach_contrasts_47_and_worth_building(): def test_no_semver_bump_in_this_invent(): text = _PROJECT.read_text(encoding="utf-8") - assert 'version = "0.19.19"' in text - assert "0.19.20" not in text + assert 'version = "0.19.20"' in text + assert "0.19.21" not in text diff --git a/tests/test_sysml_product_gateway.py b/tests/test_sysml_product_gateway.py index 5371b2f..7b78777 100644 --- a/tests/test_sysml_product_gateway.py +++ b/tests/test_sysml_product_gateway.py @@ -64,5 +64,5 @@ def test_contract_is_not_draft_and_no_semver_bump(): assert "worthBuildingVisible=true" in nest assert "MemNetProductGateway" in nest project = PROJECT.read_text(encoding="utf-8") - assert 'version = "0.19.19"' in project - assert "0.19.20" not in project + assert 'version = "0.19.20"' in project + assert "0.19.21" not in project