@dreamforgestudiollc/emet 0.2.4 → 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 (101) hide show
  1. package/.env.example +53 -0
  2. package/CHANGELOG.md +67 -3
  3. package/CHARTER.md +19 -7
  4. package/README.md +106 -21
  5. package/docs/AUTHORSHIP.md +3 -3
  6. package/docs/BOTS.md +4 -0
  7. package/docs/COVERAGE.md +2 -2
  8. package/docs/DEPLOY.md +9 -4
  9. package/docs/GUARDRAILS-AND-MONORAILS.md +2 -1
  10. package/docs/GUIDED-SETUP.md +8 -3
  11. package/docs/PERMISSIONS.md +6 -3
  12. package/docs/ROADMAP.md +25 -22
  13. package/docs/SETUP.md +8 -2
  14. package/docs/SUBKEYS.md +59 -0
  15. package/gems/artifact-index.json +12 -0
  16. package/gems/bot-team-backup/floor.json +15 -0
  17. package/gems/bot-team-backup/gem.json +43 -0
  18. package/gems/bot-team-backup/guides/BOT_TEAM_BACKUP.md +27 -0
  19. package/gems/bot-team-backup/guides/BOT_TEAM_RECOVERY.md +23 -0
  20. package/gems/fieldnote/floor.json +14 -0
  21. package/gems/fieldnote/gem.json +70 -0
  22. package/gems/fieldnote/runes/fieldnote.js +4 -0
  23. package/gems/lean-six-sigma/CHANGELOG.md +10 -0
  24. package/gems/lean-six-sigma/README.md +92 -0
  25. package/gems/lean-six-sigma/floor.json +31 -0
  26. package/gems/lean-six-sigma/gem.json +1296 -0
  27. package/gems/lean-six-sigma/guides/ASSUMPTIONS.md +45 -0
  28. package/gems/lean-six-sigma/guides/BELTS.md +52 -0
  29. package/gems/lean-six-sigma/guides/DMADV.md +56 -0
  30. package/gems/lean-six-sigma/guides/DMAIC.md +127 -0
  31. package/gems/lean-six-sigma/guides/FORMULAS.md +330 -0
  32. package/gems/lean-six-sigma/guides/LEAN.md +97 -0
  33. package/gems/lean-six-sigma/guides/TEMPLATES.md +279 -0
  34. package/gems/lean-six-sigma/runes/lss_capability.js +132 -0
  35. package/gems/lean-six-sigma/runes/lss_control_limits.js +240 -0
  36. package/gems/lean-six-sigma/runes/lss_dpmo_sigma.js +81 -0
  37. package/gems/lean-six-sigma/runes/lss_hypothesis.js +298 -0
  38. package/gems/lean-six-sigma/runes/lss_sample_size.js +81 -0
  39. package/gems/neurendipity/floor.json +65 -0
  40. package/gems/neurendipity/gem.json +42 -0
  41. package/gems/neurendipity/guides/AUTISTIC_BURNOUT.md +81 -0
  42. package/{guides → gems/neurendipity/guides}/NEURODIVERGENT_SUPPORT.md +17 -8
  43. package/guides/README.md +3 -0
  44. package/package.json +11 -5
  45. package/server.json +44 -4
  46. package/src/aleph.js +4 -4
  47. package/src/annotations.js +38 -3
  48. package/src/atlas-role.js +1 -1
  49. package/src/attribution.js +555 -0
  50. package/src/conformance.js +2 -2
  51. package/src/database.js +6 -5
  52. package/src/dispatch.js +116 -13
  53. package/src/env.js +54 -9
  54. package/src/floor.js +82 -41
  55. package/src/gaps.js +39 -6
  56. package/src/gem-check.js +1359 -0
  57. package/src/guides.js +31 -4
  58. package/src/host-reach.js +23 -0
  59. package/src/http-remote.js +46 -2
  60. package/src/index.js +9 -2
  61. package/src/layers.js +1 -1
  62. package/src/lessons-to-checks.js +3 -3
  63. package/src/logger.js +2 -1
  64. package/src/mongo-connect.js +45 -2
  65. package/src/oauth-provider.js +2 -2
  66. package/src/owner-approvals.js +281 -0
  67. package/src/persons.js +20 -0
  68. package/src/redact.js +10 -4
  69. package/src/request-log.js +1 -1
  70. package/src/rune-dispatch.js +360 -0
  71. package/src/rune-registry.js +71 -0
  72. package/src/rune-scope.js +42 -0
  73. package/src/scopes.js +3 -0
  74. package/src/session-graph.js +25 -23
  75. package/src/session.js +9 -9
  76. package/src/setup.js +297 -30
  77. package/src/socket.js +545 -0
  78. package/src/startup-pages.js +23 -6
  79. package/src/startup-payload.js +9 -6
  80. package/src/subkey-store.js +357 -0
  81. package/src/subkeys.js +947 -0
  82. package/src/tools.js +299 -62
  83. package/src/transcript-session.js +1 -1
  84. package/src/validation.js +26 -2
  85. package/src/version.js +1 -1
  86. package/templates/BOARD.md +2 -2
  87. package/templates/BOTHANDOFF.md +2 -2
  88. package/templates/CHARACTER.md +1 -1
  89. package/templates/HANDOFF.md +1 -1
  90. package/templates/IDENTITY.md +1 -1
  91. package/templates/INDEX.md +19 -19
  92. package/templates/INSTALL.md +1 -1
  93. package/templates/PROCEDURE.md +1 -1
  94. package/templates/ROSTER.md +2 -2
  95. package/templates/SEED.md +2 -2
  96. package/templates/STAGING.md +2 -2
  97. package/templates/STANDARD.md +5 -5
  98. package/templates/THREAD.md +1 -1
  99. package/templates/USER.md +4 -1
  100. package/verification/load-gate/corpus.json +1765 -0
  101. package/verification/load-gate/load-gate.mjs +1246 -0
package/docs/DEPLOY.md CHANGED
@@ -22,6 +22,9 @@ passphrase; both are required.
22
22
  | `PUBLIC_URL` | yes | The public **https** base URL. This is the OAuth issuer and must match the deployed URL exactly. |
23
23
  | `EMET_OAUTH_PASSPHRASE` | yes | Typed once per device to authorize it. Make it strong — it is the only thing between the internet and your memory. |
24
24
  | `EMET_SOURCE_TAG` | optional | Default tag for a write that passes no `source`. Leave it unset on a server several hosts share (see below); set it only when one host uses this deployment. |
25
+ | `EMET_SUBKEYS` | when more than one bot shares the owner login | `1` turns on delegated client sub-keys. On this kind of host, set it in the platform's variables. Setup refuses to write a pepper into the container `.env`. Restart or redeploy so the tools and `/owner/approvals` appear together. See [SUBKEYS.md](SUBKEYS.md). |
26
+ | `EMET_SUBKEY_PEPPER` | with that flag | Server secret, at least 32 bytes, generated by the owner on a hosted deploy (`openssl rand -hex 32`). Not stored in the database. |
27
+ | `EMET_SUBKEY_PEPPER_VERSION` | with that flag | `1` until the pepper is rotated. Set it with the other two, then redeploy. |
25
28
  | `EMET_TIMEZONE` | optional | IANA time zone that session ids are dated in, e.g. `America/Chicago`. Default `America/New_York`. An unknown name falls back to the default and `emet_session_open` says so. |
26
29
  | `EMET_CLOSE_GRACE_MINUTES` | optional | Minutes after a complete close in which a session still takes its one closing exchange (the reply sent after the close). Default `5`; `0` turns the window off; at most `60` (a larger value is capped at 60). A negative or non-numeric value is not used: the server logs a warning and uses `5`. |
27
30
  | `EMET_GAP_BASELINE` | optional | ISO date (or Unix seconds) from which the record is held to the current rules. The startup line then reports gaps since that date beside the lifetime figure. |
@@ -33,6 +36,8 @@ passphrase; both are required.
33
36
  Read this before you deploy the release that follows 0.2.2. It does not change a version number. It is the list of settings and client habits that will start failing if you leave them as they were.
34
37
 
35
38
  - **`EMET_SOURCE_TAGS` must list every real host tag**, as an exact member. Tags named in this repository's example env, docs, and live-tag checks are: `cli`, `mobile`, `desktop-host`, `cloud-host`, `project-host`, `hub-bot` (the hub; do not also list it in `EMET_RECORD_DOCS`), `reviewer-bot`, `tester-bot`, `memory-bot`, `intake-bot`, and `research-bot`. Your install may use a shorter list. A tag that is not an exact member is refused, and the refusal does not print the list.
39
+ - When a new bot joins the roster, append its tag to the end of `EMET_SOURCE_TAGS` and keep every existing tag in order, before its first write. The standing rule, including `EMET_RECORD_DOCS` and the `/health` and `emet_status` check after the redeploy, is [BOTS.md](BOTS.md) §4.
40
+ - **`EMET_STRICT_LOGIN_TAG=1`** (off by default) makes a login's bound tag final: a write that declares a different `source` is refused, and so are `emet_setup_complete` and `emet_initialize` with a mismatched tag. Leave it off while bots share one login, because with it on every bot except the login's own would be refused. Turn it on only once each bot has its own login, for example a Member Access code bound to its tag.
36
41
  - **A scheduled job that still sends a `cloud-scheduled-` prefix must switch to an exact registered tag.** `cloud-scheduled-intake` was retired on 2026-10-02. A prefix is not a tag. The weekly intake runs under `intake-bot`.
37
42
  - **An HTTP client whose stored token has no source tag must sign in again.** Refresh of that token is refused. The new consent binds a registered tag. An empty registry has no members.
38
43
  - **Caps already in force.** A client that used to send more is refused, and nothing is written:
@@ -99,8 +104,8 @@ pages each host fetched is kept in the server's memory for 60 minutes after its
99
104
  after every deploy or restart, or a longer pause, an open with an older `load_id` is refused once
100
105
  and told to call `emet_initialize {}` again.
101
106
 
102
- There is no setting to turn the monorail's refusals off. In an emergency, redeploy the previous
103
- release, git tag `v0.1.0`, and check EMET_SESSION_GRAPH first: unset or report flags
107
+ There is no setting to turn the monorail's refusals off. In an emergency, redeploy private main
108
+ as it stood before this release (commit-9bf9096) and check EMET_SESSION_GRAPH first: unset or report flags
104
109
  skipped steps without blocking them (a closed session still takes no new exchanges, and a
105
110
  session-store outage still blocks transcript writes and `emet_session_open`); enforce keeps
106
111
  refusing; off stops consulting the graph, including the closed-session lock, so a closed session
@@ -160,7 +165,7 @@ the legacy `CASCADE_...` name as a deprecated fallback (the `EMET_` name wins wh
160
165
  `EMET_SOURCE_TAG`, `EMET_SOURCE_TAGS`, `EMET_OAUTH_PASSPHRASE`, `EMET_AUDIT_LOG`, `EMET_HANDOFF_DOC`,
161
166
  `EMET_STATE_DOC`, `EMET_INSTALL_DOC`, `EMET_CHARACTER_DOC`, `EMET_TEMPLATE_MAP`, `EMET_RECORD_DOCS`,
162
167
  `EMET_READ_DOC_PAGE`, `EMET_SIGNING_KEY`, `EMET_GAP_BASELINE`, `EMET_CIMD`, `EMET_INVITES`,
163
- `EMET_TIMEZONE` and `EMET_CLOSE_GRACE_MINUTES`. These read `process.env` directly, so **only the
168
+ `EMET_TIMEZONE`, `EMET_CLOSE_GRACE_MINUTES` and `EMET_ACTIVE_GEMS`. These read `process.env` directly, so **only the
164
169
  `EMET_` name works** and a `CASCADE_` name is ignored: `EMET_COLLECTION_PREFIX`,
165
170
  `EMET_VECTOR_INDEX`, `EMET_CORPUS_INDEX`, `EMET_CORPORA`, `EMET_CORPUS_COLLECTION`,
166
171
  `EMET_REQUEST_LOG` and `EMET_CRASH_LOG`. (`MONGODB_URI`, `MONGODB_DB`, `PUBLIC_URL`, `PORT`, `HOST`,
@@ -222,7 +227,7 @@ you saved elsewhere. If the remote host sees what the laptop wrote, the deployme
222
227
 
223
228
  ## Notes
224
229
 
225
- - **Release note: startup stage 1 (the host-aware startup amendment).** Three behaviour changes take effect
230
+ - **Release note: startup stage 1 (the ref 358 amendment).** Three behaviour changes take effect
226
231
  live on deploy:
227
232
  - **Re-running setup is refused.** `emet_setup_complete` on a store where both
228
233
  `bootstrap/IDENTITY.md` and `bootstrap/USER.md` already exist is refused unless the call passes
@@ -79,7 +79,7 @@ The architecture needs flexibility of flow: at some points a session should go o
79
79
  - **Like a transistor (an IGBT).** A switch conducts only when its gate condition is met, and it is tripped by that condition, nothing else. The condition is read from what EMET already holds: the session's state, the call being made, and what the record says. The branch it selects is where the session goes next.
80
80
  - **Small and local.** A switch is a few lines of logic in the server's code. No hosted model, no outside API, no model call. It gives the same answer for the same inputs, every time, so it can be tested like any other gate. This is the role a fast external decision model (such as JEV) plays in other designs, done here by the track itself.
81
81
  - **Designed per junction.** Each switch's design follows the function it serves and how information and tasking flow through that junction. There is no general-purpose router: a junction gets a switch only when a real fork exists, and the switch knows only what that fork needs (commitment 6: over-engineering is a defect).
82
- - **Bounded on every branch.** Each branch leads to a guardrail space, for example a GEM once the socket exists, or a work instruction for a kind of task. The four gates still apply on every branch, so a switch can change where the session works, never whether its steps are recorded.
82
+ - **Bounded on every branch.** Each branch leads to a guardrail space, for example a GEM (Golem Expertise Module) once the socket exists, or a work instruction for a kind of task. The four gates still apply on every branch, so a switch can change where the session works, never whether its steps are recorded.
83
83
  - **Recorded.** Each time a switch trips, the lab results record which way it went and why, so its conditions can be checked against real sessions before anything depends on them.
84
84
 
85
85
  ### Lab results
@@ -105,3 +105,4 @@ The server sees tool calls, never the reply text. It can confirm that exchange 8
105
105
  - `src/tools.js`: `session_id` and `exchange` added to every governed schema from the graph's own tool list.
106
106
  - `src/setup.js`: `tools_in_force` and the short instructions tell every host to pass both fields and follow `session_graph.next`.
107
107
  - `tests/session-graph.test.js`: the gates, the next stop, and the fail-closed door when a named session cannot be read.
108
+ - Design record: `staging/emet-session-graph.md` in the EMET store. The framing is in semantic memory entry 297, and the decision on switches in procedural ref 402.
@@ -103,7 +103,7 @@ and report plainly. Read all of Part B before running anything.
103
103
  ### Stage 0 — check the ground
104
104
 
105
105
  ```
106
- node --version # need 20+ (package.json engines); 22 preferred
106
+ node --version # need 22+ (package.json engines)
107
107
  npm --version
108
108
  git --version
109
109
  ```
@@ -267,9 +267,14 @@ deployment is real.
267
267
  Say nothing about setup. Call `emet_initialize`. On a new store it returns `setup_required` and
268
268
  the interview questions. Ask them **conversationally, one at a time** — what the assistant should
269
269
  be called and how it should carry itself, the person's name in the form they want used, what the
270
- memory is for, and optionally how they want to be worked with and this host's tag. Then
270
+ memory is for, whether more than one bot or AI will use this memory (yes or no, in their words),
271
+ whether to turn on bot-team backup (yes or no, in their words; Yes and Yes. count as yes; **yes is the recommended choice**; no, or leaving
272
+ it out, leaves it off and the answer is recorded), and optionally how they want to be worked with
273
+ and this host's tag. Then
271
274
  `emet_setup_complete`. It refuses partial answers rather than inventing an identity; that is
272
- correct behaviour.
275
+ correct behaviour. Bot-team backup does not copy prompts or settings, and secret values are never stored.
276
+
277
+ If they answer **no**, or they skip it, leave sub-keys off. If they answer **yes** on the local server that reads `.env`, `emet_setup_complete` writes the flag, a generated pepper, and version 1 into that file after the store writes succeed. The result does not contain the pepper. Do not paste it into the chat. Tell them to restart (or redeploy) the server once. If they answer **yes** against the hosted server, the call refuses before it saves anything. No pepper or .env was written. Tell them to run setup again without yes to finish the rest, and to follow the platform-variable steps in [SUBKEYS.md](SUBKEYS.md): set `EMET_SUBKEYS=1`, an `EMET_SUBKEY_PEPPER` they generate (at least 32 bytes), and `EMET_SUBKEY_PEPPER_VERSION=1`, then redeploy. Do not copy a pepper out of the server. Each bot's tag must be listed in `EMET_SOURCE_TAGS`. The rest is [SUBKEYS.md](SUBKEYS.md).
273
278
 
274
279
  Then hand the person the short instruction block from [BOOTSTRAP.md](BOOTSTRAP.md) to paste
275
280
  into their project instructions, so future sessions consult the memory without being told.
@@ -37,7 +37,7 @@ Every tool carries MCP annotations, declared in one table in `src/annotations.js
37
37
  | `idempotentHint` | Calling it again with the same arguments changes nothing further. |
38
38
  | `openWorldHint` | It reaches systems outside this server's own store. |
39
39
 
40
- Of the 29 tools:
40
+ Of the 30 tools (`EMET_SUBKEYS=1` adds the four sub-key tools below; with the flag off they are not registered):
41
41
 
42
42
  - **11 are read-only.** `emet_gaps`, `emet_floor`, `recall`, `semantic_recall`,
43
43
  `corpus_recall`, `query_layer`, `query_transcripts`, `read_doc`, `read_doc_history`, `list_docs`,
@@ -47,8 +47,9 @@ Of the 29 tools:
47
47
  records blocked attempts), `rename_doc`, `accept_nonconformance`. They add; they do not remove or replace.
48
48
  `emet_session_open` still needs the `emet.write` scope, because it stamps the drop list a board edit trusts.
49
49
  `emet_initialize` stays a read.
50
- - **6 can replace what is already there, or hand out access.** `write_doc`, `patch_doc`, `restore_doc`, `emet_setup_complete`,
51
- `emet_invite_create`, `emet_member_access_create`. Prior versions of a document are archived to the history
50
+ - **7 can replace what is already there, or hand out access.** `write_doc`, `patch_doc`, `restore_doc`, `emet_setup_complete`,
51
+ `emet_invite_create`, `emet_member_access_create`, `emet_client_approve` (it admits or refuses a new client).
52
+ Prior versions of a document are archived to the history
52
53
  collection first, but the visible content a person may be relying on is replaced. A code that grants access
53
54
  is marked the same way: it is not a harmless add.
54
55
  - **1 marks a document obsolete.** `retire_doc`. Neither a removal nor a replacement: the
@@ -61,6 +62,8 @@ Of the 29 tools:
61
62
  detect a broken write path. A read-scoped token may call it without `probe`. With `probe: true` it needs
62
63
  `emet.write`. The probe deletes only that document. It does not drop the collection.
63
64
 
65
+ With `EMET_SUBKEYS=1` the host also receives four tools: `emet_subkey_request`, `emet_subkey_claim`, and `emet_subkey_end_session` (additive), and `emet_subkey_revoke` (it retires a key's authority; the record stays). Write tools gain `session_handle`. `emet_session_open` and `emet_session_close` gain `subkey`. With the flag off those names and fields are absent. First-use setup turns the flag on only when the owner says yes and the server reads `.env`. A hosted server refuses that yes. A single client stays on the flag-off list. See [SUBKEYS.md](SUBKEYS.md).
66
+
64
67
  **`openWorldHint` is false on every tool.** The tools talk to this server's configured database
65
68
  and nothing else: no filesystem and no shell. The sign-in server fetches a client's metadata
66
69
  document, and only from a public address it has already checked. That is the main reason a memory
package/docs/ROADMAP.md CHANGED
@@ -1,46 +1,52 @@
1
1
  # EMET — Next Steps and Proposed Features
2
2
 
3
- Status as of 2026-10-07. This is a working roadmap, not a commitment: items move when the owner rules on them. Nothing here is built unless it says so.
3
+ Status as of 2026-10-11 (last full report: [status/2026-09-29-state-of-the-system.md](status/2026-09-29-state-of-the-system.md)). This is a working roadmap, not a commitment: items move when the owner rules on them. Nothing here is built unless it says so.
4
4
 
5
5
  ## Where things stand
6
6
 
7
- - **Live:** 29 tools (11 read-only); layer writes and reads native to MongoDB; server-side checks on session start and close (machine line on the first transcript append, blocked-close cap with scope, pending lessons at startup); receipts required at close; the handoff is a record, superseded and never amended.
7
+ - **Live:** 30 tools (11 read-only); `EMET_SUBKEYS=1` adds four sub-key tools. Layer writes and reads native to MongoDB; server-side checks on session start and close (machine line on the first transcript append, blocked-close cap with scope, pending lessons at startup); receipts required at close; the handoff is a record, superseded and never amended.
8
8
  - **The aleph** verifies every write by reading it back before any receipt, and every later read by its digests, signature and place in its layer's hash chain. `emet_gaps` walks the whole chain for any host.
9
9
  - **Guardrails & Monorails** ([docs/GUARDRAILS-AND-MONORAILS.md](GUARDRAILS-AND-MONORAILS.md)): the server checks the order of a session's writes. Enforce only since 0.2.1 (deployed 2026-10-03; report mode 2026-09-29 to 2026-10-03): every skipped step is refused with the way to pass, and every check is stored as a timestamped lab result.
10
10
  - **The database** login runs under the least-privilege role `emetRecordKeeper`: it can insert and update, never remove the record.
11
11
  - **Startup load:** since 0.2.1, `emet_initialize` is served in pages of at most 18,000 bytes as received (on a live-sized store, five pages totalling about 68 KB as received, or about 64 KB whole), so a host that cuts long results short still reads all of it; `page: "all"` returns it whole on a host with no size limit.
12
+ - **GEM standard:** drafted 2026-10-11, revision Draft. The socket seats bundled prompt GEMs. Neurendipity is installed at `gems/neurendipity` and off unless `EMET_ACTIVE_GEMS` names it. The text is in [`gem-library/`](../gem-library/README.md). Canonical home: private repository [EMET-GEMs](https://github.com/dreamforgestudiollc/EMET-GEMs).
12
13
 
13
14
  ## Next steps, in order
14
15
 
15
16
  1. **Monorail: enforce only** (decided and deployed 2026-10-03, release 0.2.1). Every skipped step is refused and the refusal says how to pass; there is no report mode or off switch. Every host and scheduled routine must now read its startup, open a session with its `load_id`, and pass the `session_id` on its writes.
16
17
  2. **Admission test on the proposed items.** Every proposed feature below answers the four questions of charter commitment 6 before it is built (2026-09-30 read: the compiled-pages pilot passes; the lint pass needs a named measure; hybrid search, graph links and confidence scores do not pass yet).
17
18
  3. **Initialize payload trim.** Character document trim; measure the payload again.
18
- 4. ~~**Register or retire the `cloud-scheduled-intake` source tag.**~~ Retired 2026-10-02 (the owner, a decision record, item 7): it is a legacy tag; the weekly intake now runs under `intake-bot`, with no `session_id` on its writes; under enforce-only those writes are refused (`no_session`) until it opens a session with its startup's `load_id` (item 1). The existing rows keep counting as ambiguous in `emet_gaps` rather than being re-attributed, and the count stops growing as long as nothing new is written under the old tag. The prefix `cloud-scheduled-<task>` does not count as registered. Only an exact tag in `EMET_SOURCE_TAGS` is accepted, and a refusal does not publish the list.
19
- 5. **Monorail switches.** Small logic at each junction where a session's flow must fork, routing it to the right guardrail space: tripped only by its condition, like a transistor; no hosted model, no API; each designed from the function it serves and the flow of information and tasking through it ([GUARDRAILS-AND-MONORAILS.md](GUARDRAILS-AND-MONORAILS.md), decided 2026-09-29). First candidate junctions come with the socket, where a switch picks the GEM.
20
- 6. **The socket** — see below.
19
+ 4. ~~**Register or retire the `cloud-scheduled-intake` source tag.**~~ Retired 2026-10-02 (Alex, procedural ref 405 item 7): it is a legacy tag; the weekly intake now runs under `intake-bot`, with no `session_id` on its writes; under enforce-only those writes are refused (`no_session`) until it opens a session with its startup's `load_id` (item 1). The existing rows keep counting as ambiguous in `emet_gaps` rather than being re-attributed, and the count stops growing as long as nothing new is written under the old tag. The prefix `cloud-scheduled-<task>` does not count as registered. Only an exact tag in `EMET_SOURCE_TAGS` is accepted, and a refusal does not publish the list.
20
+ 5. **Monorail switches.** Small logic at each junction where a session's flow must fork, routing it to the right guardrail space: tripped only by its condition, like a transistor; no hosted model, no API; each designed from the function it serves and the flow of information and tasking through it ([GUARDRAILS-AND-MONORAILS.md](GUARDRAILS-AND-MONORAILS.md), decided 2026-09-29). A switch that picks a GEM waits for its own proposal. It is not one of the socket phases below.
21
+ 6. **The socket.** Phased plan under GEM socket, below. The standard is drafted. The socket, Neurendipity, and RUNED execution are in the tree. A RUNED GEM stays off unless the install names it. Activation beyond `EMET_ACTIVE_GEMS` is not.
21
22
 
22
23
  ## Done since the last revision (2026-09-28)
23
24
 
24
- - SQL translator stage 2: read path native to MongoDB; the translator and the `event` mirror column removed.
25
- - Test-tree pass: one shared harness; dated suites named by subject.
25
+ - SQL translator stage 2: read path native to MongoDB; the translator and the `event` mirror column removed (commit-017c7f3).
26
+ - Test-tree pass: one shared harness; dated suites named by subject (commit-7980e20).
26
27
  - Open questions answered 2026-09-29: the lessons `shadow` block dropped, the lesson key checked at the door; a coverage number published as an input to review; the character document consolidated quarterly (first pass done, SOUL.md v7).
27
- - Chain verification: one MongoDB connection path with a DNS fallback, then the chain walk moved into `emet_gaps` so no host needs the repo or a shell.
28
- - Security audit, first pass: two findings fixed; nothing open.
29
- - Least-privilege Atlas role, scripted and documented for new users.
30
- - Provenance stamped from the transcript; semantic and procedural writes with no source refused.
31
- - Guardrails & Monorails and lab results.
32
- - Charter revised 2026-09-29 (the aleph, the monorail, the database boundary, the per-exchange transcript) and again 2026-09-30 (the admission test in commitment 6).
28
+ - Chain verification: one MongoDB connection path with a DNS fallback (6491586), then the chain walk moved into `emet_gaps` so no host needs the repo or a shell (commit-43a5ef6).
29
+ - Security audit, first pass: two findings fixed; nothing open (commit-c2aa70d).
30
+ - Least-privilege Atlas role, scripted and documented for new users (commit-26134e7).
31
+ - Provenance stamped from the transcript; semantic and procedural writes with no source refused (commit-4f6aba8).
32
+ - Guardrails & Monorails and lab results (commit-e7b4ebe through commit-20c39d3).
33
+ - Charter revised 2026-09-29 (the aleph, the monorail, the database boundary, the per-exchange transcript; commit-d98356e) and again 2026-09-30 (the admission test in commitment 6; procedural ref 404).
33
34
 
34
35
  ## Proposed features and functions
35
36
 
36
- - **GEM socket (plug-in standard).** A GEM is a nested module inside EMET that modifies engagement; a RUNED GEM also carries tools (RUNEs). The socket must mount several GEMs, switch each on or off, and prioritise the active ones in a running schema that prevents conflicts — with a cap on sockets, a cap on active GEMs, and a priority order, because every active GEM costs the model context. Includes a developer guide for building one.
37
+ - **GEM socket (phased).** GEM means Golem Expertise Module. A RUNED directive (Registered Utility Node Executable Directive) is a declared, registered tool built into a GEM. The 2026-09-08 expansions (Guided Engagement Module, Registered Utility Node Extension) are superseded. The standard, schema, authoring guide, conformance checks, and GEP-0001 are in [`gem-library/`](../gem-library/README.md), which moves to EMET-GEMs after this revision is approved.
38
+ - PR 2 (in the tree): `src/socket.js` and `gem-check` for a bundled prompt GEM (schema, spec revision, hashes, sizes, path safety, floor-negation lint, secret scan, no code), plus a conformance test. A refused GEM does not stop initialize.
39
+ - PR 3 (in the tree): `gems/neurendipity`. `reading_people`, the neurodivergent lines, the wellbeing corpus lines, the matching reassertion lines, and the guide (the old id aliases for one release). Default off. Set `EMET_ACTIVE_GEMS=neurendipity` to turn it on. Core floor keeps persistence, general epistemic honesty, the epistemic corpus lines, and the honesty protections. `emet_floor` takes a `gem` argument. The available list shows Neurendipity installed and off unless that setting names it.
40
+ - PR 4 (proposed): each GEM's byte cost in `emet_status` (`gems`: installed and active counts, active floor bytes, headroom, the enforced caps, and per-GEM id, version, kind, bytes and refusal reason; read-only, no floor text). Caps, priority, consent when `overrides` is non-empty, and the available list in the startup text are already enforced. `EMET_ACTIVE_GEMS` is how an install asks for a GEM.
41
+ - PR 5 (in the tree): RUNED registration through dispatch, static analysis, and `gems/fieldnote`, bundled and off by default. No GEM from outside the release loads. GEP-0003 supersedes the GEP-0002 sandbox: the sandbox is removed, and the socket serves each RUNE and does not run it.
42
+ - Later, each by its own GEP: the creator keyring and signature checks, the public submission repository and its CI gate, accepting a library GEM onto the load list, and a monorail switch that picks a GEM.
37
43
  - **Claim-status grading.** Extend provenance so every recorded claim carries a status: established, deduced, proposed, still owed, or rejected — and rejected routes stay on the record with the reason they failed. (Idea taken from a physics research corpus that grades its own claims this way.)
38
44
  - **Index-first retrieval.** Score candidates against a one-line-per-item index before opening anything, open only the best match, follow one link at most — finding is logic, not a model call. EMET already has the shape (handoff and board as router, document list as index); the work is keeping the startup router small.
39
45
  - **Composite retrieval scoring.** Live as of this revision: recall ranks by how many query words match, then by importance. Current entries come first in every order, including time order. Time order is `order: 'latest'`, or a standalone latest, newest, or most recent together with other words. That phrase only reorders rows that already match. Nothing fades or is down-weighted for age. A superseded or expired entry stays in the result, marked with its end date and what replaced it. `history: true` reads the ended entries when current ones fill the limit. A recall or layer query ranks matching rows in the store (current before ended, then keyword hits and importance, or time when you asked for the latest) and then keeps a bounded window (at least 200 rows, or 20 times the page), not the whole layer. A blank sort value comes first when ascending and last when descending.
40
46
  - **Export, import, restore-and-compare.** Not built; listed in the README's known gaps.
41
47
  - **Organizational use.** Many private EMETs and a document gateway between them. Nothing built before a named customer.
42
- - **Shared hive memory for AI bots (proposed 2026-09-30).** One EMET as a common memory that several agent bots read and write as users, each keeping its own memories — candidates are Grok Bot, OpenAI dots and Meta Muse, all of which can reach a remote MCP server. A GEM per bot, seated in the socket, if needed. Taken up with the socket; the first design question is each bot's source tag and scope.
43
- - **Compiled topic pages, pilot (proposed 2026-09-30).** After the LLM-wiki pattern: a document prefix of topic pages compiled from semantic entries. Every claim cites its entry or transcript span; a compiled page never cites another compiled page as evidence; pages are derived, never the source of truth; one compiler role builds pages, others write entries only. No database change — the document store already versions, hashes, signs and checks form. Pilot page: the hive-memory idea. Nothing added beyond what the pilot needs.
48
+ - **Shared hive memory for AI bots.** Closed as a separate item on 2026-10-11. Folded into the GEM socket work above. A bot that shares one EMET still needs its own source tag and scope. That question stays with the socket.
49
+ - **Compiled topic pages, pilot (proposed 2026-09-30).** After the LLM-wiki pattern: a document prefix of topic pages compiled from semantic entries. Every claim cites its entry or transcript span; a compiled page never cites another compiled page as evidence; pages are derived, never the source of truth; one compiler role builds pages, others write entries only. No database change. The document store already versions, hashes, signs and checks form. Pilot page: the hive-memory idea. The hive-memory feature is closed as its own item (2026-10-11) and folded into the socket. If this pilot is built, it needs a different page. Nothing added beyond what the pilot needs.
44
50
  - **Lint pass over the semantic layer (proposed 2026-09-30).** A scheduled sweep for contradictions between entries, outdated claims a newer entry supersedes, entries that should link and don't, and subjects mentioned often with no compiled page. Findings are reported, never applied automatically; corrections go through supersession. Built after the pilot page, and only once it names its measure. Design inputs from the LLM Wiki v2 review (typed links, multi-agent sync rules, drift invariants, confidence only on top of provenance) are each weighed against commitment 6 before adoption. Its idea of letting entries fade from what surfaces is not taken: nothing in EMET fades.
45
51
  - **Advisory judge for team traffic (parked).** A fast external decision model (TypeSafe's Jev was evaluated) could sort traffic and interactions when many people and hosts share one EMET. Never in the write path — no model decides what EMET stores. Not for single-user installs.
46
52
  - **Local open-weight model as a host.** A read-only trial of EMET under a locally run model, once the host machine's GPU and RAM are on record.
@@ -50,10 +56,7 @@ Status as of 2026-10-07. This is a working roadmap, not a commitment: items move
50
56
 
51
57
  ## Design commitments these must keep
52
58
 
53
- - No model in the write path: EMET stores only what the assistant deliberately chose to write.
54
- - Controls, not reminders: a rule that matters is checked by the server.
55
- - Over-engineering is a defect, and the check comes before the build. Nothing is built until it
56
- names the failure it fixes, what it replaces, how we will know it worked, and what keeps it
57
- working (charter commitment 6). While EMET is in design it follows DMADV (define, measure,
58
- analyze, design, verify); once stable, DMAIC (define, measure, analyze, improve, control).
59
+ - No model in the write path: EMET stores what the assistant deliberately chose to write.
60
+ - Controls, not reminders — a rule that matters is checked by the server.
61
+ - Over-engineering is a defect, and the check comes before the build: nothing is built until it names the failure it fixes, what it replaces, how we will know it worked, and what holds it once it works (charter commitment 6). DMADV while EMET is in design; DMAIC once stable.
59
62
  - Correct the record by superseding, never by editing.
package/docs/SETUP.md CHANGED
@@ -153,13 +153,19 @@ have to. A new store returns a short interview; an established one returns the a
153
153
  identity, your profile, and recent context. Requiring a command would have been backwards —
154
154
  the one session you would need it is the first one, before you have read any of this.
155
155
 
156
- The interview asks six things, four required and two optional:
156
+ The interview asks eight things, four required and four optional:
157
157
 
158
158
  - **What the assistant should be called**, and **how it should carry itself.** This becomes
159
159
  the identity it speaks from in every session on every host.
160
160
  - **Your name**, in the form you actually want used.
161
161
  - **What you are using this memory for**, which shapes what gets treated as worth saving.
162
- - Optionally: how you want to be worked with, and this host's source tag.
162
+ - Optionally: how you want to be worked with, this host's source tag, and whether more than
163
+ one bot or AI will use this memory. Leaving that one out leaves sub-keys off. The
164
+ walkthrough is [SUBKEYS.md](SUBKEYS.md).
165
+ - Optionally: whether to turn on bot-team backup. **Yes is the recommended choice.** Yes and
166
+ Yes. count as yes, the same way as the multi-bot question. No, or leaving it out, leaves it
167
+ off. The answer is recorded. EMET does not copy prompts or
168
+ settings itself, and secret values are never stored. The recipe is `gems/bot-team-backup/guides/BOT_TEAM_BACKUP.md`.
163
169
 
164
170
  Your assistant asks these conversationally, one at a time — not as a form — then calls
165
171
  `emet_setup_complete`.
@@ -0,0 +1,59 @@
1
+ # When more than one bot uses EMET
2
+
3
+ One EMET. One owner login. If more than one bot or AI writes through that login, each bot that can keep a key file gets its own key. The server stamps the tag on the key. A bot does not get to name another bot's tag and have that stamp stick.
4
+
5
+ This is part of EMET. It is the same server, the same owner page, and the same keys. It is not a second product, and it is not a fork.
6
+
7
+ The Charter and the floor are unchanged. This supports ISO 9001:2015 clause 7.5.3 and ISO 13485:2016 clause 4.2.5 (identification of who changed a record, retention of records, nothing deleted), as the README and the Charter word it. EMET claims no certification. The organization validates EMET for its own use.
8
+
9
+ ## Turn it on
10
+
11
+ Say **initialize**. Your assistant asks whether more than one bot or AI will use this memory. Answer in your own words. Leaving it out is the same as no.
12
+
13
+ - **No.** Sub-keys stay off. That one client uses its own source tag. The tool list does not grow.
14
+ - **Yes, and this server reads a `.env` file.** Setup writes three settings into that file after your identity is saved: sub-keys on, a pepper the server generates, and version 1. You do not type the pepper, and it is not repeated. Restart (or redeploy) the server once. The tools and `/owner/approvals` appear together after that restart. They do not turn on in the server that is already running.
15
+ - **Yes, and the server takes its settings from the platform** (Railway or anything else that injects environment variables). Setup refuses before it saves anything. No pepper or .env was written. Run setup again without yes to finish the rest. Then set these in the platform's variables and redeploy:
16
+ 1. `EMET_SUBKEYS=1`
17
+ 2. `EMET_SUBKEY_PEPPER` — generate it yourself, at least 32 bytes, for example with `openssl rand -hex 32`
18
+ 3. `EMET_SUBKEY_PEPPER_VERSION=1`
19
+
20
+ Do not paste the pepper into the chat or into any EMET document.
21
+
22
+ A single client does not get this turned on. The page and the tools ship with EMET. They stay quiet until the answer is yes and the server has restarted with the flag on.
23
+
24
+ If this memory is already set up and you later add bots, say so. Your assistant turns sub-keys on only after you explicitly agree to run setup again. That writes a new version of your identity documents. The previous version is kept.
25
+
26
+ ## Approve a bot
27
+
28
+ List each bot's tag in `EMET_SOURCE_TAGS` before it asks for a key. An empty list refuses every request.
29
+
30
+ 1. Open `/owner/approvals` on the same host you already use for this memory. Enter the passphrase you already use when you connect a device. A correct passphrase opens a short session. A wrong one is counted with the other passphrase attempts.
31
+ 2. Each bot that can keep a key file asks for a key with its own tag.
32
+ 3. On the approvals page, approve that request. Deny applies only to a pending request.
33
+ 4. The bot claims the key within 24 hours. It keeps the key where the other bots cannot read it. The key is never written into EMET.
34
+
35
+ A bot then opens a session with that key and passes the session handle the server gives back on later writes in that session.
36
+
37
+ ## A key lasts 30 days
38
+
39
+ To renew a key, the bot asks again with the same tag, you approve it on the page, and the bot claims the new key within 24 hours. The previous key works for a few minutes while the bot switches, then it stops. Earlier writes stay as they were written.
40
+
41
+ ## Revoking your login
42
+
43
+ Revoking the owner login stops every sub-key. The keys hang off that login. They do not keep working after it is gone.
44
+
45
+ ## A phone, or a web project
46
+
47
+ A host that cannot store a key file does not take a sub-key. A phone, or a web project instance, uses the tag on its own connection.
48
+
49
+ ## Security
50
+
51
+ The pepper is a server secret. When this server reads `.env`, setup writes that file and does not put the pepper in the database, in a document, or in the answer it gives your assistant. An MCP call is what writes the file, and only on that kind of server. A hosted server does not get a pepper written into its container.
52
+
53
+ The approvals page uses the same passphrase as connecting a device, and a wrong passphrase counts toward the same lockout.
54
+
55
+ What a sub-key shows is that a write was made with a key you approved. If several bots can read each other's files, EMET cannot prove which program was holding the key. If you think an active key has leaked, revoke it from your own login (`emet_subkey_revoke`), then the bot requests a new key and you approve it on the page. Deny only applies to a pending request.
56
+
57
+ ## Building a bot team
58
+
59
+ For designing a team of bots, see Lauren Tan (@poteto, https://x.com/poteto), who works on Grok Bot and describes choosing a bot topology (one generalist, several narrow specialists, or generalists each owning a project) in [this post](https://x.com/poteto/status/2109781899610874002). Her bot designer, [dr eggbot](https://x.ai/bot/93gOz3op1UQdBdbekQFLK) ([source](https://x.com/poteto/status/2106895160298852470)), helped design the EMET author's own bot team.
@@ -0,0 +1,12 @@
1
+ {
2
+ "sha256:c9f58a0ef18f7468b9618d0f1e96ddd8c50845243e098e84480908ca8cb0a528": {
3
+ "gem": "fieldnote",
4
+ "rune": "fieldnote",
5
+ "version": "1.0.0"
6
+ },
7
+ "sha256:cfb62b669f67c69f53989ed2621a40bfbfa60a744f1b4040e5b8496755598a35": {
8
+ "gem": "fieldnote",
9
+ "rune": "fieldnote",
10
+ "version": "1.0.1"
11
+ }
12
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "sections": {
3
+ "bot_team_backup": {
4
+ "title": "Bot-team backup",
5
+ "note": "Optional. Off unless the recorded setup answer is yes. This floor does not copy documents by itself.",
6
+ "lines": {
7
+ "follow_the_recipe": "When bootstrap/USER.md records bot-team backup as yes, follow guides/BOT_TEAM_BACKUP.md. Write each bot's name, prompt, settings, routines and skills to bot-team/<bot>.md. Revise a document only when it changed. Supersede; do not delete.",
8
+ "no_secrets": "Never store secret values, tokens, passwords or card data in a bot-team document. Connectors, logins and secrets are reconnected by hand. Name those items in bot-team/RECOVERY.md. Do not write the values."
9
+ }
10
+ }
11
+ },
12
+ "reassertion": [
13
+ "Bot-team backup stores no secret values."
14
+ ]
15
+ }
@@ -0,0 +1,43 @@
1
+ {
2
+ "spec": "2026-10-12",
3
+ "id": "bot-team-backup",
4
+ "name": "Bot-team backup",
5
+ "description": "Optional recipe for writing each bot's name, prompt, settings, routines and skills as controlled documents. Off unless the recorded setup answer is yes. Does not store tokens, passwords or card data.",
6
+ "version": "1.0.0",
7
+ "kind": "gem",
8
+ "requires": {
9
+ "emet": ">=0.2.6"
10
+ },
11
+ "priority": 10,
12
+ "defaultOn": false,
13
+ "released": true,
14
+ "overrides": [],
15
+ "distribution": "bundled",
16
+ "floor": "floor.json",
17
+ "guides": [
18
+ "guides/BOT_TEAM_BACKUP.md",
19
+ "guides/BOT_TEAM_RECOVERY.md"
20
+ ],
21
+ "runes": [],
22
+ "files": [
23
+ {
24
+ "path": "floor.json",
25
+ "digest": "sha256:7182ec1d78bed4234c9a309bd03b4ca4099fa3b031e6b743d554378862230862",
26
+ "size": 802
27
+ },
28
+ {
29
+ "path": "guides/BOT_TEAM_BACKUP.md",
30
+ "digest": "sha256:aa912c28c08745e4cde13d156488af94a74745573e7d184a10007ee453de2d12",
31
+ "size": 1384
32
+ },
33
+ {
34
+ "path": "guides/BOT_TEAM_RECOVERY.md",
35
+ "digest": "sha256:8fbccbc7985c2e1696c42293c73c1257e2fbf9548717b19a8086306b2ed0db0e",
36
+ "size": 1305
37
+ }
38
+ ],
39
+ "authors": [
40
+ "Dreamforge Studio LLC"
41
+ ],
42
+ "license": "MIT"
43
+ }
@@ -0,0 +1,27 @@
1
+ # Bot-team backup
2
+
3
+ Optional. Off unless the first-run answer recorded in `bootstrap/USER.md` under BOT-TEAM BACKUP is `yes`. Yes is the recommended choice. Leaving the question out records `no`.
4
+
5
+ EMET does not run this recipe. The assistant does, and only after that recorded yes.
6
+
7
+ ## What to write
8
+
9
+ For each bot the install uses, keep one controlled document at `bot-team/<bot>.md`. Use the bot's own tag as `<bot>`, the same tag its writes already carry. The document holds:
10
+
11
+ - the bot's name
12
+ - the prompt it runs with
13
+ - the settings that are not secret
14
+ - the routines it follows
15
+ - the skills it uses
16
+
17
+ Write the document through the normal document tools. A later change is a new revision of the same id. Do not delete the previous copy. If nothing changed since the last revision, do not write again.
18
+
19
+ Check on a steady cadence the install chooses, such as at session close, and only write when the text would differ.
20
+
21
+ ## What never goes in
22
+
23
+ Never store secret values, tokens, passwords or card data. Not in `bot-team/<bot>.md`, not in `bot-team/RECOVERY.md`, and not in any other bot-team document. A name of a connector or a login is not a secret. The value behind it is.
24
+
25
+ ## Recovery
26
+
27
+ Keep the rebuild order in `bot-team/RECOVERY.md`, filled from `guides/BOT_TEAM_RECOVERY.md`. That document lists what a person must reconnect by hand. It does not store the secrets themselves.
@@ -0,0 +1,23 @@
1
+ # Bot-team recovery
2
+
3
+ Copy this into the store as `bot-team/RECOVERY.md` when bot-team backup is on. Revise it when the rebuild order changes. Supersede; do not delete.
4
+
5
+ Never store secret values, tokens, passwords or card data here. Name the item that has to be reconnected. Leave the value out.
6
+
7
+ ## Rebuild order
8
+
9
+ 1. Restore the memory server and its database from the operator's own backup of that service.
10
+ 2. Read `bot-team/<bot>.md` for each bot and put back that bot's name, prompt, settings, routines and skills.
11
+ 3. Reconnect, by hand, every item in the list below. The documents do not contain what those items need in order to authenticate.
12
+
13
+ ## Reconnect by hand
14
+
15
+ | Item | Where it lives | What the person does |
16
+ |---|---|---|
17
+ | Connectors | The host's connector settings | Connect each one again. The document may name the connector. It must not hold a key. |
18
+ | Logins | The host account for each bot | Sign in again. The document may name the account. It must not hold a password. |
19
+ | Secrets | The host's secret store | Put each secret back from the place the operator keeps secrets. This document names the slot, not the value. |
20
+
21
+ ## Rule
22
+
23
+ If a value is a token, a password, a card number, or any other secret, it does not belong in EMET. Record that the item must be reconnected. Stop there.
@@ -0,0 +1,14 @@
1
+ {
2
+ "sections": {
3
+ "field_notes": {
4
+ "title": "Field notes",
5
+ "note": "A count of the working layer is a note about what is already stored. It does not add a store.",
6
+ "lines": {
7
+ "count_only": "Report the count. The count is not a list, and it is not a new record."
8
+ }
9
+ }
10
+ },
11
+ "reassertion": [
12
+ "The working layer is memory, and a count is not a new store."
13
+ ]
14
+ }
@@ -0,0 +1,70 @@
1
+ {
2
+ "spec": "2026-10-12",
3
+ "id": "fieldnote",
4
+ "name": "Fieldnote",
5
+ "description": "A reference RUNED directive. Counts rows the caller passes in. Off unless the install asks for it.",
6
+ "version": "1.0.1",
7
+ "kind": "runed-gem",
8
+ "requires": {
9
+ "emet": ">=0.2.4"
10
+ },
11
+ "priority": 40,
12
+ "defaultOn": false,
13
+ "overrides": [],
14
+ "distribution": "bundled",
15
+ "floor": "floor.json",
16
+ "guides": [],
17
+ "runes": [
18
+ {
19
+ "name": "fieldnote",
20
+ "description": "Count the rows the caller passes in. A call returns this code and does not run it.",
21
+ "execution": "client",
22
+ "artifact": "runes/fieldnote.js",
23
+ "sha256": "sha256:cfb62b669f67c69f53989ed2621a40bfbfa60a744f1b4040e5b8496755598a35",
24
+ "version": "1.0.1",
25
+ "runtime": "node",
26
+ "inputSchema": {
27
+ "type": "object",
28
+ "properties": {
29
+ "rows": {
30
+ "type": "array",
31
+ "description": "Working-layer rows the caller already read."
32
+ }
33
+ }
34
+ },
35
+ "outputSchema": {
36
+ "type": "object",
37
+ "properties": {
38
+ "count": {
39
+ "type": "integer"
40
+ }
41
+ }
42
+ },
43
+ "annotations": {
44
+ "readOnlyHint": true,
45
+ "destructiveHint": false,
46
+ "idempotentHint": true,
47
+ "openWorldHint": false
48
+ },
49
+ "reads": [],
50
+ "writes": [],
51
+ "network": "none"
52
+ }
53
+ ],
54
+ "files": [
55
+ {
56
+ "path": "floor.json",
57
+ "digest": "sha256:11af3724b165beb3e9a49a681f1f07cb742bcb4535206f714a0dc689067f32d6",
58
+ "size": 403
59
+ },
60
+ {
61
+ "path": "runes/fieldnote.js",
62
+ "digest": "sha256:cfb62b669f67c69f53989ed2621a40bfbfa60a744f1b4040e5b8496755598a35",
63
+ "size": 147
64
+ }
65
+ ],
66
+ "authors": [
67
+ "Dreamforge Studio LLC"
68
+ ],
69
+ "license": "MIT"
70
+ }
@@ -0,0 +1,4 @@
1
+ export default function fieldnote(input) {
2
+ const rows = input && Array.isArray(input.rows) ? input.rows : [];
3
+ return { count: rows.length };
4
+ }
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ ## 0.9.0
4
+ date: 2026-10-20
5
+ class: initial
6
+ what changed and why: Pre-release 0.9.0. requires.emet is >=0.2.6. Rune files are unchanged.
7
+ init time: before none, after unmeasured
8
+ test time: before none, after unmeasured
9
+ log noise: before none, after unmeasured
10
+ byte cost: before none, after 1790