Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ This project uses Semantic Versioning as **interpreted for MemNet**: package `a.
## [Unreleased]

### Changed
- **Honesty `c` — device MemNet services, one MemNet MCP at the droplet (tip≠face)** — Ops fleet modelled outside `MemNetSystem`: `DropletHost` hosts the one `MemNetMcpServer` (MemNet tip/ops engine face; `tipIsFace=false`; `mcpCount=1`). Product invent face is cousin SysMLEdge (`sysmledge`; `mustNotInventUploadBind`). `MemNetDeviceHost[1..*]` run `MemNetCoreLibrary`; `mcpNested=false` means no **product** MCP nested; tip `memnet-mcp` on Pi for ops is legal (`tipMcpLegal=true`). Dual-MCP remeter: product Q → `sysmledge`; MemNet tip/ops → droplet MemNet MCP and/or Pi tip. `MN-REQ-06.6` / `MN-VER-06-S03`. Not N-server federation (#47). Same goldfish loop. No Hatch bump. See [`sysml-models/outputs/device-fleet-one-mcp-case-study.md`](sysml-models/outputs/device-fleet-one-mcp-case-study.md).
- **Honesty `c` — configurable `session save` on TTL expiry** — Off unless ``MEMNET_SAVE_ON_EXPIRE``. Then explicit `session save --file` writes an expired in-RAM session (drops the id; `@WRN: session_expired_saved`). ``MEMNET_EXPIRE_SNAPSHOT_DIR`` auto-writes `{session_id}.snap` on purge/get expire. Default off: `session_expired` as before. Not Neo4j. Same goldfish loop. No Hatch bump.
- **Honesty `c` — SysML expire-save + nest review** — `SnapshotStore` / `CapsPolicy` / `CmdSessionSave` / `CmdSessionLoad` / `EvExpireTtl` match configurable TTL file save (default off; RAM drop; file until user drop; load restores; not Neo4j). `MN-VER-01-S03`. Leftover archive still off `ProjectMemNet` load; dashboard still look-only. No Hatch bump.
- **Honesty `c` — leftover archive off ProjectMemNet load** — leftover_* / TierACodec / LegacyPipe* honesty moved to `sysml-models/models/archive.sysml` (`MemNetArchive`). `config.yaml` omits that file; `root.sysml` MUST NOT import it. Product nest uses leftover flags only (not leftover_* parts under Schema / GraphStore). One-page nest: [`sysml-models/outputs/product-nest-one-page.md`](sysml-models/outputs/product-nest-one-page.md). Teach path stays GQL; dashboard remains look-only (`httpImplemented=false`, `tipIsFace=false`). Same goldfish loop. No Hatch bump.
Expand Down
12 changes: 7 additions & 5 deletions sysml-models/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ Design authority: rebuilt requirements + ADR-001 (GQL agent wire) + `docs/gramma

| File | Package | Role |
|------|---------|------|
| `models/connections.sysml` | `MemNetConnections` | SharedLlmMemory, SessionHandoff (+ CallerId / SessionBind / SessionCapability), WorkingMemorySlice, SessionImportRequest, optional ImportGuardDecision; ServeUsageLook / ImportGuardArmedLook / HumanUsagePage (ops look); application `CompanyAnalyticalSsot` / `HostSearchBridge` |
| `models/requirements.sysml` | `MemNetRequirements` | MN-REQ-00…13 (01.7/01.8, 06.4, **06.5** human usage look, 12.9–12.13, 13.1 Recall/Commit; 02.9 cousin store-key; 04.8 cue \|Q\|>1; 04.9 empty-q outline) |
| `models/connections.sysml` | `MemNetConnections` | SharedLlmMemory, SessionHandoff (+ CallerId / SessionBind / SessionCapability), WorkingMemorySlice, SessionImportRequest, optional ImportGuardDecision; ServeUsageLook / ImportGuardArmedLook / HumanUsagePage (ops look); application `CompanyAnalyticalSsot` / `HostSearchBridge` / `DeviceMemNetFleet` |
| `models/requirements.sysml` | `MemNetRequirements` | MN-REQ-00…13 (01.7/01.8, 06.4, **06.5** human usage look, **06.6** device services / one droplet MemNet MCP tip/ops, product face sysmledge, 12.9–12.13, 13.1 Recall/Commit; 02.9 cousin store-key; 04.8 cue \|Q\|>1; 04.9 empty-q outline) |
| `models/cousins.sysml` | `MemNetCousinContrast` | TARGET vs eight cousin pointing/identity designs (not a product switch; SysMLEdge is a distinct pin_map; overlay family `SysMLEdgePrj-*`; git `sysml-models/` is SSOT) |
| `models/deploy.sysml` | `MemNet` | Nested parts; `RecallCommit` two-operator cut; Multitask spine; `MemNetUsageDashboard` outside `MemNetSystem` |
| `models/deploy.sysml` | `MemNet` | Nested parts; `RecallCommit` two-operator cut; Multitask spine; `MemNetUsageDashboard` / `MemNetOpsFleet` outside `MemNetSystem` |
| `models/behaviour.sysml` | `MemNetBehaviour` | HandoffById, SessionImportReceive, Multitask async, M2.5 hydrate/flush |
| `models/verify.sysml` | `MemNetVerification` | MN-VER-12-G00 + S01…S14; MN-VER-04-S01…S04; MN-VER-09-S01; MN-VER-13-S01; MN-VER-06-S01…S02 |
| `models/verify.sysml` | `MemNetVerification` | MN-VER-12-G00 + S01…S14; MN-VER-04-S01…S04; MN-VER-09-S01; MN-VER-13-S01; MN-VER-06-S01…S03 |
| `models/root.sysml` | `ProjectMemNet` | Root imports (load last). MUST NOT import `MemNetArchive` |
| `models/archive.sysml` | `MemNetArchive` | ARCHIVE shelf (leftover_* / TierACodec / LegacyPipe*). **Off** `config.yaml` load |

Expand All @@ -49,6 +49,7 @@ MemNetSystem // SharedLlmMemory product
APPLICATION LOOK CousinPointingContrast / HostSearchBridge (outside)
ARCHIVE LOOK MemNetArchive — leftover fog shelf; root does not import
OPS LOOK MemNetUsageDashboard — look only; not agent wire
OPS FLEET MemNetOpsFleet — device MemNet services; one MemNet MCP at droplet (tip/ops; tip≠face)
```

**Happy path Multitask:** Path A shared session → re-`pin_map` (ImportGuard unused). Path B uses optional ImportGuard nest then ImportAbsorb. Hook shipped ≠ cheap LLM shipped.
Expand All @@ -65,7 +66,7 @@ OPS LOOK MemNetUsageDashboard — look only; not agent wire
- **Optional soft policy:** `ImportGuard` nest (path B): `ImportGuardHook` shipped; `CheapLlmImportGuard` shipped (#63; env-gated); happy path A = re-pin without guard
- **WorkerWriteScope:** CapsPolicy / MutateGate hard-rejects out-of-scope mutate when session ACL is enabled; overlap: serialise or **RSV** lease
- **CapsPolicy ACL (as-is):** who / pin_map-vs-mutate / WorkerWriteScope hard reject / optional bind are shipped (`engineAclShipped=true`); MutateGate, PinMapShapedRead, and SessionHandoffEmit consult; ACL is off by default
- **Out of scope:** novel-writer; EvidenceCentre / MissionDock / CompanyMemory / **HostSearchBridge** / **CousinPointingContrast** / **MemNetUsageDashboard** MUST NOT nest under MemNetSystem (optional host locators 0.17 / cousin pointing contrast / human usage look)
- **Out of scope:** novel-writer; EvidenceCentre / MissionDock / CompanyMemory / **HostSearchBridge** / **CousinPointingContrast** / **MemNetUsageDashboard** / **MemNetOpsFleet** MUST NOT nest under MemNetSystem (optional host locators 0.17 / cousin pointing contrast / human usage look / device fleet with one droplet MemNet MCP tip/ops; product face is sysmledge)
- **ARCHIVE (off ProjectMemNet load):** leftover_* / TierACodec / LegacyPipe* honesty in `models/archive.sysml` (`MemNetArchive`). Root MUST NOT import it. Engine leftover codecs may remain on disk for tests; product teach is GQL only.

### CapsPolicy ACL (as-is 0.8)
Expand Down Expand Up @@ -97,6 +98,7 @@ Two shelves (detail + principles: [outputs/README.md](outputs/README.md)). **Pro
| Snapshot passport | [outputs/snapshot-passport-case-study.md](outputs/snapshot-passport-case-study.md) |
| Empty-cue session outline | [outputs/session-outline-case-study.md](outputs/session-outline-case-study.md) |
| Human usage look (read-only dashboard; HTTP parked) | [outputs/usage-dashboard-case-study.md](outputs/usage-dashboard-case-study.md) |
| Device fleet (one MemNet MCP at droplet, tip≠face; not #47) | [outputs/device-fleet-one-mcp-case-study.md](outputs/device-fleet-one-mcp-case-study.md) |
| Durable hydrate/flush (M2.5) | [outputs/durable-hydrate-flush-case-study.md](outputs/durable-hydrate-flush-case-study.md) |

### Application examples (on SharedLlmMemory)
Expand Down
15 changes: 15 additions & 0 deletions sysml-models/models/connections.sysml
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,21 @@ package MemNetConnections {
*/
}

item def DeviceMemNetFleet {
doc /*
APPLICATION / OPS PATTERN only (MUST NOT nest under MemNetSystem):
multiple device MemNet services (MemNetCoreLibrary on Pi /
workstation) plus one MemNetMcpServer at the droplet as the
MemNet tip/ops engine face (tip≠face; mcpCount=1). Product
invent face is cousin SysMLEdge (`sysmledge`;
mustNotInventUploadBind). Device MAY run tip memnet-mcp for
ops; MUST NOT nest a second product MCP / SysMLEdge-as-product.
Each service keeps its own session registry. Handoff = session id.
MUST NOT be N-server federation (#47). See
outputs/device-fleet-one-mcp-case-study.md.
*/
}

// Retired Layer / TierA / LegacyPipe item zoo lives in models/archive.sysml
// (package MemNetArchive). Root MUST NOT import it.

Expand Down
108 changes: 105 additions & 3 deletions sysml-models/models/deploy.sysml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
│ └── Schema / Caps (size + shipped ACL) / …
// leftover_* / TierACodec / LegacyPipe* : models/archive.sysml (off ProjectMemNet load)
├── TransportBoundary // InProcess / LocalIpc / TcpServe
├── MemNetMcpServer // LLM ↔ MemNet (GQL/MCP)
├── MemNetMcpServer // MemNet tip/ops MCP (GQL); fleet: one at droplet; tip≠face
│ └── McpFacade // TARGET cue/pattern commands only
├── DurableBuffer // AgensGraphAdapter + Neo4jAdapter cabinet
│ // + optional Neo4jLibraryPort (0.16; skip unless name)
Expand Down Expand Up @@ -69,6 +69,12 @@
ImportGuard armed display). MUST NOT nest manage/mutate ports.
HTTP/UI parked (httpImplemented=false). tip is not face; not Foam
product MCP. Manage = Memnetor + Devicor.
APPLICATION / OPS FLEET (not in MemNetSystem): MemNetOpsFleet —
device hosts run MemNetCoreLibrary services; the droplet hosts
the one MemNet MCP (tip/ops engine face; tip≠face). Product invent
face is cousin SysMLEdge (`sysmledge`; mustNotInventUploadBind).
Device MAY run tip memnet-mcp for ops; MUST NOT nest a second
product MCP / SysMLEdge-as-product. Not N-server federation (#47).
APPLICATION (not in MemNetSystem): CousinPointingContrast — TARGET vs
eight cousin pointing/identity designs (sysml-models/models/cousins.sysml),
including SysMLEdge (distinct pin_map / desk; not MemNet session strata;
Expand Down Expand Up @@ -1577,19 +1583,39 @@ package MemNet {
Target core composite allocated to parts/common/memnet.
Nest: TransportBoundary (InProcessEngine owns AgentMemory) + CliFacade.
AgentMemory lives under transport.inProcess.memory — one instance.
Legal on a device host as a MemNet service without nesting a
product MCP (MN-REQ-06.6). Tip memnet-mcp on the device for
engine ops is allowed and remains tip≠face. The fleet MemNet
MCP (tip/ops) sits on the droplet; product invent face is
sysmledge (cousin; mustNotInventUploadBind).
*/
part transport : TransportBoundary;
part cli : CliFacade;
attribute deviceHostLegal : Boolean = true;

satisfy MN_REQ_00_MissionBridge::MN_REQ_06_ProcessBoundary::MN_REQ_06_6_DeviceServicesOneDropletMcp;
}

part def MemNetMcpServer {
doc /*
Product surface parts/memnet-mcp — generic tools only.
parts/memnet-mcp — generic MemNet tools only. This is the MemNet
tip/ops MCP (CompanyMemory / engine tool face). NOT the product invent face
(tip≠face; tipIsFace=false). Product LLM face is
cousin SysMLEdge (`sysmledge`; mustNotInventUploadBind).
Ops fleet: at most one fleet MemNet MCP, on the droplet host
(MN-REQ-06.6; mcpCount=1). Device hosts SHALL NOT nest a second
product MCP / SysMLEdge-as-product; a Pi MAY run tip memnet-mcp
for engine ops (still tip≠face; not sold as product).
*/
part tools : McpFacade;
part bridge : ServeBridge;
part seed : LawSeedHelper;
port fromHost : GqlWireInPort;
attribute fleetSingleton : Boolean = true;
attribute defaultHostKind : String = "droplet";
attribute tipIsFace : Boolean = false;

satisfy MN_REQ_00_MissionBridge::MN_REQ_06_ProcessBoundary::MN_REQ_06_6_DeviceServicesOneDropletMcp;
}

// =====================================================================
Expand Down Expand Up @@ -2593,15 +2619,18 @@ package MemNet {
leftover_* / TierACodec / LegacyPipeImport live on MemNetArchive
(models/archive.sysml; off ProjectMemNet load). MUST NOT nest here.
HostSearchBridge / EvidenceCentre / CousinPointingContrast /
MemNetUsageDashboard MUST NOT nest here. Only MN-REQ-00 satisfied here.
MemNetUsageDashboard / MemNetOpsFleet MUST NOT nest here. Only MN-REQ-00 satisfied here.
usageDashboardInsideSystem=false (ops look is outside; not MCP face).
opsFleetInsideSystem=false (device services + one droplet MemNet
MCP tip/ops is outside; product face is sysmledge).
*/
part core : MemNetCoreLibrary;
part mcp : MemNetMcpServer;
part durable : DurableBuffer;
part pinMaps : PinMapRoadmap;
part multitask : MultitaskOperatingModel;
attribute usageDashboardInsideSystem : Boolean = false;
attribute opsFleetInsideSystem : Boolean = false;
attribute leftoverFogNested : Boolean = false;
attribute leftoverArchiveOffLoad : Boolean = true;
attribute leftoverLayerDeleteThisPr : Boolean = false;
Expand Down Expand Up @@ -2834,4 +2863,77 @@ package MemNet {
end port source ::> memNetSystem.multitask.coordinator.importReceive.guard.cheapLlm.armedLookOut;
end port sink ::> usageDashboard.armedLookIn;
}

// =====================================================================
// OPS FLEET — MemNetOpsFleet (MUST NOT instantiate under MemNetSystem).
// Multiple device MemNet services; one MemNet MCP (tip/ops) at droplet.
// Product invent face = cousin sysmledge (tip≠face). Not #47.
// =====================================================================

part def DropletHost {
doc /*
DigitalOcean droplet. Hosts the fleet's one MemNetSystem, hence
the one MemNetMcpServer (MemNet tip/ops engine face; tip≠face)
plus local core / CompanyMemory. mcpCount=1 counts that MemNet
MCP, not the product invent face. The product LLM face on this
host is cousin SysMLEdge (`sysmledge`; MUST NOT nest under
MemNetSystem; mustNotInventUploadBind). MUST NOT add a second
product MCP on this host.
*/
part memnet : MemNetSystem;
attribute hostKind : String = "droplet";
attribute mcpCount : Integer = 1;

satisfy MN_REQ_00_MissionBridge::MN_REQ_06_ProcessBoundary::MN_REQ_06_6_DeviceServicesOneDropletMcp;
}

part def MemNetDeviceHost {
doc /*
Compute device (Pi, workstation, SBC). Hosts a MemNet service
(engine + serve + CLI) as a local notepad / device working set.
MUST NOT nest a second product MCP. MUST NOT nest
SysMLEdge-as-product on the device. mcpNested=false /
productMcpNested=false mean no product MCP nested — not a ban
on ops tip. A tip MemNet MCP (memnet-mcp) MAY run here for
engine ops and remains tip≠face (tipMcpLegal=true; not sold
as product). Session registry is this host's own; MUST NOT
mash handles with the droplet. Software-only host (no ISQ/SI).
Illustrative first device: rpi5-syson.
*/
part service : MemNetCoreLibrary;
attribute hostKind : String = "device";
attribute mcpNested : Boolean = false;
attribute productMcpNested : Boolean = false;
attribute tipMcpLegal : Boolean = true;
attribute nServerPeer : Boolean = false;

satisfy MN_REQ_00_MissionBridge::MN_REQ_06_ProcessBoundary::MN_REQ_06_6_DeviceServicesOneDropletMcp;
}

part def MemNetOpsFleet {
doc /*
OPS nest outside MemNetSystem (MN-REQ-06.6). Device hosts run
MemNetCoreLibrary services; the droplet hosts the one MemNet
MCP (tip/ops engine face; tip≠face; mcpCount=1). Product invent
face is cousin SysMLEdge (`sysmledge`; mustNotInventUploadBind).
Dual-MCP remeter: product questions → sysmledge only; MemNet
tip/ops → droplet MemNet MCP and/or Pi tip. MUST NOT answer
product questions on the MemNet tip path. Each service keeps
its own session handles. Handoff remains session id; optional
Path-B ImportAbsorb is not a live-server MERGE.
nServerFederation=false (#47 stays research).
*/
part droplet : DropletHost;
part devices : MemNetDeviceHost[1..*];
attribute mcpCount : Integer = 1;
attribute nServerFederation : Boolean = false;
attribute insideMemNetSystem : Boolean = false;
attribute fleetMcpHost : String = "droplet";
attribute productInventFace : String = "sysmledge";
attribute mustNotInventUploadBind : Boolean = true;

satisfy MN_REQ_00_MissionBridge::MN_REQ_06_ProcessBoundary::MN_REQ_06_6_DeviceServicesOneDropletMcp;
}

part opsFleet : MemNetOpsFleet;
}
36 changes: 36 additions & 0 deletions sysml-models/models/requirements.sysml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
MN-REQ-04.11 pin_map order is a function of Shape observables,
not hid / nickname id / CREATE order (gauge)
MN-REQ-06.5 Human usage look (read-only dashboard; not agent wire)
MN-REQ-06.6 Device MemNet services; one MemNet MCP (tip/ops) at the droplet; product face is sysmledge (tip≠face)
MN-REQ-11.17 Catalog Snap / model Snap — session strata (0.15)
MN-REQ-11.17.1 Cross-cut satisfy locators on the catalog; SysMLEdge
pin_map is a different tool (not this catalog)
Expand Down Expand Up @@ -667,6 +668,38 @@ package MemNetRequirements {
*/
attribute requirementId : String = "MN-REQ-06.5";
}

requirement def MN_REQ_06_6_DeviceServicesOneDropletMcp {
doc /*
A droplet-centred ops fleet SHALL run MemNet engine/serve
(MemNetCoreLibrary) on one or more device hosts (Pi,
workstation, SBC) as separate services, each with its own
session registry. The fleet SHALL instantiate at most one
MemNet MCP (MemNetMcpServer) as the MemNet tip/ops engine
face, and that MemNet MCP SHALL sit on the droplet host.
That MemNet MCP is NOT the product invent face (tip≠face;
tipIsFace=false). The product LLM face is the cousin
SysMLEdge (`sysmledge` MCP on the droplet). MUST NOT invent
upload/bind (mustNotInventUploadBind). Device hosts SHALL
NOT nest a second product MCP and SHALL NOT nest
SysMLEdge-as-product on the device. A tip MemNet MCP on a
Pi for engine ops (memnet-mcp) is allowed and remains
tip≠face (not sold as product). mcpNested=false means no
product MCP nested, not a ban on ops tip. Product questions
SHALL bind sysmledge only; MemNet tip/ops SHALL bind the
droplet MemNet MCP and/or the Pi tip. MUST NOT answer
product questions on the MemNet tip path. Each service
keeps its own session handles (two handles stay two
handles). This SHALL NOT be N-server federation (#47): no
Cypher MERGE of live servers, no requirement that hosts
share a cabinet, no mashed session ids. Handoff remains
session id; optional Path-B import into a mission session
stays ImportAbsorb, not a new pipe. Shared Multitask on
one host still uses one serve (TCP / streamable-http)
per MN-REQ-12.2.
*/
attribute requirementId : String = "MN-REQ-06.6";
}
}

// ----- MCP agent boundary -----
Expand Down Expand Up @@ -1600,6 +1633,8 @@ package MemNetRequirements {
: MN_REQ_00_MissionBridge::MN_REQ_06_ProcessBoundary::MN_REQ_06_4_DurableStoreBehindMemNet;
requirement humanUsageLookReq
: MN_REQ_00_MissionBridge::MN_REQ_06_ProcessBoundary::MN_REQ_06_5_HumanUsageLook;
requirement deviceServicesOneDropletMcpReq
: MN_REQ_00_MissionBridge::MN_REQ_06_ProcessBoundary::MN_REQ_06_6_DeviceServicesOneDropletMcp;

requirement mcpAgentBoundaryReq
: MN_REQ_00_MissionBridge::MN_REQ_07_McpAgentBoundary;
Expand Down Expand Up @@ -1819,6 +1854,7 @@ package MemNetRequirements {
end #derive ::> tcpServeMigrationReq;
end #derive ::> durableStoreBehindMemNetReq;
end #derive ::> humanUsageLookReq;
end #derive ::> deviceServicesOneDropletMcpReq;
}

#derivation connection deriveMcpLeaves {
Expand Down
Loading
Loading