@dreamforgestudiollc/emet 0.0.0-stage → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/.env.example +189 -0
  2. package/CHANGELOG.md +360 -0
  3. package/CHARTER.md +137 -0
  4. package/LICENSE +22 -0
  5. package/README.md +868 -2
  6. package/docs/AUTHORSHIP.md +26 -0
  7. package/docs/BENCHMARKS.md +261 -0
  8. package/docs/BOOTSTRAP.md +127 -0
  9. package/docs/BOTS.md +83 -0
  10. package/docs/COVERAGE.md +64 -0
  11. package/docs/DEPLOY.md +251 -0
  12. package/docs/DISCIPLINES.md +29 -0
  13. package/docs/GUARDRAILS-AND-MONORAILS.md +108 -0
  14. package/docs/GUIDED-SETUP.md +301 -0
  15. package/docs/PERMISSIONS.md +121 -0
  16. package/docs/ROADMAP.md +62 -0
  17. package/docs/SETUP.md +265 -0
  18. package/docs/SUBKEYS.md +59 -0
  19. package/gems/artifact-index.json +12 -0
  20. package/gems/bot-team-backup/floor.json +15 -0
  21. package/gems/bot-team-backup/gem.json +43 -0
  22. package/gems/bot-team-backup/guides/BOT_TEAM_BACKUP.md +27 -0
  23. package/gems/bot-team-backup/guides/BOT_TEAM_RECOVERY.md +23 -0
  24. package/gems/fieldnote/floor.json +14 -0
  25. package/gems/fieldnote/gem.json +70 -0
  26. package/gems/fieldnote/runes/fieldnote.js +4 -0
  27. package/gems/lean-six-sigma/CHANGELOG.md +10 -0
  28. package/gems/lean-six-sigma/README.md +92 -0
  29. package/gems/lean-six-sigma/floor.json +31 -0
  30. package/gems/lean-six-sigma/gem.json +1296 -0
  31. package/gems/lean-six-sigma/guides/ASSUMPTIONS.md +45 -0
  32. package/gems/lean-six-sigma/guides/BELTS.md +52 -0
  33. package/gems/lean-six-sigma/guides/DMADV.md +56 -0
  34. package/gems/lean-six-sigma/guides/DMAIC.md +127 -0
  35. package/gems/lean-six-sigma/guides/FORMULAS.md +330 -0
  36. package/gems/lean-six-sigma/guides/LEAN.md +97 -0
  37. package/gems/lean-six-sigma/guides/TEMPLATES.md +279 -0
  38. package/gems/lean-six-sigma/runes/lss_capability.js +132 -0
  39. package/gems/lean-six-sigma/runes/lss_control_limits.js +240 -0
  40. package/gems/lean-six-sigma/runes/lss_dpmo_sigma.js +81 -0
  41. package/gems/lean-six-sigma/runes/lss_hypothesis.js +298 -0
  42. package/gems/lean-six-sigma/runes/lss_sample_size.js +81 -0
  43. package/gems/neurendipity/floor.json +65 -0
  44. package/gems/neurendipity/gem.json +42 -0
  45. package/gems/neurendipity/guides/AUTISTIC_BURNOUT.md +81 -0
  46. package/gems/neurendipity/guides/NEURODIVERGENT_SUPPORT.md +287 -0
  47. package/guides/README.md +3 -0
  48. package/package.json +76 -4
  49. package/server.json +79 -0
  50. package/src/aleph.js +395 -0
  51. package/src/annotations.js +170 -0
  52. package/src/approve-throttle.js +54 -0
  53. package/src/atlas-role.js +58 -0
  54. package/src/attribution.js +555 -0
  55. package/src/conformance.js +688 -0
  56. package/src/content_analyzer.js +450 -0
  57. package/src/database.js +812 -0
  58. package/src/disciplines.js +26 -0
  59. package/src/dispatch.js +382 -0
  60. package/src/env.js +97 -0
  61. package/src/floor.js +228 -0
  62. package/src/gaps.js +509 -0
  63. package/src/gem-check.js +1359 -0
  64. package/src/guides.js +75 -0
  65. package/src/host-reach.js +23 -0
  66. package/src/http-remote.js +313 -0
  67. package/src/index.js +397 -0
  68. package/src/invites.js +167 -0
  69. package/src/layers.js +449 -0
  70. package/src/lessons-to-checks.js +366 -0
  71. package/src/logger.js +300 -0
  72. package/src/metadata.js +61 -0
  73. package/src/module-path.js +32 -0
  74. package/src/mongo-connect.js +91 -0
  75. package/src/named-items.js +208 -0
  76. package/src/oauth-provider.js +838 -0
  77. package/src/owner-approvals.js +281 -0
  78. package/src/persons.js +136 -0
  79. package/src/provenance.js +257 -0
  80. package/src/redact.js +237 -0
  81. package/src/request-log.js +124 -0
  82. package/src/rune-dispatch.js +360 -0
  83. package/src/rune-registry.js +71 -0
  84. package/src/rune-scope.js +42 -0
  85. package/src/scopes.js +100 -0
  86. package/src/security-headers.js +26 -0
  87. package/src/session-graph.js +947 -0
  88. package/src/session.js +1097 -0
  89. package/src/setup.js +1580 -0
  90. package/src/socket.js +545 -0
  91. package/src/startup-pages.js +371 -0
  92. package/src/startup-payload.js +129 -0
  93. package/src/subkey-store.js +357 -0
  94. package/src/subkeys.js +947 -0
  95. package/src/tools.js +4508 -0
  96. package/src/transcript-session.js +106 -0
  97. package/src/validation.js +1187 -0
  98. package/src/version.js +2 -0
  99. package/templates/BOARD.md +72 -0
  100. package/templates/BOTHANDOFF.md +57 -0
  101. package/templates/CHARACTER.md +30 -0
  102. package/templates/HANDOFF.md +63 -0
  103. package/templates/IDENTITY.md +29 -0
  104. package/templates/INDEX.md +82 -0
  105. package/templates/INSTALL.md +29 -0
  106. package/templates/PROCEDURE.md +39 -0
  107. package/templates/ROSTER.md +43 -0
  108. package/templates/SEED.md +65 -0
  109. package/templates/STAGING.md +37 -0
  110. package/templates/STANDARD.md +99 -0
  111. package/templates/THREAD.md +43 -0
  112. package/templates/USER.md +32 -0
  113. package/verification/load-gate/corpus.json +1765 -0
  114. package/verification/load-gate/load-gate.mjs +1246 -0
package/.env.example ADDED
@@ -0,0 +1,189 @@
1
+ # EMET configuration.
2
+ # Copy this file to .env and fill it in. .env is gitignored - never commit it.
3
+ # Real environment variables always take precedence over this file.
4
+
5
+ # ---- storage (required) ----
6
+ # Atlas: the mongodb+srv:// string from Connect -> Drivers.
7
+ # A local MongoDB (6 or later) also works: MONGODB_URI=mongodb://127.0.0.1:27017/
8
+ # Only semantic_recall needs Atlas (its vector index); everything else runs on either.
9
+ MONGODB_URI=mongodb+srv://USERNAME:PASSWORD@cluster.example.mongodb.net/?retryWrites=true&w=majority
10
+ MONGODB_DB=emet
11
+
12
+ # ---- provenance ----
13
+ # Every write records the host that made it (its source tag). Register the tags
14
+ # your hosts and bots will use, so a typo is marked, not invented. List every tag
15
+ # you will give the setup interview or pass as `source` - while this is set, a
16
+ # transcript append under a tag not listed here is refused.
17
+ # Unset = any tag is accepted, and the bot guards (bots/ folders, main records)
18
+ # are OFF. See docs/BOTS.md before adding a bot's tag.
19
+ EMET_SOURCE_TAGS=laptop,phone,cli
20
+ # A remote server shared by several hosts: do not set EMET_SOURCE_TAG - a default
21
+ # makes every host look the same; each host passes its own tag on the write.
22
+ # A server used by one host only may set its default tag:
23
+ # EMET_SOURCE_TAG=laptop
24
+
25
+ # HMAC key for signed digests. Generate once, keep only here / on your host.
26
+ # Never commit a real value. Never store it in Mongo. Unset = entries are saved
27
+ # "unsigned" (everything else works). To make one:
28
+ # node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
29
+ # EMET_SIGNING_KEY=
30
+
31
+ # Two doors for a second person into THIS store, each off unless set to 1.
32
+ # Leave both unset on a single-person assistant.
33
+ # EMET Guest Access: one-time codes for read access. Set to 1 only on a
34
+ # household or project EMET meant to be shared.
35
+ # EMET_INVITES=1
36
+ # EMET Member Access: one-time codes for a new person with read and write
37
+ # access (never the owner). Separate from guest access.
38
+ # EMET_MEMBER_ACCESS=1
39
+ # Strict login tags: a login bound to a tag may write only under that tag; a
40
+ # different declared source is refused. Off by default. Turn it on only once
41
+ # each bot has its own login (for example a Member Access code bound to its tag);
42
+ # on a shared login every other bot's writes would be refused.
43
+ # EMET_STRICT_LOGIN_TAG=1
44
+ # Delegated client sub-keys (EMET-0001). Off unless set to 1: one shared owner
45
+ # login, each bot holding its own key as a local secret. Off is no behavior
46
+ # change. First-use setup asks whether more than one bot or AI will use this
47
+ # memory. Leaving it out, or no, leaves these commented. Yes writes
48
+ # EMET_SUBKEYS=1, a generated pepper, and EMET_SUBKEY_PEPPER_VERSION=1 into
49
+ # this file only when the server reads it. A hosted deploy, where real
50
+ # environment variables are the config source, refuses that yes: set the
51
+ # three variables in the platform, then redeploy. Setup does not write a
52
+ # pepper into a container .env. Copying this example does not turn them on.
53
+ # See docs/SUBKEYS.md.
54
+ # The pepper is a server secret of at least 32 bytes, never stored in
55
+ # the database. EMET_SUBKEY_PEPPER_VERSION defaults to 1. While rotating, set
56
+ # EMET_SUBKEY_PEPPER_PREV and EMET_SUBKEY_PEPPER_PREV_VERSION so seals made
57
+ # with the previous pepper still verify. Keys last EMET_SUBKEY_TTL_DAYS
58
+ # (default 30, at most 90). A replaced key stays valid for
59
+ # EMET_SUBKEY_GRACE_MINUTES (default 10; 0 revokes it at once).
60
+ # EMET_SUBKEYS=1
61
+ # Turning EMET_SUBKEYS off ends every live sub-key session once, in the
62
+ # background at startup, when the sub-key collection already exists. The
63
+ # history event is written before the status change. Each ended session is
64
+ # kept and is not deleted. If that collection does not exist, startup does
65
+ # not create it. The sweep tries once, then a few times with backoff, and
66
+ # does not block the server accepting calls.
67
+ # With the flag off, a write that presents an emh_ handle is refused without
68
+ # opening the store. A write that names a sub-key session is refused the
69
+ # same way only when that session was live at this process's sweep. The
70
+ # refusal lasts until the next restart, by which time those sessions are
71
+ # already ended. The tool list stays the flag-off list either way.
72
+ # A store that ran the first sub-key build (rows inside emet/CLIENT_APPROVALS.md)
73
+ # still has those rows in that document's history. Production did not run it.
74
+ # EMET_SUBKEY_PEPPER=
75
+ # EMET_SUBKEY_PEPPER_VERSION=1
76
+ # EMET_SUBKEY_PEPPER_PREV=
77
+ # EMET_SUBKEY_PEPPER_PREV_VERSION=
78
+ # EMET_SUBKEY_GRACE_MINUTES=10
79
+ # EMET_SUBKEY_TTL_DAYS=30
80
+ # EMET_SUBKEY_FAIL_MAX=5
81
+ # How long a failed presentation counts, in milliseconds. Default 15 minutes.
82
+ # Values below 1000 are ignored.
83
+ # EMET_SUBKEY_FAIL_WINDOW_MS=900000
84
+
85
+ # The monorail, the server-side check on the order of a session's writes
86
+ # (docs/GUARDRAILS-AND-MONORAILS.md), runs in enforce only and has no setting:
87
+ # EMET_SESSION_GRAPH is no longer read. Every check is stored in <prefix>graph_lab;
88
+ # emet_gaps summarizes it.
89
+
90
+ # Optional. The time zone session ids are dated in (IANA name). Set it to your
91
+ # own zone, so an evening session carries your day, not UTC's. If unset, the
92
+ # default is America/New_York.
93
+ # EMET_TIMEZONE=America/New_York
94
+
95
+ # Optional. Minutes after a complete close in which the session still takes its
96
+ # ONE closing exchange (the reply sent after emet_session_close). After that one
97
+ # append, or once the window passes, the session is locked. Default 5; 0 = off;
98
+ # at most 60 (a larger value is capped at 60). A negative or non-numeric value
99
+ # is not used: the server logs a warning and uses 5. The legacy name
100
+ # CASCADE_CLOSE_GRACE_MINUTES is still read as a deprecated fallback; EMET_ wins.
101
+ # EMET_CLOSE_GRACE_MINUTES=5
102
+
103
+ # Optional. The date from which this record is held to the current rules.
104
+ # Set it and the startup line reports gaps SINCE this date beside the lifetime
105
+ # figure - the lifetime figure never falls once history is in the store; the
106
+ # since-baseline figure is the one that should trend to zero.
107
+ # EMET_GAP_BASELINE=2026-09-07
108
+
109
+ # Optional. Startup page size in bytes: emet_initialize is served in pages that
110
+ # each fit this budget (default 18000; clamped to 12000-19000). Lower it only for
111
+ # a host that cuts results shorter than the usual 20,000-byte limit.
112
+ # EMET_INIT_PAGE_BYTES=18000
113
+
114
+ # Optional. read_doc page limit in bytes as the host receives it (default 18000):
115
+ # a page ends before its JSON-escaped text plus 1,500 bytes for the rest of the
116
+ # result would pass it, on a whole character. Offsets are UTF-8 bytes.
117
+ # EMET_READ_DOC_PAGE=18000
118
+
119
+ # ---- document names (optional; defaults shown) ----
120
+ # The session handoff and the board.
121
+ # EMET_HANDOFF_DOC=HANDOFF.md
122
+ # EMET_STATE_DOC=STATE.md
123
+ # The user's host-and-machine notes.
124
+ # EMET_INSTALL_DOC=bootstrap/INSTALL.md
125
+ # The character document (character and voice). When unset, the usual
126
+ # bootstrap names are tried in order (bootstrap/CHARACTER.md first).
127
+ # EMET_CHARACTER_DOC=bootstrap/CHARACTER.md
128
+ # More record documents, beside the handoff (comma-separated ids): kept as
129
+ # superseded records, never amended. Bot handoffs are listed here, e.g.
130
+ # bots/<tag>/HANDOFF.md.
131
+ # EMET_RECORD_DOCS=
132
+ # More document-to-template mappings for validate_doc, as id=template pairs
133
+ # (comma-separated). Additive only: an entry that would change a built-in
134
+ # mapping is ignored and reported.
135
+ # EMET_TEMPLATE_MAP=
136
+
137
+ # ---- http transport only (src/http-remote.js) ----
138
+ PORT=8849
139
+ # Local use: keep the server on this machine only.
140
+ HOST=127.0.0.1
141
+ # Deploy-only (container/host behind a proxy): listen on all interfaces.
142
+ # HOST=0.0.0.0
143
+ # When deployed: must exactly match the deployed https URL - it is the OAuth issuer.
144
+ # Leave it unset to run the HTTP server on this machine; it then defaults to
145
+ # http://127.0.0.1:PORT.
146
+ # PUBLIC_URL=https://your-deployment.example.com
147
+ # Typed once per device to authorize it. This is the whole perimeter. Make it strong.
148
+ # While it is unset, the HTTP server refuses every authorization.
149
+ # EMET_OAUTH_PASSPHRASE=
150
+ # The server trusts exactly one proxy hop (Railway's edge). TRUST_PROXY is not read.
151
+ # Client ID Metadata Documents are advertised by default; 0 falls back to
152
+ # Dynamic Client Registration only (a rollback with no redeploy).
153
+ # EMET_CIMD=1
154
+ # One redacted log line per OAuth/MCP request and per error response; 0 silences it.
155
+ # EMET_REQUEST_LOG=1
156
+
157
+ # ---- optional ----
158
+ # Collection name prefix. Governs layer collections, the counters collection and the
159
+ # OAuth collections. Change only before first use - or set it to cascade_ to adopt an
160
+ # existing upstream CASCADE store in place. See docs/SETUP.md, "Migrating an existing
161
+ # CASCADE deployment".
162
+ # EMET_COLLECTION_PREFIX=emet_
163
+
164
+ # Atlas Vector Search index used by semantic_recall. Migrating installs set this to
165
+ # cascade_content_auto.
166
+ # EMET_VECTOR_INDEX=emet_content_auto
167
+
168
+ # Optional supplementary corpus searched by corpus_recall.
169
+ # EMET_CORPUS_COLLECTION=corpus_chunks
170
+ # EMET_CORPUS_INDEX=corpus_content_auto
171
+
172
+ # Comma-separated names for the optional supplementary corpus searched by
173
+ # corpus_recall. Leave unset unless you have populated a corpus yourself.
174
+ # EMET_CORPORA=
175
+
176
+ # Optional. GEM ids this install asked to turn on, comma-separated.
177
+ # Unset means a GEM activates only when its manifest says defaultOn.
178
+ # Neurendipity ships bundled and off. Set this to keep that guidance active:
179
+ # EMET_ACTIVE_GEMS=neurendipity
180
+
181
+ # Diagnostics.
182
+ LOG_LEVEL=info
183
+ LOG_FORMAT=text
184
+ # DEBUG=true
185
+ # EMET_AUDIT_LOG=
186
+ # EMET_CRASH_LOG=
187
+
188
+ # Attribution v2: the chief-of-staff bot that reviews new clients. Unset: the owner reviews them.
189
+ # EMET_COS_TAG=hub-bot
package/CHANGELOG.md ADDED
@@ -0,0 +1,360 @@
1
+ # Changelog
2
+
3
+ All notable changes to EMET are listed here, newest first. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and version numbers follow
5
+ [Semantic Versioning](https://semver.org/). EMET is still 0.x: the stored data shapes may
6
+ change before 1.0.
7
+
8
+ ## Unreleased
9
+
10
+ ## 0.2.6 - 2026-10-20
11
+
12
+ ### Added
13
+ - First-use setup can turn on delegated client sub-keys (EMET-0001). `more_than_one_bot` is optional and defaults to no. Yes writes the flag, a generated pepper and version 1 into `.env` only when that file is the config source, after the store writes succeed, and does not turn the flag on in the running process. A hosted server refuses and tells the owner to set `EMET_SUBKEYS=1`, an owner-generated `EMET_SUBKEY_PEPPER` and `EMET_SUBKEY_PEPPER_VERSION=1`, then redeploy. See `docs/SUBKEYS.md`.
14
+ - Delegated client sub-keys (EMET-0001, accepted 2026-10-15). Behind `EMET_SUBKEYS=1` (off registers nothing new): `emet_subkey_request`, `emet_subkey_claim`, `emet_subkey_revoke`, and `emet_subkey_end_session`, plus the `subkey` and `session_handle` arguments and the `declared_attribution` gap. A bot on the shared owner login presents an `emk_` key at `emet_session_open` and the one-time `emh_` session handle on later writes. The server stamps the key's tag. Keys expire after 30 days and can be reissued. Approve and revoke stay on the owner's own login. Each bot holds its key as a local secret. HMAC seals store a pepper version so the previous pepper still verifies during rotation. Records live in the subkeys collection and its history, readable by the owner and the chief of staff. Each change is a compare-and-set on that document's revision and writes only the documents it changed. History events have their own ids and a duplicate-key error is not dropped. A correct handle is never locked out; only failed presentations count, per key, per client, and per session. Each open keeps its own record. Closing a session releases it only when the caller holds that session's key and handle, checked against `receipts.transcript_session_id`. A transcript row written in that session carries `key_id`. With the flag off the tool list is unchanged. Startup ends any live sub-key session once, in the background, when that collection already exists, and a write does not open the sub-key store. A write that presents an `emh_` handle, or names a sub-key session this process has seen, is refused. An empty `EMET_SOURCE_TAGS` refuses every sub-key tag. A store that ran the first build still has sub-key rows in the `emet/CLIENT_APPROVALS.md` history; production did not run that build.
15
+ - `emet_status` reports each GEM's byte cost (`gems`): installed and active counts, active floor bytes against `MAX_ACTIVE_FLOOR_BYTES`, headroom, the enforced caps, and per-GEM id, version, kind, bytes and refusal reason. Read-only and carries no floor text; a socket failure is reported in the field and never fails the status (GEM socket PR 4).
16
+ - Optional bot-team backup, off unless the first-run interview records yes. Yes is the recommended choice. The answer is stored on `bootstrap/USER.md`. The recipe and the recovery template ship as the bundled bot-team-backup GEM. EMET does not copy prompts or settings itself. Secret values are never stored. The recorded answer accepts yes or no in the user's words. Yes and Yes. count as yes. A non-string and any other text are refused before a write.
17
+ - Lean Six Sigma 0.9.0, a bundled runed GEM, off unless `EMET_ACTIVE_GEMS=lean-six-sigma`. Its `requires.emet` is `>=0.2.6` and `released` is true. Rune file digests are unchanged. `guides/BELTS.md` is `sha256:e9e591af0e2d89a27cddf73da48e4f4acacd1785e22473d42dd3b56366d008d0`. `gem.json` is `sha256:5f9da0caf7719a73f19bfbff211002eb66dbd0f988fd094131b56c4ecf438b31` and `CHANGELOG.md` is `sha256:d07810bd35e71952cea36212b878d8762a43b4f7b8e5f710b41a4190308d86fc`, the shipped 0.9.0 copy. `gems/artifact-index.json` is unchanged.
18
+
19
+ ### Security
20
+ - `EMET_SUBKEY_PEPPER` is masked on the write path. Setup does not return it or write it into a hosted container's `.env`. A leaked active key is revoked with `emet_subkey_revoke` from the owner's login. Deny applies only to a pending request. ISO 9001 7.5.3 / ISO 13485 4.2.5 document-control wording, the Charter and the floor are unchanged.
21
+
22
+ ### Fixed
23
+ - The bot-team backup answer accepts yes or no in the user's words, the same way as the multi-bot question. Yes and Yes. record the flag. A non-string and any other text are still refused before a write.
24
+ - The socket refuses a GEM whose `gem.json` `released` is not the boolean `true` (SR-08) on every boot. `false`, the string `"true"`, `1`, and `null` fail, and the socket logs the value. A missing field is allowed only for `neurendipity` 1.2.3 and `fieldnote` 1.0.1 when the id, the version, and every file digest match the pin. A shorter file list does not match. The pin covers the id, the version, and the file digests. It does not cover every other manifest field, including `defaultOn`, `priority`, `requires`, `description`, `name`, `authors`, `license`, rune `description`, schemas, the guides list, `distribution`, `coverage`, and rune metadata other than the version. `overrides` still needs SR-05 consent. A rune `execution` of `server` and `distribution` `library` are refused by GC-02. `gem.json` is not hashed: anyone who can edit it can already add `released: true`, so hashing it would grant nothing extra. A missing field on `neurendipity` or `fieldnote` that missed the pin says `(legacy pin mismatch: version/digests)`. An unpinned GEM does not get that hint. Any other GEM missing the field is refused, including a bumped version of those two. A read error refuses and does not turn the check off. Deleting or corrupting `fieldnote` does not disable the check. Two candidates that share an id log their own refusal.
25
+ - A RUNE may import only a file under the same GEM's `runes/`. A relative import that normalizes outside `runes/`, such as `../lib/h.js`, is refused even when that file is listed. A resolved real path outside `runes/` is refused, so a symlink that leaves `runes/` cannot be imported. A symlinked GEM directory fails GC-01 (`symlink`), and that refusal is not reused for the real directory. A symlinked file under `runes/` fails GC-04 (`symlink`) and is not followed. The socket records that refusal instead of omitting the entry. A `.JS` file under `runes/` is scanned. `.cjs` is not treated as a JavaScript module.
26
+ - The deploy image and the npm package include `verification/`. `src/host-reach.js` imports the RUNE load gate from there. A release that omitted the directory crashed at startup with `ERR_MODULE_NOT_FOUND`.
27
+ - RUNE import specifiers are checked in the vendored load gate (`runeSpecifierReason`). A bare package, `node:`, a URL, `emet/rune`, a path that normalizes outside the GEM, `../` with no file list, and a relative import that is not in the passed file list are refused. gem-check calls the same function. GC-16 still allows `emet/rune`; GC-19 still names that failure. A file under `runes/` that is not `.js` or `.mjs` fails GC-16 (`rune extension`) instead of being skipped.
28
+ - The GC-19 load gate is an allowlist (`verification/load-gate/load-gate.mjs`, the file EMET-GEMs vendors with `corpus.json`). acorn 8.19.0, fail closed, no second scan. Only listed AST nodes are admitted. No `var`, and no binding may reuse a top-level name. `Math` is only a direct read or call of a listed member, never `random`, and the Math object is never stored, passed, or returned. A computed key is a literal, a `const` bound directly to a primitive literal, or a read of a top-level `Object.freeze({ __proto__: null, … })` table inside a recognized `Object.hasOwn` guard. The guarded key is one `const` that is a primitive before the guard (`const n = String(input.n)` or `Number(...)`, or a recognized `typeof` check for `'string'` or `'number'`). A const object is refused: `toString` or `Symbol.toPrimitive` can return one own key at the check and another at the read. A member, a `let`, or a parameter does not qualify. The guard's non-own-key safety rests on the table being frozen with a null prototype. `.freeze` counts only on the unbound `Object` identifier. There is no loop-index exception. Tables are not passed, spread, or returned. A member write is admitted only on an object or array born in that function. `prototype`, `Array.prototype`, `Error.prepareStackTrace`, and `RegExp.$1` fail. `toLocaleString`, `localeCompare`, `toLocaleDateString`, and `toLocaleTimeString` fail (`intl`). `Buffer`, including `Buffer.allocUnsafe`, fails (`memory`). A `for (const k of …)` key still needs `String`/`Number` or a `typeof` check. `toLocaleUpperCase`, `toLocaleLowerCase`, and a destructured locale name fail (`intl`). A computed key in a binding or assignment pattern must be a string or number literal, including nested patterns, parameters, defaults, `catch`, and `for-of`. Concatenation, a member, and a const used as that key fail. `m['call']` fails with `.call`. The checker accepts spec `2026-10-12` and optional `changelog`, `update`, `knowledge`, and `coverage`. A `coverage` list holds at most 256 entries.
29
+ - The per-RUNE description and served response wrap the `metadata.gem` value in backticks, so the sentence period is not copied with the value.
30
+ - A per-RUNE tool states the exact `metadata.gem` value (`<gem>@<version>`, for example `fieldnote@1.0.1`) in its description and in the served response. A save that does not use that form says `metadata.gem` must be `'<gem>@<version>'`.
31
+ - The serve log file `logs/gem-serves.json` keeps the latest `SERVE_CAP` (200) rows for each principal, so one caller cannot evict another. This release creates the new collection `<prefix>gem_serves` (`SERVE_COLLECTION`). Alex approved it as an append-only write site on the write-path allow-list. The collection keeps every row. Nothing is deleted. A redeploy that drops the file can still seal a result. Concurrent serves write distinct temp files, and one process records one serve at a time. Tests point the file at a temp path. The guard and the GC-19 load gate reject `vm`, `new Function`, and a computed `import()` path. When the store is not connected, the file is the only copy and a redeploy drops it. Fieldnote is off by default. See SPEC.md §10.
32
+ - Error text again replaces a stack frame with `[stack-frame]`. The publish workflow runs only on a published release. Public text no longer carries a private path, a private branch name, or an install-specific display name.
33
+ - Bot-team backup references name `gems/bot-team-backup/guides/BOT_TEAM_BACKUP.md`, the file on disk.
34
+
35
+ ### Changed
36
+ - Lean Six Sigma is 0.9.0, `released` true, `requires.emet` `>=0.2.6`. The GEM version pattern is `MAJOR.MINOR.PATCH` with no suffix. A version suffix fails GC-02. `gem.json` (`sha256:5f9da0caf7719a73f19bfbff211002eb66dbd0f988fd094131b56c4ecf438b31`) and `CHANGELOG.md` (`sha256:d07810bd35e71952cea36212b878d8762a43b4f7b8e5f710b41a4190308d86fc`) are the shipped 0.9.0 copy. The same digests are recorded in `tests/fixtures/lss-source/DIGESTS.json`.
37
+ - The socket serves RUNED code and does not run it (GEP-0003). One read-only tool per RUNE, named `gem_<gem>__<rune>`, returns the code, description, inputs, outputs, runtime, and served sha256. The server sandbox is removed. GC-19 checks the artifact hash and a static load gate: no network, no dynamic `import()`, no `eval`. A kept result is sealed on the existing write path. The principal comes from authentication. The served hash is the pin. The client-reported hash and the input hash are stored for traceability. Those attestation fields do not change on a later write. Superseded artifacts stay in `gems/artifact-index.json` by sha256. Charter commitment 1, the Extension-socket carve-out: "EMET verifies the record, not the computation. Client-executed RUNE results are recorded as attested by the client; they are replayable from recorded inputs, not re-executed by EMET." Fieldnote is off by default. ISO 9001 7.5.3 / ISO 13485 4.2.5 document-control wording is unchanged.
38
+ - Version 0.2.6. Charter commitment 1 again states the client-executed RUNE carve-out: EMET verifies the record, not the computation. ISO 9001 7.5.3 / ISO 13485 4.2.5 document-control wording is unchanged.
39
+
40
+ ### Docs
41
+ - Client-side execution of RUNED directives (GEP-0003, accepted by Alex 2026-10-16). Supersedes GEP-0002, which is kept. The socket must not run RUNE code. One read-only tool per RUNE serves that RUNE's code, inputs, outputs, description, and served hash. SPEC.md §10–12, CONFORMANCE.md GC-19, the charter commitment 1 carve-out (EMET verifies the record, not the computation) and the Extension-socket row, and `docs/gem/README.md`. ISO 9001 7.5.3 / ISO 13485 4.2.5 document-control wording is unchanged. No code change in this revision.
42
+
43
+ ## 0.2.5 - 2026-10-14
44
+
45
+ Per-session attribution with client approval, the GEM socket with the bundled Neurendipity GEM (off unless the user asks), and two new core floor lines: `goal_check` and `no_rapport_mirroring`. ISO 9001 7.5.3 / ISO 13485 4.2.5 document-control wording is unchanged. No stored data shapes change; deploy over 0.2.4.
46
+
47
+ ### Fixed
48
+
49
+ - Neurendipity 1.2.3 (the reviewer's non-blocking nit on #40). `NEURODIVERGENT_SUPPORT.md` §8 prose now reads "A meta-analysis (2026, online 2025)" to match the Vann-Adibe tag. In-text tags for Bougoure et al. and Pagán et al. now carry "(online 2025)" in both guides, matching their Sources entries. gem.json digests updated. Guides only; floor unchanged.
50
+
51
+ - Review fixes from the reviewer for #38 and #39. Floor: `no_rapport_mirroring` now reads "agree as a way to build rapport or seem attuned", allows quoting the person for accuracy, and limits the no-praise rule to "praise or rapport-building language used for effect"; `acknowledge` now acknowledges good thinking "when it is earned by substance, stated as a specific reason, not as praise", which removes the conflict between the two lines. New tests cover the protected and modifiable override paths, the wording, and the reassertion line. Neurendipity 1.2.2: the 'poor at telling current from past burnout' finding is now attributed to the prepublication AASPIRE measure, not the ABSI (AUTISTIC_BURNOUT.md); the year convention is applied to Cai 2026 (online 2025, *Autism Research* 19(2)), Vann-Adibe 2026 (online 2025, *Appl Psychophysiol Biofeedback* 51(3)), and Bougoure (online 2025); Pagán values now "were associated with" camouflaging; Ferrie comma fixed. ISO 9001 / ISO 13485 document-control wording is unchanged.
52
+
53
+ ### Added
54
+
55
+ - Core floor, engagement: `goal_check` (before multi-step work, on an ambiguous request, or when the conversation turns, state the person's goal and underlying problem in one sentence in your own words, marked as your read, and confirm; distinct from `their_own_plan`, it checks the goal underneath and never re-narrates a stated plan) and `no_rapport_mirroring` (no echoing, flattery, or agreement to build rapport or seem attuned; that is manipulation; agreement is earned by substance; state the obvious only when it adds information; default register is plain facts, with no emotional padding, praise, or rapport-building language). One matching reassertion line. `no_rapport_mirroring` is a protected override path; `goal_check` joins the modifiable list (a GEM or modifier may tune when it fires, never remove the anti-mirroring line). Targets the next public release, which must update the repo, website, README, npm package, MCP Registry entry, and description together.
56
+ - Neurendipity 1.2.1 (accuracy fixes from the reviewer's review of #37, under the owner's 2026-10-12 10:17 AM approval). Guides only; floor unchanged. Bougoure line in `NEURODIVERGENT_SUPPORT.md` rewritten (AUC 0.92 vs PHQ-9 0.78; correlates with depression and anxiety, so it does not on its own tell burnout from depression). Arnold 2023 sample limits; Osborne described as 14 studies with qualitative data synthesised; Pagán 'was associated with' and therapy-programme recruitment; van Asselt scope and no intervention studies; Vann-Adibe effect label, heterogeneity and moderator scope; Comerford UK-only and 'a sense of community'; Ferrie & Hafetz sample limits, service line tagged as a suggestion; Clarey author initials. One year convention stated (issue year, online year in brackets); Pagán cited as 2026 (online 2025).
57
+ - Neurendipity 1.2.0 (the owner's approval 2026-10-12 10:17 AM). Guides only; floor unchanged. `AUTISTIC_BURNOUT.md`: measurement (Arnold 2023 ABSI, Bougoure 2026), shame and dual masking (Clarey 2026), camouflaging as energy cost and unmasking as a balancing act (Osborne 2026), culture (Pagán 2025). `NEURODIVERGENT_SUPPORT.md`: RSD scoping review findings (van Asselt 2026) and self-compassion validity (Cai 2025) in §3; Osborne and Pagán in §6; interoception meta-analysis (Klein 2025) and remote HRV biofeedback meta-analysis (Vann-Adibe 2025) in §8; Comerford 2026 and Ferrie & Hafetz 2026 in §9. Support only, not counseling or treatment.
58
+ - Attribution per session, v2 (replaces the reverted #32). Agents sharing one OAuth login are stamped with the tag they declare (`source_basis: declared`, `source_login` kept), but a declared tag never gains rights beyond the login's tag: every guard runs for both. Every write naming a session is checked against the tag that owns the session, rebuilt after a restart from the session's stored rows. New clients: the first write by an unknown tag is refused and queued in `emet/CLIENT_APPROVALS.md` with who connected, the declared name, client_id and what it tried to write, routed to the chief-of-staff bot (`EMET_COS_TAG`) or, with none set, to the owner. A first, solo client on a fresh store is approved at once as the owner's primary. New tool `emet_client_approve`. `emet_initialize` and `emet_status` report the caller's real tag and, to the owner or COS, the pending clients.
59
+
60
+ - The GEM socket (`src/socket.js`) and `gem-check` (`src/gem-check.js`). This release seats bundled prompt GEMs only. A refused GEM is listed with its check id and does not stop startup. An empty mount logs nothing. A seating summary is logged only when a GEM is installed. RUNE execution is not implemented and is refused. No new runtime dependency.
61
+ - Neurendipity, the bundled GEM at `gems/neurendipity` (reading people, the neurodivergent engagement lines, the wellbeing corpus lines, the matching reassertion lines, and the guide). It is off unless the install sets `EMET_ACTIVE_GEMS=neurendipity`. `emet_floor` takes a `gem` argument to read an installed GEM's floor without turning it on. The guide id `guides/NEURODIVERGENT_SUPPORT.md` still resolves to that GEM's copy for one release.
62
+
63
+ ### Changed
64
+
65
+ - The core floor keeps persistence (named items, including what was set aside on purpose), a general epistemic-honesty line (established, emerging, or anecdote), the epistemic corpus lines, and the honesty protections. An active GEM ranks below the floor and below the user's current word. Neurodivergent engagement is no longer on every install.
66
+
67
+ ### Docs
68
+
69
+ - README and website: version 0.2.5; a GEM socket fact; the website gains a Document control (ISO 9001 7.5.3 / ISO 13485 4.2.5) fact in the README's words; the tool count is 30 with `emet_client_approve` (docs/PERMISSIONS.md lists it with the tools that can replace or hand out access).
70
+ - GEM standard, Draft revision 2026-10-11, in `gem-library/` (canonical home: the private repository EMET-GEMs). The charter's extension socket, commitment 8, and the core-floor row are revised: EMET is a memory resource, core floor protections stay non-removable, and neurodivergent engagement is the bundled Neurendipity GEM, off unless the user asks.
71
+ - Registering a bot (`docs/BOTS.md` §4, with a pointer in `docs/DEPLOY.md`): every bot writes under its own source tag, `<prefix>-<bot>`. When a bot joins the roster, append its tag to the end of `EMET_SOURCE_TAGS`, keep every existing tag in order, and add `bots/<tag>/HANDOFF.md` to `EMET_RECORD_DOCS` before its first write. Setting either variable redeploys the server; afterwards, check `/health` and `emet_status`.
72
+
73
+ ## 0.2.4 - 2026-10-08
74
+
75
+ A board fix, a public website, and the first npm package, `@dreamforgestudiollc/emet`. A session that boots with no unhandled drops can edit the board again. No data shapes or settings change; deploy over 0.2.3 as is.
76
+
77
+ ### Added
78
+
79
+ - A static website in `site/`, for search, and a GitHub Actions workflow that publishes that folder to GitHub Pages on pushes to `main`.
80
+ - `glama.json` at the repo root names `dreamforgestudiollc` as maintainer for the Glama directory listing.
81
+ - The README records the origin in the same words as the site: EMET was built by Dreamforge Studio LLC from a neurodivergent user’s own need for an AI assistant that remembers. The word coined for that is neurendipity: neurodivergent and serendipity.
82
+ - The public-scrub suite reads the Pages workflow's deploy job `if` and requires it to be exactly `github.repository == 'dreamforgestudiollc/EMET' && github.ref == 'refs/heads/main'`. A repository name that only contains that text, such as `dreamforgestudiollc/EMET-private`, does not pass.
83
+ - The same suite requires `site/sitemap.xml`, `site/robots.txt`, `site/.nojekyll`, and every image the site HTML references to be present on the scrub and publish walk. Removing one of those files fails the suite.
84
+ - `server.json` for the Official MCP Registry. Its name is `io.github.dreamforgestudiollc/emet`, the same value as `mcpName` in package.json. The npm package it names is the stdio server at version 0.2.4.
85
+ - The pack test reads the text inside the tarball. On a scrubbed tree, an install-specific name in any packed file fails it. On this private tree that check waits, because the publish scrub has not rewritten those files yet.
86
+ - The site image check fails a root-relative `/EMET/` image URL, a protocol-relative URL, a JSON-LD image in one of those forms, and a path that climbs out of the repository. A second Pages job with no `if` fails the deploy gate.
87
+
88
+ ### Changed
89
+
90
+ - The README now opens with the search line and a short account of what EMET does, in the same words as the website: an MCP (Model Context Protocol) memory server, persistent shared memory for AI agents, bot teams and chats. The previous opening paragraph, including how to connect a single-session chat, is kept below that.
91
+ - package.json is prepared for a public npm release at version 0.2.4. The package name is now `@dreamforgestudiollc/emet`. It was `emet-mcp-server`. npm refused the unscoped name `emet` at publish as too similar to existing package names, so the package uses the documented scoped fallback with `"publishConfig": { "access": "public" }`. `server.json` names the same package. The command it installs is still `emet`. `@black-knight.dev/emet` is a different server that also installs a command named `emet`. Keywords match the public GitHub topics. `repository`, `homepage` (`https://dreamforgestudiollc.github.io/EMET/`), and `bugs` point at the public project. `bin` and `main` stay `src/index.js`. `engines` stays Node 20 or newer. The `files` list ships the server, the charter, templates, guides, top-level docs, the changelog, the registry manifest, and `.env.example`. It does not ship tests, scripts, `docs/status/`, backups, or `.env`.
92
+
93
+ ### Fixed
94
+
95
+ - A session that boots with no unhandled drops can edit or restore the board. The empty list was not saved, so the board guard treated it as a list that had failed to load. A list that really failed to load is still refused. Retired drops stay off that list.
96
+ - A module file is opened from `fileURLToPath` and `path.resolve`. On Windows, `new URL(...).pathname` is `/C:/...`, and resolving that against a `C:` working directory produced `C:\C:\...` and the open failed.
97
+ - `.env.example` no longer assigns `TRUST_PROXY`. The server trusts exactly one proxy hop (Railway's edge) and does not read that variable.
98
+ - The example environment that ships is the public one. It listens on `127.0.0.1`, registers the generic tags `laptop,phone,cli`, and leaves `EMET_OAUTH_PASSPHRASE` commented out, so HTTP authorization stays refused until someone sets a passphrase. The pack test fails if the packed example assigns a passphrase, binds `0.0.0.0`, or names this install's source tags.
99
+
100
+ ## 0.2.3 - 2026-10-07
101
+
102
+ The security fixes from the October audit, recall that ranks by how well an entry matches and keeps ended entries visible, and public wording that matches the code. Read the 0.2.3 checklist in docs/DEPLOY.md before upgrading: every host tag must be listed in `EMET_SOURCE_TAGS`, a `cloud-scheduled-` tag is refused, and an HTTP client whose token has no source tag signs in again once.
103
+
104
+ ### Security
105
+
106
+ - The client-metadata fetch connects to the public address it already checked. A second DNS answer cannot move that connection onto a private, loopback, link-local, or metadata address. A redirect is still refused.
107
+ - That address check uses the parsed bits of the address. The whole link-local range `fe80::/10` is refused, including `fe90::` and `febf::`. The same check refuses loopback, private, unique-local, unspecified, multicast, IPv4-mapped and IPv4-compatible addresses, NAT64 `64:ff9b::/96`, and carrier-grade NAT. An unreachable pinned address rejects the fetch and does not crash the process.
108
+ - Every HTTP response sends `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, `Referrer-Policy: no-referrer`, and HSTS. The consent page keeps its own content security policy.
109
+ - `save_transcript` no longer reads a file path. The caller passes the exchanges, each field is capped, and the whole request is capped. The server does not read the disk for a transcript.
110
+ - An invite code, an authorization code, and a refresh token can be spent once. A second redeem does not create a second person. Inside a short grace window a repeated refresh returns the replacement already issued; any other reuse revokes that whole sign-in.
111
+ - A board edit or restore runs only when the session has a verified drop list from `emet_session_open`. An append does not open that session. No write may shrink a document below half of its largest size in the last 24 hours. That window is a floor on cuts, not a fading of memory.
112
+ - A refusal does not publish the list of source tags, and a `cloud-scheduled-` prefix is not a registered tag. Over HTTP the source tag is the one bound at approval. Stdio stamps one local subject, and the 20-drop cap is one bucket for the whole local process.
113
+ - Setup, guest invites, and member codes are the owner's. A guest invite is read-only. Opening a session, and a status check that probes the write path, need write access. The probe removes its own document and leaves the collection. An HTTP token with no scopes is not the owner. The consent page shows the scopes it is granting.
114
+ - A governed write that names a session stops when the session record cannot be read. Nothing is written.
115
+ - The client-metadata fetch refuses loopback, private, link-local, and metadata addresses, and it is rate limited. Tool rate limits are per person and client. The HTTP body limit is 256kb, and the server trusts one proxy hop.
116
+ - The consent page sends a content security policy, denies framing, and sends HSTS. Error details are not attached on HTTP, including a rate-limit response. The audit log is redacted the same way as the console.
117
+ - A token issued before source tags were stored may still write when the caller names a tag that is an exact member of `EMET_SOURCE_TAGS`. Refreshing that token is refused (`invalid_grant`): the client signs in again, and the new consent binds a registered tag. Those logins age out on their own. An empty registry has no members, so that fallback does not accept an arbitrary tag.
118
+ - The local stdio client is the owner and can create guest and member codes. Over HTTP those codes still require an owner person. A member code can carry a registered source tag, set by the owner when the code is created and bound when the code is redeemed.
119
+ - A later verified `emet_session_open` clears `drops_unverified` when the drop load succeeds, including when open drops remain. Only a failed drop load sets the flag. An open drop still has to be retired before the board is edited.
120
+
121
+ ### Fixed
122
+
123
+ - Session start lists the half-finished, dated, open, undecided, and parked rows it can read (`named_items`). A section that is not a table is marked unread, including prose such as "None". Unread is not an empty list: the session still reads the document. An empty list is not a reason to skip the document. Nothing is hidden, and nothing is dropped because it is old.
124
+ - The handoff refusal names `patch_doc` for the board. Restoring the board counts as the board step.
125
+ - Recall orders matches by how many of your words appear, then by importance. Current entries come first in every order, including time order. Pass `order: 'latest'` for time order. A standalone "latest", "newest", or "most recent", together with other words, reorders those matches and does not change which rows match. "latest-budget", "not the latest", and a bare "latest" are ordinary keywords.
126
+ - An entry that has expired or been superseded stays in recall and in layer queries. It is marked with the date it ended and, when a newer entry replaced it, which one. The current entry is listed first, including when you ask for the latest or sort by time. Pass `history: true` when you need the ended entries and the current ones already fill the limit.
127
+ - Revising an entry records the end date and the new entry's id on the old one. The old entry stays readable.
128
+ - Retired documents stay in the document list and in the startup scan, after the current ones, marked with the date they were retired and what replaced them. A retired drop is listed apart from the drops that still need a decision.
129
+ - A recall or a layer query ranks matching rows in the store before it keeps a bounded window (at least 200 rows, or 20 times the page). The rank is the same as the page: current entries first, then how many words match and importance, or time when you asked for the latest. A better match is not dropped for a lower importance or an older time. A blank sort value comes first when the order is ascending and last when it is descending. A word is matched as itself, so `$gt` is that text. Capital and lower case count as the same match, including `École` and `école`. `İ` matches only itself. Full-width letters fold only with their full-width counterparts. `ẞ` and `ß` fold together. The page keeps the store's hit count, so the two do not disagree. The sort may use disk so a layer of large entries can finish.
130
+
131
+ ### Changed
132
+
133
+ - The public wording now matches the code on who can join (one owner; Guest is read-only and Member is read and write; both stay off until turned on), on the drop-cap buckets, and on working documents (`retire_doc` refuses them; a rename marks the old id retired and the text stays). The charter states the monorail is enforce only, and that a templated write is checked, marked, and kept as the current revision.
134
+
135
+ ### Internal
136
+
137
+ - Tests now pin the guards a mutation check left unasserted, and the MCP SDK and proxy-addr dependencies are updated.
138
+ - Session close prunes size baselines only for sessions closed or idle more than 7 days, and only those keys. A live session's baseline on a document is not touched.
139
+ - An HTTP caller with no OAuth client id is stored as http:visitor, never in a stdio bucket.
140
+ - The test suite sets the boot-list store timeout short so a missing store does not stall the run.
141
+ - The HTTP visitor check calls the HTTP tool path with no OAuth client id, and the baseline prune check leaves a document with only live or fresh baselines unwritten.
142
+ - Reviewers now have a checklist (`REVIEW.md`), and pull requests and pushes to main run the test suite with coverage (`.github/workflows/ci.yml`).
143
+
144
+ ## 0.2.2 - 2026-10-04
145
+
146
+ The board is guarded, and the test store is shared.
147
+
148
+ - A session cannot wipe or overwrite the board. The server sets up a blank board, and a session can only edit it, with a reason. An added item says where it came from. A removed or closed item says why.
149
+ - No change may leave a document under half the size it had when this session first touched it. Overlapping edits and a walk-down across edits are refused. Working documents are edited, not retired.
150
+ - A board edit or restore is refused while a drop listed at that session's boot is still open. Drops are capped at 20 per caller per New York day. A drop with no source is stored as visitor.
151
+ - An owner-listed host can restore an earlier version of the board or a working document, with a reason, when the copy matches its stored hash. A record is not restored. A shipped copy is never restored.
152
+ - Every write records the person and the connected app, stamped by the server from the login, never taken from the caller.
153
+ - A read-only token can initialize and open a session. A missing board is provisioned only for a write-scoped caller, or at setup.
154
+ - The test suites share one in-memory store. No behavior change.
155
+
156
+ ## 0.2.1 - 2026-10-03
157
+
158
+ Startup comes in pages that fit every host, every startup carries a `load_id`, long documents
159
+ are read in byte-sized pages, and the session-order check now refuses every skipped step, with
160
+ the way to pass in the same reply. After upgrading, each host reconnects once to see the new
161
+ arguments, then reads its startup again before opening a session.
162
+
163
+ ### Added
164
+
165
+ - **Startup in pages.** `emet_initialize` now sends the startup in pages of about 18 KB
166
+ each, so it fits hosts that cut long tool results short. The rules and instructions that
167
+ must always be followed come first. Page 1 lists what every page carries, and each page
168
+ names the exact call for the next one. Every page of one startup comes from the same
169
+ snapshot, even if new memories are written in between. If the startup changes partway
170
+ through, the server says so and you start again from page 1. `page: "all"` still returns
171
+ the whole startup in one result for hosts with no size limit, led by its `load_id`. The page size can be set
172
+ with `EMET_INIT_PAGE_BYTES` (12,000–19,000 bytes, default 18,000). Hosts may need to
173
+ reconnect once to see the new `page` and `load_id` arguments. A `page` that isn't a whole
174
+ number from 1, or `"all"`, is refused with a clear message.
175
+ - **Missing-page check when a session opens.** `emet_session_open` checks that every page
176
+ of your startup was fetched, named by the `load_id` from your startup pages. An open with
177
+ a page missing is refused (see Changed).
178
+ - `.env.example` now lists every setting the server reads. New entries include
179
+ `EMET_MEMBER_ACCESS`, the page-size settings, the document-name overrides,
180
+ `EMET_RECORD_DOCS`, `EMET_TEMPLATE_MAP`, `EMET_CIMD` and `EMET_REQUEST_LOG`.
181
+ - `CHANGELOG.md` (this file).
182
+ - **`read_doc` version pin.** Pass the `version` (or `sha256`) your first page returned as
183
+ `expected_version` (or `expected_sha256`) with each later page. If the document changed
184
+ in between, the read is refused with "document changed - restart from offset 0" and no
185
+ content, so pages of two versions are never joined. The pin is optional; without it a read
186
+ works as before. A shipped guide has no version, so pin it by `sha256`.
187
+
188
+ ### Changed
189
+
190
+ - **The session-order check now refuses every skipped step.** It runs in enforce only: there
191
+ is no report mode and no off switch, and `EMET_SESSION_GRAPH` is no longer read (remove it
192
+ from the service's variables). A skipped step is refused before anything is written, and
193
+ the refusal is recorded in `emet_gaps`. Every refusal says how to pass in the same reply:
194
+ an open with no `load_id` is told to pass it from the startup pages; a missing startup page
195
+ is named with the exact `emet_initialize` call; a skipped exchange is named with the
196
+ `emet_transcript_append` call; a write with no session is told to open one with
197
+ `emet_session_open` and its `load_id`; a write to a closed session is told the work belongs
198
+ in the next session; an early handoff names each step and its tool. A session id the caller
199
+ sent is echoed at most 64 characters, so the instruction always fits. A transcript write
200
+ with a missing or unregistered `source` is told first to pass one, then which tags are
201
+ accepted: the first 8 registered tags, then "+N more", and the caller's tag capped at 64
202
+ characters, so the refusal stays under the cap with any number of registered tags. One exception stays: if
203
+ the check cannot read the records of the session a write names, the write goes ahead and is
204
+ recorded as `unknown`.
205
+ Writes that name no session (for example the scheduled weekly intake) are now refused
206
+ (gate `no_session`) until they open a session.
207
+ - The startup sends each memory layer's importance band once instead of twice, which saves
208
+ a little space at the start of every session.
209
+ - **`read_doc` pages are now measured in bytes, as the host receives them.** A long
210
+ document comes back in pages (was 40,000 characters). A page ends before its text, written
211
+ as JSON (where every newline, quote and backslash costs an extra byte), plus 1,500 bytes
212
+ kept for the rest of the result would pass the limit (default 18,000). So a page of
213
+ quote-heavy, code-like or short-line text holds less document text than a page of prose.
214
+ The 1,500 bytes is an allowance, not a measurement: a result whose other fields run longer
215
+ (for example a long list of conformance failures) can still pass 18,000 bytes, and a host
216
+ that cuts at about 20,000 bytes is not guaranteed the whole result in every case. A page
217
+ never splits a character. `offset`, `next_offset`, `returned` and `size` in the `page`
218
+ block are UTF-8 bytes; `returned_escaped` is the page's size as JSON, and `envelope_spare`
219
+ is the 1,500. Following `next_offset` still gives back the whole document exactly. The
220
+ result's whole-document `size` stays in characters; `size_unit` says so and `size_bytes`
221
+ gives the UTF-8 bytes. `EMET_READ_DOC_PAGE` sets the limit (default 18000).
222
+ - **Startup pages say to fetch them all before opening a session.** Page 1 and every page
223
+ that names a next call now say "Fetch all N pages before emet_session_open; an open with
224
+ any page not fetched is refused." The line replaces the older "keep calling until a page
225
+ says it is the last", and binding text stays where it was.
226
+ - **Missing startup pages go through the session-order check.** `emet_session_open` passes
227
+ a `startup_pages` gate: an open with a page of its startup never fetched is refused,
228
+ nothing is written, and the reply leads with the exact call for the first missing page and
229
+ names the missing pages once, as ranges (`2-40`), so it fits the 500-character error cap
230
+ however many pages are missing. A `load_id` the server has no record of (made up, expired
231
+ 60 minutes after its last page, or from before a restart) is refused too, since its pages
232
+ cannot be checked: the reply says to call `emet_initialize {}`, fetch every page and open
233
+ with the `load_id` it returns. After a server restart each host does that once.
234
+ The record of fetched pages now keeps up to 2,000 loads for 60 minutes after each load's
235
+ last page (the page cache still keeps 32 payloads for 10 minutes), so many hosts starting at
236
+ once, or a host that opens a while after reading its startup, still open.
237
+ - **A session open must name its startup.** Pass the `load_id` from your startup pages
238
+ (`startup_page.load_id`; every page carries it and the last page names it) to
239
+ `emet_session_open`, so the page check runs on your own startup, never on another host's.
240
+ It stays optional in the tool schema, but an open without it is refused before anything is
241
+ written and told to pass it. The server no longer falls back to the latest startup it built.
242
+ - **Every startup carries a load_id, so every host can open a session.** A startup served
243
+ whole - `page: "all"`, a startup that fits one result, and a store that is not set up yet
244
+ (or cannot be reached, or is misconfigured) - now leads with `startup_page` (`index`, `of: 1`,
245
+ `load_id`, `next: null`) and a `page_notice` that says to pass that `load_id` to
246
+ `emet_session_open`. The load is recorded with every page fetched, so the open passes the
247
+ page check. The payload after those two fields is unchanged, byte for byte, and its `load_id`
248
+ is the same one its pages carry. The startup tests' byte-for-byte pins now compare the payload
249
+ after pinning the two leading fields exactly. On a new store the setup flow opens a session
250
+ with that `load_id`, appends, records the interview with `emet_setup_complete` (which never
251
+ needs a session) and closes as usual.
252
+ - When EMET Guest Access and EMET Member Access are both off, the refusal message now
253
+ names both and the setting that turns each one on.
254
+ - The README explains that Grok Bot teams and single-session Grok chats on the same server
255
+ share one memory: what the bots save is there for a fresh chat to find once it
256
+ initializes, and the reverse. A single-session chat uses that memory most reliably when the
257
+ instruction block from `docs/BOOTSTRAP.md` is in its project instructions, or, where there is
258
+ no such field, pasted as its first message.
259
+ - The server reports version 0.2.1.
260
+ - The README has a short "Best practices" section: split the work by what each host does
261
+ best, with a single-session chat for long one-sitting drafting and review and bots for the
262
+ rest. The one line you send the chat names the document that holds the task.
263
+ - The README says how to connect a single-session chat: add the server's `/mcp` URL as a
264
+ remote MCP connector on a host that supports its OAuth sign-in, sign in with the passphrase,
265
+ then put the `docs/BOOTSTRAP.md` block in the project instructions.
266
+ - The README's Best practices section adds eight short entries: fetch every startup page and
267
+ open with its `load_id`; set `EMET_SOURCE_TAGS` before a second writer; put the instruction
268
+ block in the project's instructions; standing approval for reads; reconnect after a tool-list
269
+ change; register a bot in one change; prove the write path with `probe: true`; keep house
270
+ style in the store.
271
+ - In the public release, the shipped `CHARTER.md` and nine base templates carry no internal
272
+ ids; the meaning is unchanged. An install whose stored charter is the public 0.1.0 text is
273
+ reported as differing from the shipped copy until it is rewritten with `write_doc`.
274
+ - **The startup and the docs say to open a session with the startup's `load_id`.** The
275
+ startup's short instructions read "After every startup page, call emet_session_open with
276
+ its load_id", and `tools_in_force` reads "emet_session_open with the startup's load_id, after
277
+ every startup page". On a live-sized store the five pages, as received, are 17,301, 17,864,
278
+ 13,778, 14,033 and 5,560 bytes; every page stays within the 18,000-byte page budget, and a
279
+ test checks it. The bot session loop in `docs/BOTS.md` starts with `emet_initialize {}` and
280
+ every page it names (`{"page": "all"}` only on a host known to read long results whole) and
281
+ opens with that `load_id`; the README, the paste-in block in `docs/BOOTSTRAP.md` and the bot
282
+ handoff template say the same.
283
+ - `docs/DEPLOY.md`'s rollback note says what each `EMET_SESSION_GRAPH` value does on the
284
+ older build, and `docs/ROADMAP.md` records the enforce-only monorail and paged startup as
285
+ deployed.
286
+
287
+ ### Fixed
288
+
289
+ - In `emet_gaps`, session-order results now show the source tag of memory saves and
290
+ revisions (they showed none before), and flagged document writes now name the document.
291
+ - The README and the permissions guide now give the correct tool count: 28 tools, 12 of
292
+ them read-only.
293
+ - The "Known gaps" entry about the scheduled weekly intake is rewritten in plain words and
294
+ matches how such writes are handled now.
295
+ - The upstream project EMET is built from can no longer be reached at its old address.
296
+ The credit is kept as it was, with a note that the link is unavailable.
297
+ - The README, the setup and guided-setup guides, the deploy guide and the message at the end
298
+ of setup no longer say to set a distinct `EMET_SOURCE_TAG` per host. On a server several
299
+ hosts share it stays unset: each host passes its own `source`, and `EMET_SOURCE_TAGS`
300
+ registers the tags, as `.env.example` already said. A default tag is only for a server one
301
+ host uses.
302
+ - `emet_session_close` takes `source`, and the close is never refused for it. The close is
303
+ attributed only to a registered tag that wrote the session (the `source` passed, else the
304
+ server's default tag); otherwise it warns and says why: no tag, a tag not registered in
305
+ `EMET_SOURCE_TAGS`, or a tag that did not write the session. The tag is echoed capped at
306
+ whole characters. It used to warn on every close on a server with no default tag, even when
307
+ the host passed a registered tag of its own.
308
+ - The bot handoff template's session loop now says to fetch every startup page, with
309
+ `{"page": "all"}` only on a host known to read long results whole, as `docs/BOTS.md` does.
310
+ - The setup interview's note for a store that is already initialized now says a second
311
+ `emet_setup_complete` is refused unless `reissue: true` is passed. It said a re-run would
312
+ create a new version.
313
+
314
+ ### Security
315
+
316
+ - Updated three dependencies to patch releases that fix moderate advisories: `fast-uri`
317
+ 3.1.8, `hono` 4.13.12 and `ip-address` 10.7.3. No direct dependency changed.
318
+ - New tests confirm that a code is refused before any lookup when both access doors are
319
+ off, that the owner's sign-in still refreshes, and that a database outage is reported
320
+ as a server error (500), not as a bad sign-in.
321
+
322
+ ## 0.1.0 - 2026-10-02
323
+
324
+ The first public release.
325
+
326
+ ### Added
327
+
328
+ - **A shared memory server for MCP.** One store in MongoDB (Atlas or self-hosted) that
329
+ several hosts can read and write: desktop and command-line apps, browser and phone
330
+ clients, and assistants from other vendors.
331
+ - **Six memory layers and a word-for-word transcript tier.** Curated memories and the
332
+ conversations behind them are kept apart, so neither can quietly overwrite the other.
333
+ - **Every write is checked.** Each write is read back and compared before it is reported
334
+ as saved. Each memory carries a content digest (and a signature, when a signing key is
335
+ set), and each layer forms a hash chain that `emet_gaps` can walk end to end.
336
+ - **Corrections without deletion.** Memories and transcripts are corrected by superseding
337
+ them, never by editing or deleting them. Documents can be changed, but every earlier
338
+ version is kept in their history, and they are retired rather than deleted.
339
+ - **A versioned document store** with templates, a conformance check and a full revision
340
+ history.
341
+ - **Session start and close.** One call to `emet_initialize` gives the assistant everything
342
+ it needs at the start; `emet_session_open` starts the transcript. Closing a session
343
+ requires receipts for each record it was supposed to update.
344
+ - **A session-order check** that watches the order of a session's writes. It ships in
345
+ report mode: it flags what it would refuse and blocks nothing.
346
+ - **Local or remote.** The same code runs as a local stdio server or as a remote HTTP
347
+ server with OAuth sign-in, protected by a passphrase you choose.
348
+ - **Two optional access doors, both off by default.** EMET Guest Access gives a second
349
+ person read access; EMET Member Access gives a new person read and write access, never
350
+ the owner's identity. Each person's sign-in only refreshes while its own door is on.
351
+ - **Source tags.** Every write records which host made it. Registering the allowed tags
352
+ with `EMET_SOURCE_TAGS` turns on the guards against unknown or mistyped tags.
353
+ - **Least-privilege database access.** A script and guide for a database role that can add
354
+ and update records but never delete them.
355
+ - **Secrets masked before storage.** Common secrets such as API keys, tokens and
356
+ passwords in connection strings are masked in content before it is saved.
357
+ - **Clear sign-in errors.** An expired, revoked, replaced or unknown sign-in is answered as
358
+ a sign-in problem (401 or 400) that tells the app to sign in again, not as a server error.
359
+ - 28 tools, 12 of them read-only, each labelled with standard MCP hints so a host can tell
360
+ reads from writes (and, if it chooses, skip approval for reads).