@dreamforgestudiollc/emet 0.0.0-stage → 0.2.4
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.
- package/.env.example +136 -0
- package/CHANGELOG.md +296 -0
- package/CHARTER.md +125 -0
- package/LICENSE +22 -0
- package/README.md +783 -2
- package/docs/AUTHORSHIP.md +26 -0
- package/docs/BENCHMARKS.md +261 -0
- package/docs/BOOTSTRAP.md +127 -0
- package/docs/BOTS.md +79 -0
- package/docs/COVERAGE.md +64 -0
- package/docs/DEPLOY.md +246 -0
- package/docs/DISCIPLINES.md +29 -0
- package/docs/GUARDRAILS-AND-MONORAILS.md +107 -0
- package/docs/GUIDED-SETUP.md +296 -0
- package/docs/PERMISSIONS.md +118 -0
- package/docs/ROADMAP.md +59 -0
- package/docs/SETUP.md +259 -0
- package/guides/NEURODIVERGENT_SUPPORT.md +278 -0
- package/package.json +70 -4
- package/server.json +39 -0
- package/src/aleph.js +395 -0
- package/src/annotations.js +135 -0
- package/src/approve-throttle.js +54 -0
- package/src/atlas-role.js +58 -0
- package/src/conformance.js +688 -0
- package/src/content_analyzer.js +450 -0
- package/src/database.js +811 -0
- package/src/disciplines.js +26 -0
- package/src/dispatch.js +279 -0
- package/src/env.js +52 -0
- package/src/floor.js +187 -0
- package/src/gaps.js +476 -0
- package/src/guides.js +48 -0
- package/src/http-remote.js +269 -0
- package/src/index.js +390 -0
- package/src/invites.js +167 -0
- package/src/layers.js +449 -0
- package/src/lessons-to-checks.js +366 -0
- package/src/logger.js +299 -0
- package/src/metadata.js +61 -0
- package/src/module-path.js +32 -0
- package/src/mongo-connect.js +48 -0
- package/src/named-items.js +208 -0
- package/src/oauth-provider.js +838 -0
- package/src/persons.js +116 -0
- package/src/provenance.js +257 -0
- package/src/redact.js +231 -0
- package/src/request-log.js +124 -0
- package/src/scopes.js +97 -0
- package/src/security-headers.js +26 -0
- package/src/session-graph.js +945 -0
- package/src/session.js +1097 -0
- package/src/setup.js +1313 -0
- package/src/startup-pages.js +354 -0
- package/src/startup-payload.js +126 -0
- package/src/tools.js +4271 -0
- package/src/transcript-session.js +106 -0
- package/src/validation.js +1163 -0
- package/src/version.js +2 -0
- package/templates/BOARD.md +72 -0
- package/templates/BOTHANDOFF.md +57 -0
- package/templates/CHARACTER.md +30 -0
- package/templates/HANDOFF.md +63 -0
- package/templates/IDENTITY.md +29 -0
- package/templates/INDEX.md +82 -0
- package/templates/INSTALL.md +29 -0
- package/templates/PROCEDURE.md +39 -0
- package/templates/ROSTER.md +43 -0
- package/templates/SEED.md +65 -0
- package/templates/STAGING.md +37 -0
- package/templates/STANDARD.md +99 -0
- package/templates/THREAD.md +43 -0
- package/templates/USER.md +29 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Authorship
|
|
2
|
+
|
|
3
|
+
Early commits in this project's private development history recorded the
|
|
4
|
+
user's git identity in the author field. Those changes were machine-authored — written by assistant
|
|
5
|
+
instances under the user's direction. No git user was configured in any scope,
|
|
6
|
+
so that identity was supplied per command.
|
|
7
|
+
|
|
8
|
+
Later commits in that history name the assistant in the author field, and an `Approved-by` trailer
|
|
9
|
+
names the user, so what made a change and who accepted it are two separate
|
|
10
|
+
recorded facts rather than one conflated one.
|
|
11
|
+
|
|
12
|
+
The earlier commits are not rewritten. Corrections to any EMET record are made by
|
|
13
|
+
adding — a superseding entry, a marker, a written disposition — never by removing
|
|
14
|
+
or editing what is already there. A history rewritten to read correctly destroys
|
|
15
|
+
the retained record in order to do it. This file is the addition.
|
|
16
|
+
|
|
17
|
+
This matters because the charter states that records are attributable. An author
|
|
18
|
+
field naming a person for machine-made changes is not attributable evidence, and
|
|
19
|
+
git was the one store in this system with no source-attribution mechanism: memory
|
|
20
|
+
entries carry a host tag and an assertion origin, document writes carry a host tag
|
|
21
|
+
that is never a person, transcripts carry a session id.
|
|
22
|
+
|
|
23
|
+
## Upstream
|
|
24
|
+
|
|
25
|
+
Portions of this work derive from CASCADE Enterprise RAM (C.I.P.S. LLC). See
|
|
26
|
+
`LICENSE`, which carries both that notice and Dreamforge Studio LLC's.
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# EMET benchmarks — implementation language evaluation
|
|
2
|
+
|
|
3
|
+
**Run 2026-09-08. Four implementations, one specification, live MongoDB Atlas, identical hosting.**
|
|
4
|
+
**Conclusion: EMET stays on JavaScript — on measurement, not by default.**
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Why this exists
|
|
9
|
+
|
|
10
|
+
A programmer friend of the maintainer suggested that a more object-oriented or compiled
|
|
11
|
+
language — Java, Python, C++, and Rust in particular — would likely be faster than Node and
|
|
12
|
+
serve EMET better long term. That is a reasonable prior and it deserved a real answer rather
|
|
13
|
+
than a defence of the status quo.
|
|
14
|
+
|
|
15
|
+
Two questions were separated, because they have different answers and different costs:
|
|
16
|
+
|
|
17
|
+
1. **Language** — is JavaScript the right substrate for EMET's backend?
|
|
18
|
+
2. **Durability** — which practices have legs, independent of language?
|
|
19
|
+
|
|
20
|
+
This document reports the first. It also reports the thing the exercise actually produced,
|
|
21
|
+
which was not a language choice.
|
|
22
|
+
|
|
23
|
+
**Nothing here argues from intuition about language speed.** Every number was measured, and
|
|
24
|
+
every limit of the measurement is stated.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Method
|
|
29
|
+
|
|
30
|
+
**One specification, implemented once per language, as a single file with the tasks as
|
|
31
|
+
functions inside it** — so connection, configuration, fixtures, timing and output are written
|
|
32
|
+
once per language and shared by every task, rather than drifting across eight separate scripts.
|
|
33
|
+
|
|
34
|
+
Each implementation ran as its own service on the same platform (Railway, region `sfo`),
|
|
35
|
+
against the **same live MongoDB Atlas cluster**, reading the **same fixtures file**, writing to
|
|
36
|
+
throwaway `bench_*` collections that never touch EMET's own data.
|
|
37
|
+
|
|
38
|
+
### Equivalence — checked before any timing was read
|
|
39
|
+
|
|
40
|
+
Two digests are computed by every implementation: a fixed canonical string, and the **masked**
|
|
41
|
+
form of a secret-bearing fixture. If they differ, the implementations are not doing the same
|
|
42
|
+
work and no timing means anything.
|
|
43
|
+
|
|
44
|
+
| language | canonical probe | masked secret |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| javascript | `feb7628ae8a0…` | `15a3c529bee0…` |
|
|
47
|
+
| python | `feb7628ae8a0…` | `15a3c529bee0…` |
|
|
48
|
+
| go | `feb7628ae8a0…` | `15a3c529bee0…` |
|
|
49
|
+
| rust | `feb7628ae8a0…` | `15a3c529bee0…` |
|
|
50
|
+
|
|
51
|
+
**Identical across all four.** This check is what separates a benchmark from four programs
|
|
52
|
+
that happen to run.
|
|
53
|
+
|
|
54
|
+
### Clock points
|
|
55
|
+
|
|
56
|
+
Per task the implementations record `t_total`, and `t_driver` — the summed duration of every
|
|
57
|
+
awaited database call. `t_inproc = t_total − t_driver` is the language's own work: hashing,
|
|
58
|
+
masking, serialisation, validation, receipt construction.
|
|
59
|
+
|
|
60
|
+
⚠ **The split is not clean, and the report does not pretend otherwise.** BSON encoding and TLS
|
|
61
|
+
happen *inside* the driver call and are genuinely language and driver work counted in
|
|
62
|
+
`t_driver`. The two buckets are therefore "in-process work outside the driver call" and
|
|
63
|
+
"driver call duration". **No single "language speed" number is produced, because none would be
|
|
64
|
+
honest.**
|
|
65
|
+
|
|
66
|
+
Percentiles are p50 and p95, never mean.
|
|
67
|
+
|
|
68
|
+
### Tasks
|
|
69
|
+
|
|
70
|
+
`T1` connect · `T2` write through the full door (mask, digest content and metadata, insert,
|
|
71
|
+
read back, verify) · `T3` structured read with filters · `T5` supersession write · `T6`
|
|
72
|
+
document write with archive and sha256 read-back · `T9` 300 KB document write · `T10` 300 KB
|
|
73
|
+
server-side read-modify-write · `T11` bulk write of 100 records.
|
|
74
|
+
|
|
75
|
+
The 300 KB size is not arbitrary: it is the size of a real EMET thread document.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Results — in-process work, p50 milliseconds
|
|
80
|
+
|
|
81
|
+
| task | javascript | python | go | rust |
|
|
82
|
+
|---|---|---|---|---|
|
|
83
|
+
| T2 door write (small) | 0.141 | 0.088 | 0.046 | **0.033** |
|
|
84
|
+
| T3 structured read | 0.037 | 0.030 | **0.007** | **0.007** |
|
|
85
|
+
| T5 supersession write | 0.132 | 0.070 | 0.029 | **0.027** |
|
|
86
|
+
| T6 document write (small) | 0.314 | 0.180 | 0.227 | **0.089** |
|
|
87
|
+
| **T9 300 KB write** | 1.198 | 12.185 | **45.540** | **1.092** |
|
|
88
|
+
| T10 300 KB read-modify-write | 0.763 | 0.599 | 0.850 | **0.428** |
|
|
89
|
+
| T11 bulk 100 records | 0.784 | 0.610 | 1.290 | **0.244** |
|
|
90
|
+
|
|
91
|
+
### The finding that matters — where the 300 KB in-process time goes
|
|
92
|
+
|
|
93
|
+
| step | javascript | python | go | rust |
|
|
94
|
+
|---|---|---|---|---|
|
|
95
|
+
| **mask (regex passes over 300 KB)** | **0.592** | 11.642 | **44.845** | 0.769 |
|
|
96
|
+
| sha256 (300 KB) | 0.211 | 0.226 | 0.340 | **0.156** |
|
|
97
|
+
|
|
98
|
+
**Masking is the entire story, and it inverts the premise the exercise began with.**
|
|
99
|
+
JavaScript is the *fastest* of the four at it: V8's JIT-compiled engine beats Rust's `regex`
|
|
100
|
+
crate and is **75× faster than Go's RE2**. A compiled language turned out to be the slowest
|
|
101
|
+
implementation in the benchmark, by an order of magnitude, at the operation that dominates.
|
|
102
|
+
|
|
103
|
+
### Total latency and what it means
|
|
104
|
+
|
|
105
|
+
| task | javascript | python | go | rust |
|
|
106
|
+
|---|---|---|---|---|
|
|
107
|
+
| T2 | 136.1 | 139.7 | 138.5 | 123.2 |
|
|
108
|
+
| T6 | 542.7 | 560.9 | 558.0 | 491.4 |
|
|
109
|
+
| T9 | 209.5 | 226.5 | 264.4 | 190.5 |
|
|
110
|
+
| T11 | 73.8 | 74.2 | 76.6 | 65.2 |
|
|
111
|
+
|
|
112
|
+
⚠ **No language ranking should be read from this table.** These are dominated by the Atlas
|
|
113
|
+
round trip. The spread between languages (10–20%) is the same order as ordinary network
|
|
114
|
+
variance, and each language was run once, not interleaved.
|
|
115
|
+
|
|
116
|
+
**For JavaScript and Rust, in-process work never exceeds ~1% of any operation.** Go reaches
|
|
117
|
+
17.2% on T9, entirely because of the regex.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Results — concurrency
|
|
122
|
+
|
|
123
|
+
The serial numbers leave one question open: does a single-threaded runtime degrade when
|
|
124
|
+
several callers hit it at once? That is measured with **concurrent inbound requests** — what
|
|
125
|
+
the condition actually looks like against a live server — each performing one 300 KB mask and
|
|
126
|
+
digest with **no database**, so nothing hides behind network latency.
|
|
127
|
+
|
|
128
|
+
| | conc | throughput/s | in-process p50 ms | in-process p95 ms |
|
|
129
|
+
|---|---|---|---|---|
|
|
130
|
+
| **javascript** | 1 | 10.92 | 1.250 | 1.555 |
|
|
131
|
+
| | 4 | 37.22 | 0.878 | 1.430 |
|
|
132
|
+
| | **16** | **59.62** | **0.904** | **1.413** |
|
|
133
|
+
| **rust** | 1 | 10.75 | 2.249 | 4.628 |
|
|
134
|
+
| | 4 | 35.73 | 2.420 | 6.452 |
|
|
135
|
+
| | **16** | 57.72 | 2.619 | 4.359 |
|
|
136
|
+
| **go** | 1 | 6.90 | 47.116 | 64.208 |
|
|
137
|
+
| | 4 | 21.97 | 55.600 | 75.655 |
|
|
138
|
+
| | **16** | 50.88 | 73.791 | 126.559 |
|
|
139
|
+
| **python** | 1 | 8.93 | 18.126 | 25.698 |
|
|
140
|
+
| | 4 | 21.35 | 43.540 | 76.169 |
|
|
141
|
+
| | **16** | **15.26** ⬇ | 46.095 | 112.792 |
|
|
142
|
+
|
|
143
|
+
**JavaScript wins outright: highest throughput at every level, lowest in-process latency, and
|
|
144
|
+
the flattest curve** (1.250 → 0.904 ms from concurrency 1 to 16 — it *improves* as the JIT
|
|
145
|
+
warms). Rust is a close second and scales cleanly. Go degrades 57%. **Python's throughput
|
|
146
|
+
collapses past concurrency 4** — textbook GIL contention.
|
|
147
|
+
|
|
148
|
+
**The mechanism matters more than the ranking.** Node's single thread was never the bottleneck
|
|
149
|
+
because the per-request CPU cost is small: 0.5 ms of masking does not saturate an event loop.
|
|
150
|
+
Python fails on the *same* architecture because its mask costs 35× more. **Being
|
|
151
|
+
single-threaded is only a liability when each request is expensive — which is an argument for
|
|
152
|
+
making requests cheap, not for changing language.** And Go had cores to spread across and still
|
|
153
|
+
lost: **parallelism does not fix a slow inner loop.**
|
|
154
|
+
|
|
155
|
+
⚠ **Core counts:** `os.cpus()` (Node) and `runtime.NumCPU()` (Go) reported **48** — the *host*
|
|
156
|
+
count; those APIs ignore the container's cgroup quota. Rust's `available_parallelism()`
|
|
157
|
+
respects it and reported **8**. The honest figure is ~8 usable cores, which **strengthens** the
|
|
158
|
+
result: the multi-core runtimes genuinely had room and still did not win.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Standards provenance
|
|
163
|
+
|
|
164
|
+
Beyond performance, the maintainer set a standing priority on candidates provable against
|
|
165
|
+
confirmed standards. Verified 2026-09-08:
|
|
166
|
+
|
|
167
|
+
| candidate | language standard |
|
|
168
|
+
|---|---|
|
|
169
|
+
| **JavaScript** | **ECMA-262 and ISO/IEC 16262** — dual-standardised |
|
|
170
|
+
| C# | ECMA-334, plus an ISO/IEC edition |
|
|
171
|
+
| Java | **No ISO or ECMA standard.** Governed by the JCP, the JLS (JSR 901) and a TCK — a rigorous but vendor-administered regime |
|
|
172
|
+
| Rust | No language standard. A *qualified toolchain* exists (Ferrocene, TÜV SÜD: ISO 26262 ASIL D, IEC 61508 SIL 3, IEC 62304 Class C) — a different guarantee, aimed at safety-critical software |
|
|
173
|
+
| Go, Python | No standards-body specification found |
|
|
174
|
+
|
|
175
|
+
**JavaScript is the only candidate with an international language standard.** TypeScript, often
|
|
176
|
+
proposed as the cheap improvement, has none at all — it is a vendor-controlled superset, and
|
|
177
|
+
adopting it would trade a standard for a governance model.
|
|
178
|
+
|
|
179
|
+
⚠ The ISO edition of ECMAScript (16262:2011) lags ECMA-262's annual editions considerably.
|
|
180
|
+
The stamp is real; its currency is not.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Conclusion
|
|
185
|
+
|
|
186
|
+
**EMET stays on JavaScript**, and the decision rests on two independently measured legs:
|
|
187
|
+
|
|
188
|
+
1. **Standards** — the only dual-standardised candidate.
|
|
189
|
+
2. **Performance, serial and concurrent** — the difference is not merely negligible; **it
|
|
190
|
+
favours JavaScript**, which posted the highest throughput and lowest in-process latency at
|
|
191
|
+
every concurrency level tested.
|
|
192
|
+
|
|
193
|
+
The port was never competing for much. In-process work is ≤1% of any operation, because
|
|
194
|
+
**EMET is round-trip-bound, not compute-bound.** Against that, a port would have to re-earn
|
|
195
|
+
**673 test assertions across 17 suites**, counted for the 2026-09-08 run (the current suite is larger; the README states that count), the single write path, two transports and a proven
|
|
196
|
+
OAuth flow.
|
|
197
|
+
|
|
198
|
+
### What the exercise actually produced
|
|
199
|
+
|
|
200
|
+
Not a language choice — **a function to optimise.**
|
|
201
|
+
|
|
202
|
+
The benchmark identified the write-path scrubber as the dominant in-process cost. Profiling the
|
|
203
|
+
real implementation on a 300 KB body found something the benchmark alone could not:
|
|
204
|
+
|
|
205
|
+
| case | before | after |
|
|
206
|
+
|---|---|---|
|
|
207
|
+
| clean prose, no secrets | 6.401 ms | **0.962 ms** |
|
|
208
|
+
| secret-bearing | 7.251 ms | **3.549 ms** |
|
|
209
|
+
|
|
210
|
+
**Nine tenths of the worst case was being paid by documents containing nothing to redact** —
|
|
211
|
+
the cost was scanning, not replacing. Three causes: a regular expression compiled per literal
|
|
212
|
+
*on every call*, the literal registry re-sorted every call, and four pattern rules scanning the
|
|
213
|
+
full body unconditionally. Fixed by caching the order, using plain substring operations for
|
|
214
|
+
literals, and giving each rule a **necessary-condition prefilter**.
|
|
215
|
+
|
|
216
|
+
Behaviour is unchanged and that was the acceptance criterion: **hit counts are identical on
|
|
217
|
+
every case and the redaction suite passes untouched.** A prefilter that changed what got masked
|
|
218
|
+
would be a defect, not an optimisation.
|
|
219
|
+
|
|
220
|
+
**This saves ~3.7 ms per large write. The gap between the fastest and slowest reasonable
|
|
221
|
+
language candidate was ~0.1 ms.** The function was worth roughly thirty times the port.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## What was not measured
|
|
226
|
+
|
|
227
|
+
Stated plainly, because a report that only lists what it proved is advocacy.
|
|
228
|
+
|
|
229
|
+
- **MCP over streamable HTTP, and OAuth, were not implemented in any candidate.** They measure
|
|
230
|
+
what an SDK *can do*, not how fast it is. **They remain the only substantive reason to build
|
|
231
|
+
further implementations.**
|
|
232
|
+
- **Stranger-install cost was not measured.** A single compiled binary needs no runtime where
|
|
233
|
+
Node does, and the `.mcpb` bundle format supports Node, Python and compiled binaries with
|
|
234
|
+
dependencies bundled — which narrows the gap by an unknown amount. **That question is settled
|
|
235
|
+
by an install on a clean machine, not by benchmarking.** It is the open axis.
|
|
236
|
+
- **Vector search** was excluded: it needs an index provisioned on the bench collection, and
|
|
237
|
+
embedding happens server-side, so it carries almost no signal about language.
|
|
238
|
+
- **One run per language, not interleaved or repeated.** All services ran in `sfo` while the
|
|
239
|
+
production service runs in US East; same-region running would shrink driver times and raise
|
|
240
|
+
in-process shares by a projected factor of ~3 — without changing the ranking.
|
|
241
|
+
- The concurrency runs used a **simplified masker**, not EMET's production scrubber. Same
|
|
242
|
+
shape, different absolute numbers.
|
|
243
|
+
|
|
244
|
+
## Two harness defects, found and corrected before comparing
|
|
245
|
+
|
|
246
|
+
Both would have compared *programs* rather than languages, which is the failure this kind of
|
|
247
|
+
exercise exists to avoid:
|
|
248
|
+
|
|
249
|
+
- JavaScript counted substring occurrences with `split()`, allocating an array over a 300 KB
|
|
250
|
+
body, where Python and Go used a scanning count. Corrected to a scan.
|
|
251
|
+
- A structured-read task failed because an earlier task's per-iteration writes left duplicates
|
|
252
|
+
that crowded lower-importance fixtures out of a limited, sorted read. Corrected by seeding
|
|
253
|
+
singletons.
|
|
254
|
+
|
|
255
|
+
Each cause was read from the failing result's own diagnostic output rather than guessed.
|
|
256
|
+
|
|
257
|
+
## Reproducing the scrubber measurement
|
|
258
|
+
|
|
259
|
+
`scripts/redact-bench.mjs` measures the write-path scrubber alone — no database, no network.
|
|
260
|
+
**Run it before and after any change to `src/redact.js`.** The four-language services were
|
|
261
|
+
scaffolding and have been torn down; this instrument guards shipped code and remains.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Wiring EMET into your assistant
|
|
2
|
+
|
|
3
|
+
Connecting the server gives your assistant the *ability* to remember. It does not make it
|
|
4
|
+
*use* that ability. An assistant with memory tools and no instruction about them will answer
|
|
5
|
+
from what it can infer, save nothing, and leave you to notice.
|
|
6
|
+
|
|
7
|
+
This is the layer that closes that gap, and it is deliberately small.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Why it is short
|
|
12
|
+
|
|
13
|
+
A memory system usually arrives with a long standing prompt — identity, protocol, rules,
|
|
14
|
+
startup sequence — pasted into every project and re-pasted whenever it changes.
|
|
15
|
+
|
|
16
|
+
EMET moves almost all of that into the server. `emet_initialize` returns the assistant's
|
|
17
|
+
identity, the user profile, recent context, and the operating disciplines, **on every call, on
|
|
18
|
+
every host.** So the block you paste does not need to contain any of it. It only needs to say:
|
|
19
|
+
call that first, and mean it.
|
|
20
|
+
|
|
21
|
+
The practical consequence: when you change who your assistant is, you change it once with
|
|
22
|
+
`write_doc` and every host picks it up on the next session. Nothing to re-paste anywhere.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## The block
|
|
27
|
+
|
|
28
|
+
Paste this into your project's custom instructions, system prompt, or equivalent.
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
## Memory
|
|
32
|
+
|
|
33
|
+
You have persistent memory through EMET.
|
|
34
|
+
|
|
35
|
+
Call `emet_initialize` FIRST, before anything else, at the start of every session -
|
|
36
|
+
and whenever the user opens with "initialize", "start", "begin", or similar. It
|
|
37
|
+
returns who you are, who you are serving, where things were left, and the operating
|
|
38
|
+
disciplines. It comes in pages: fetch every page it names (each page gives the exact
|
|
39
|
+
call for the next), or call it with page: "all" on a host with no size limit. Adopt
|
|
40
|
+
identity, character, and floor; do not recite those three back. Then open the
|
|
41
|
+
session transcript with emet_session_open and the load_id the startup carries, if
|
|
42
|
+
that tool is present. Read HANDOFF and the board.
|
|
43
|
+
Name the board in plain words: half-state, dated items, open items with next
|
|
44
|
+
action, anything left undecided; then parked items one line each with what
|
|
45
|
+
brings them back; then the counts as a check; then the tools actually present;
|
|
46
|
+
then a question. Never a question alone. Never letter-number codes.
|
|
47
|
+
|
|
48
|
+
If a local shell MCP is present, measure the computer name and that machine's
|
|
49
|
+
clock before the host line; put the raw return on the first transcript append.
|
|
50
|
+
If none is present, do not invent the line. Say system status and time were
|
|
51
|
+
not measured because no local shell MCP is connected, and that adding one
|
|
52
|
+
enables that function.
|
|
53
|
+
|
|
54
|
+
Before answering anything that might have prior context - a decision, a preference,
|
|
55
|
+
a configuration, a name, a past conversation - search memory first with `recall`,
|
|
56
|
+
`semantic_recall` or `query_layer`. Do not answer from what seems likely when the
|
|
57
|
+
store would have told you.
|
|
58
|
+
|
|
59
|
+
tools_in_force from initialize are calls, not reading. After every reply, append
|
|
60
|
+
that exchange to the transcript. Save as you go, not at the end: decisions with their
|
|
61
|
+
reasoning, problems solved, preferences stated, corrections made. Read every write
|
|
62
|
+
back before reporting it saved. Use all six layers - `emet_initialize` returns what belongs in each, and
|
|
63
|
+
routing everything into the two or three that feel obvious is how a layer goes
|
|
64
|
+
unused for a year without anyone noticing.
|
|
65
|
+
|
|
66
|
+
When the session ends - the user says goodbye or thanks you, asks to wrap up,
|
|
67
|
+
mentions restarting or opening a new session, or you are running out of room -
|
|
68
|
+
work through the `session_close_protocol` that `emet_initialize` returned, in its
|
|
69
|
+
order, then call `emet_session_close` to confirm it landed. Do not tell the user
|
|
70
|
+
the session is saved until it returns state "complete".
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
That is the whole thing. The disciplines it alludes to arrive in full from
|
|
74
|
+
`emet_initialize`; repeating them here would create two copies to keep in agreement.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Hosts differ, and EMET degrades gracefully
|
|
79
|
+
|
|
80
|
+
**Hosts with an instructions field** — a claude.ai Project, a `CLAUDE.md`, a system prompt,
|
|
81
|
+
a custom GPT. Paste the block. This is the strongest integration: the assistant reaches for
|
|
82
|
+
memory unprompted, on the first turn, without being told.
|
|
83
|
+
|
|
84
|
+
**Hosts with projects but no instructions field** — some vendors offer a project or workspace
|
|
85
|
+
that groups conversations without letting you set standing instructions. **It still works.**
|
|
86
|
+
The tool descriptions do the work: `emet_initialize` is described as "START HERE," and a
|
|
87
|
+
capable model calls it when you open with "initialize." You are relying on the model reading
|
|
88
|
+
its tools rather than on a standing instruction, which is slightly less reliable and entirely
|
|
89
|
+
usable.
|
|
90
|
+
|
|
91
|
+
**Plain chat with the connector enabled** — same as above. Say "initialize" and the session
|
|
92
|
+
comes up with your identity and context. No project, no instructions, nothing to configure.
|
|
93
|
+
|
|
94
|
+
**What actually degrades** without an instructions field is the *unprompted* behaviour: the
|
|
95
|
+
assistant is less likely to search before answering, or to save a decision you did not ask it
|
|
96
|
+
to save. If you find that happening, the instruction block is the fix — and on a host that has
|
|
97
|
+
no field for it, pasting it as your first message of a session works as a fallback.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Adding your own layer
|
|
102
|
+
|
|
103
|
+
Everything above is the minimum. Some people want more: a house style, project-specific
|
|
104
|
+
priorities, a checklist to run at session start.
|
|
105
|
+
|
|
106
|
+
Keep that separate from the memory instruction, and prefer putting it **in the store** rather
|
|
107
|
+
than in the paste. A document written with `write_doc` is read by every host and changed in
|
|
108
|
+
one place; text pasted into three different projects is three copies that will disagree within
|
|
109
|
+
a month.
|
|
110
|
+
|
|
111
|
+
The identity and user documents created by the setup interview
|
|
112
|
+
(`bootstrap/IDENTITY.md`, `bootstrap/USER.md`) are ordinary documents. Edit them with
|
|
113
|
+
`write_doc`, and every host sees the change on its next `emet_initialize`. That is the
|
|
114
|
+
intended place for "who this assistant is" to live.
|
|
115
|
+
|
|
116
|
+
**Your hosts and machines go in `bootstrap/INSTALL.md`** (or whatever `EMET_INSTALL_DOC`
|
|
117
|
+
names). The server cannot see which host or computer a session is running on, so it serves
|
|
118
|
+
this document whole at startup as `install_notes` and tells the assistant to run the checks
|
|
119
|
+
it names, in its order, before listing your items. Put in it what only you know: how to tell
|
|
120
|
+
your hosts apart, which machine is which and how to check, the session-id form you want, the
|
|
121
|
+
source tag each host should write under, and any tool quirks worth knowing before the first
|
|
122
|
+
call. Without it the assistant still mints a session id and picks a source tag from
|
|
123
|
+
`EMET_SOURCE_TAGS` - it just cannot check what it has not been told about.
|
|
124
|
+
|
|
125
|
+
Delivery preferences - how short, how plain, what to leave out - belong in
|
|
126
|
+
`bootstrap/USER.md`, not in a host's own memory feature. A preference kept by one vendor's
|
|
127
|
+
memory does not travel to the next host; the user document does.
|
package/docs/BOTS.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Running bots alongside your assistant
|
|
2
|
+
|
|
3
|
+
**Document control:** id `docs/BOTS.md` · tier 3, work instruction and reference (`templates/INDEX.md` hierarchy) · revision: the repository's history governs · status: DRAFT, for the user's review · owner: EMET (base) · forms it points to: `templates/ROSTER.md`, `templates/BOTHANDOFF.md` (both DRAFT) · rules it points to: `docs/DEPLOY.md` (bot records), `docs/GUARDRAILS-AND-MONORAILS.md` (bot sessions)
|
|
4
|
+
**Failure it prevents:** a bot set up by hand that the server did not treat as a bot, because its handoff id was never listed, found only when a live check's refusal came from the wrong rule (a live check of per-bot close records, 2026-10-01); and a bot close that could not finish because the bot never saved a session record with its session id, or saved one and never appended the exchange it was stamped with.
|
|
5
|
+
|
|
6
|
+
This is the reference for adding a bot — a separate agent with its own job, such as a reviewer, a tester or a scheduled intake run — to an EMET install that already serves you and your assistant. It states how a bot is registered and how a bot session runs. The rules themselves live in server code and in the documents named above; this page points to them and restates none of them as new rules.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. What changes when you add a bot
|
|
11
|
+
|
|
12
|
+
- **Your records stay yours.** `HANDOFF.md` and `STATE.md` hold only the conversation between you and your hub (§3). A bot keeps its own handoff, `bots/<tag>/HANDOFF.md`, and never writes yours: the server refuses it (§5) — **but only for tags listed in `EMET_RECORD_DOCS`.** An unlisted or misspelled tag is treated as a host. When `EMET_SOURCE_TAGS` is set, the main records and everything under `bots/` refuse any tag not registered there, a missing source included; a registered tag that is not listed as a bot can still write the main records and any bot's folder (a known gap). A listed bot also cannot write another bot's folder or `bots/ROSTER.md`. With `EMET_SOURCE_TAGS` unset, these guards are off. Register a bot (§4) before its first write.
|
|
13
|
+
- **A bot closes against its own record.** Its close checks its own handoff and seven receipts, and counts only revisions written under its own tag (`src/session.js` `BOT_RECEIPT_FIELDS`; `docs/GUARDRAILS-AND-MONORAILS.md`).
|
|
14
|
+
- **Nothing about your own sessions changes.** Host sessions keep their eight receipts and their verdict.
|
|
15
|
+
|
|
16
|
+
## 2. Naming the tag
|
|
17
|
+
|
|
18
|
+
- One bot, one source tag, used on every write the bot makes: `source` on documents and transcripts, `metadata.source` on layer entries.
|
|
19
|
+
- Form: `<prefix>-<bot name>`, lower case, letters, digits and hyphens, for example `bot-reviewer` or `bot-tester`. A prefix that names the platform the bots run on lets a reader tell bots from hosts at a glance. **No `/`**: a tag containing one is never a bot tag (`src/session-graph.js` `isBotTag`).
|
|
20
|
+
- A tag is never shared between bots and never reused after a bot is retired. The record has to be able to say who wrote what.
|
|
21
|
+
|
|
22
|
+
## 3. The hub is not a bot
|
|
23
|
+
|
|
24
|
+
If one agent talks to you on behalf of the others — relays their reports up and your decisions down — it is the **hub**. The hub writes your `HANDOFF.md` and `STATE.md` under host rules. **Its tag is registered as a host and is never listed in `EMET_RECORD_DOCS`**: a listed tag can no longer write the main records (`docs/DEPLOY.md`). The roster records the hub in its own section for exactly this reason. **The hub's tag must be in `EMET_SOURCE_TAGS`:** with a registry set, an unregistered tag is refused the main records and any write under `bots/`.
|
|
25
|
+
|
|
26
|
+
## 4. Registering a bot
|
|
27
|
+
|
|
28
|
+
Do these in order. Each step names what to read back. Steps 2 and 3 are **one change**: set `EMET_SOURCE_TAGS` and `EMET_RECORD_DOCS` together, in one deployment. A tag registered as a source but not yet listed as a bot is treated as a host in between.
|
|
29
|
+
|
|
30
|
+
1. **Roster row.** Add the bot to `bots/ROSTER.md`, filled from `templates/ROSTER.md`: tag, name, role, host, machine, handoff doc, tool profile, owner, status. The hub keeps the roster. Read back: `read_doc bots/ROSTER.md`.
|
|
31
|
+
2. **Register the tag as a source.** Append the tag to `EMET_SOURCE_TAGS` (comma list) on the deployment. Without it, the bot's transcript appends are refused (`src/dispatch.js` `requireRegisteredSource`). The operator reads the variable back from the deployment (a bot cannot read deployment settings from a session).
|
|
32
|
+
3. **Make the tag a bot tag.** Append `bots/<tag>/HANDOFF.md` to `EMET_RECORD_DOCS` (comma list). This one id is the only switch: nothing else — not the tag's prefix, not `EMET_SOURCE_TAGS`, not the roster — tells the server a tag is a bot (`src/session-graph.js` `isBotTag`; `docs/DEPLOY.md`).
|
|
33
|
+
- **Setting the variable replaces its value.** Keep every entry already there and append.
|
|
34
|
+
- The id must match exactly: the tag's exact case, no leading `./`. A typo silently leaves the tag on host rules.
|
|
35
|
+
- If your install still uses the legacy `CASCADE_RECORD_DOCS`, edit that one, or move its entries into `EMET_RECORD_DOCS`: once the `EMET_` name is set, the `CASCADE_` one is ignored.
|
|
36
|
+
- The ids are a deploy setting rather than code defaults on purpose: they name your bots, which differ per install, and removing one id puts that tag back on host rules without a release.
|
|
37
|
+
- Changing a variable redeploys the service. Note the new deployment id.
|
|
38
|
+
4. **Fill §3 of the roster** with the bot entries of both variables as read back, the date and the deployment id.
|
|
39
|
+
5. **Verify with one refused write — only once `HANDOFF.md` exists** (`list_docs HANDOFF.md` shows a version). On a new install with no handoff yet, skip this step until there is one: if the tag is not configured — the very case this step catches — the write would *create* the user's handoff. Then, under the bot's tag, `write_doc HANDOFF.md` with no `supersedes`. Expected reply: "HANDOFF.md is a main record and `<tag>` is a bot tag ... Nothing was written." If the reply says instead that HANDOFF.md "is a record and vN is in force", the tag is not a bot tag yet: check the id in step 3. If it says `<tag>` "is not a registered source tag", the tag is unregistered (step 2) and not yet a bot tag (step 3).
|
|
40
|
+
|
|
41
|
+
**Templates.** A bot's handoff is filled from `templates/BOTHANDOFF.md`. Do not map bot handoffs to `templates/HANDOFF.md`: that template asks for a board a bot does not keep, so every bot close would be marked nonconforming. While `templates/BOTHANDOFF.md` is DRAFT it is not mapped; once it is IN FORCE, map each bot with `bots/<tag>/HANDOFF.md=templates/BOTHANDOFF.md` in `EMET_TEMPLATE_MAP` (additive; append to any existing entries). Conformance marks a record and never rejects a write.
|
|
42
|
+
|
|
43
|
+
## 5. What a bot may never write
|
|
44
|
+
|
|
45
|
+
Under a tag listed in `EMET_RECORD_DOCS` (a bot tag), `write_doc`, `patch_doc`, `retire_doc`, `rename_doc` (from or onto) and `accept_nonconformance` refuse the main handoff and board, in every session-graph mode, and nothing is written (`src/tools.js` `refuseBotMainRecord`). A close whose session revised either is `incomplete`, and a receipt that names either is `blocked`. Anything the user must see goes to the hub, which carries it into the user's records.
|
|
46
|
+
|
|
47
|
+
A bot tag is also refused any write under `bots/` outside `bots/<tag>/`: other bots' records and `bots/ROSTER.md` are the hub's. When `EMET_SOURCE_TAGS` is set, the main handoff and board, and anything under `bots/`, refuse any source not registered there, a missing source included (a listed bot keeps writing and patching its own `bots/<tag>/` either way). Since startup stage 1, `retire_doc` and `rename_doc` are refused to a bot tag for every document, its own `bots/<tag>/` folder included (retiring and renaming are the owner's and the hub's), and `emet_setup_complete` is refused to a bot tag. Before either guard, the same five tools refuse a look-alike doc id: a leading `/`, a `.` or `..` segment, or `bots/` in the wrong case (`Bots/`); also a control or invisible formatting character anywhere (zero-width space, BOM, direction overrides), leading or trailing whitespace on the id or any segment, a backslash, the same `/`, `.`/`..` and `bots/` shapes after Unicode NFKC folding (full-width dots and slashes, `‥`, full-width letters; the first segment must be the ASCII `bots`), and a case or Unicode variant of a main-record id (`handoff.md`, ` HANDOFF.md`). Doc ids are flat strings, never resolved as paths or URL-decoded; there is no confusables table. One exception, for cleaning up ids written before these checks: `retire_doc`, and `rename_doc` from such an id onto a clean one, are let through for a tag listed in `EMET_SOURCE_TAGS` that is not a bot tag (never for a bot, an unlisted or missing tag, or with no registry set).
|
|
48
|
+
|
|
49
|
+
**These refusals cover listed tags only.** An unlisted or misspelled tag is treated as a host by the bot refusals. With `EMET_SOURCE_TAGS` set, the registry guard still refuses it the main records and `bots/`; a registered tag that is not listed as a bot is a host for both guards and can still write the main records (the handoff, given the version in force) and any bot's folder (a known gap). **With `EMET_SOURCE_TAGS` unset, neither guard applies; both are opt-in:** any caller can write the main records and every bot folder. Keep the roster's §3 read-back current and register every bot before it writes.
|
|
50
|
+
|
|
51
|
+
## 6. The bot session loop
|
|
52
|
+
|
|
53
|
+
One session per run, opened and closed by the bot itself.
|
|
54
|
+
|
|
55
|
+
1. `emet_initialize {}` and fetch every page it names (each page gives the exact call for the next); `{"page": "all"}` only on a host known to read long results whole, since the server counts a whole serve as fetched even if the host's connector cut it short. Keep `startup_page.load_id`. A read: nothing is written.
|
|
56
|
+
2. `emet_session_open` — a slug that names the bot and the job, and `load_id` from step 1. Keep the returned `session_id` and the start time (`session_start`). An open without `load_id`, before every page is fetched, or more than 60 minutes after the startup's last page (or after a server restart) is refused, and the refusal says what to call instead; nothing is written.
|
|
57
|
+
3. `emet_transcript_append` — exchange 1, `source: <tag>`.
|
|
58
|
+
4. `save_to_layer` — the session record on the episodic layer, with **`session_id`** and **`metadata.source: <tag>`**. The server stamps `derived_from` with the exchange *in progress*: the highest stored exchange plus one (`src/tools.js`, the A5 provenance stamp). Read it back.
|
|
59
|
+
5. `emet_transcript_append` — exchange 2, the one the save was stamped with. **Do not skip this:** without it the close reports that a layer entry cites an exchange that was never saved, and the close is `incomplete`.
|
|
60
|
+
6. `write_doc bots/<tag>/HANDOFF.md` — filled from `templates/BOTHANDOFF.md`, `source: <tag>`, written last. Revision 1 is written plain. **Every later revision is supersede-only:** pass `supersedes` set to the revision in force; `patch_doc` is refused on it, because it is a record.
|
|
61
|
+
7. `emet_session_close` — with `session_id`, `session_start` and the seven receipts: `working_docs` (`[]` if none), `episodic_id`, `transcript_session_id`, `transcript_parts`, `transcript_exchanges` (the highest exchange — 2 in the loop above), `handoff_doc` (`bots/<tag>/HANDOFF.md`), `handoff_version`. Expect `state: "complete"`, `closed_recorded: true`, and `checked.session_records` with `kind: "bot"` and the tag.
|
|
62
|
+
|
|
63
|
+
A bot with more exchanges appends after every reply as usual; the rule that matters is that the last append comes after the last layer save and before the handoff.
|
|
64
|
+
|
|
65
|
+
**Name every write attempt.** The user's approval of a bot's writes names each write call it covers, one per line: the tool, the document id or layer, and what it writes (for the loop above: `emet_session_open` with its `load_id`; `emet_transcript_append` exchange 1; `save_to_layer` episodic; `emet_transcript_append` exchange 2; `write_doc bots/<tag>/HANDOFF.md`; `emet_session_close`), including any deliberate negative test. The hub relays that list verbatim in the bot's brief, and the bot's report lists every write it attempted, from the raw replies. The second reader checks each attempted write against the approved list: a write not on it, a retry, or a write after the close is a finding. Reads (`emet_initialize` included) and dry runs (`validate_doc`) need no listing. This is what lets the second reader confirm that nothing was written beyond what the user approved.
|
|
66
|
+
|
|
67
|
+
## 7. Corrections
|
|
68
|
+
|
|
69
|
+
Nothing is edited in place and nothing is deleted.
|
|
70
|
+
|
|
71
|
+
- **The bot's handoff:** the next revision corrects it, with `supersedes`, and names the correction in its §4.
|
|
72
|
+
- **Episodic entries** are events and are never revised: a correction is a later entry that says what it corrects.
|
|
73
|
+
- **Semantic and procedural entries:** `revise_memory` writes a new entry that supersedes the old one; both stay readable.
|
|
74
|
+
- **Transcripts:** `revise_transcript` writes a corrected part that points at the one it replaces.
|
|
75
|
+
- **The roster:** a new revision with a §4 change-log row; a retired bot's row stays, marked RETIRED, and its handoff id is removed from `EMET_RECORD_DOCS` only when it will never write again.
|
|
76
|
+
|
|
77
|
+
## 8. Tool profiles
|
|
78
|
+
|
|
79
|
+
The server has no tool-profile mechanism: every connection sees every tool, and the refusals in §5 key on the tag, not on what a host offers. A roster's profile column records how the bot's host is configured. Profile names proposed for adoption are provisional until the user adopts them.
|
package/docs/COVERAGE.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Code coverage
|
|
2
|
+
|
|
3
|
+
Measured 2026-10-07 22:44 UTC at a pre-release commit, Node v22.14.0. Regenerate with `npm run coverage`.
|
|
4
|
+
|
|
5
|
+
**An input to review, not a gate** (owner's ruling 2026-09-29). No threshold fails the build; the number is here so a reviewer or auditor can see what the suite exercises and what it does not.
|
|
6
|
+
|
|
7
|
+
## Totals
|
|
8
|
+
|
|
9
|
+
- Lines: 89.6% (10286 of 11480 executable lines in src/)
|
|
10
|
+
- Functions: 91.2% (839 of 920 functions in loaded files)
|
|
11
|
+
- Files: 38 of 38 loaded by at least one suite
|
|
12
|
+
- Suites: 64 of 64 passed; 1852 checks passed, 0 failed
|
|
13
|
+
|
|
14
|
+
## Method
|
|
15
|
+
|
|
16
|
+
- Node's built-in V8 coverage (`NODE_V8_COVERAGE`), no dependency. Every suite runs in its own process; coverage from all of them is merged.
|
|
17
|
+
- A line counts when it is not blank and not wholly comment. It is covered when any suite ran the code at its first character.
|
|
18
|
+
- A function is covered when any suite called it. Functions are counted only in files a suite loaded.
|
|
19
|
+
- V8 does not report a function nested inside a function that never ran, so the function figure undercounts uncalled code and reads high. **The line figure is the one to trust.**
|
|
20
|
+
- A file no suite loads counts with every executable line uncovered - it is not left out.
|
|
21
|
+
- The comment scanner is simple: a quote or `//` inside a regular-expression literal can misjudge that one line.
|
|
22
|
+
|
|
23
|
+
## Per file, lowest line coverage first
|
|
24
|
+
|
|
25
|
+
| File | Lines covered | Lines | Functions called | Loaded by a suite |
|
|
26
|
+
|---|---|---|---|---|
|
|
27
|
+
| `src/env.js` | 42.9% | 12 / 28 | 2 / 2 | yes |
|
|
28
|
+
| `src/http-remote.js` | 53.4% | 102 / 191 | 9 / 14 | yes |
|
|
29
|
+
| `src/gaps.js` | 80.1% | 258 / 322 | 23 / 34 | yes |
|
|
30
|
+
| `src/dispatch.js` | 80.6% | 154 / 191 | 5 / 9 | yes |
|
|
31
|
+
| `src/index.js` | 80.7% | 205 / 254 | 7 / 13 | yes |
|
|
32
|
+
| `src/logger.js` | 81.9% | 177 / 216 | 22 / 25 | yes |
|
|
33
|
+
| `src/database.js` | 83.8% | 434 / 518 | 39 / 45 | yes |
|
|
34
|
+
| `src/tools.js` | 84.0% | 2703 / 3219 | 157 / 174 | yes |
|
|
35
|
+
| `src/setup.js` | 90.4% | 838 / 927 | 59 / 65 | yes |
|
|
36
|
+
| `src/oauth-provider.js` | 91.3% | 558 / 611 | 60 / 73 | yes |
|
|
37
|
+
| `src/session.js` | 94.6% | 739 / 781 | 60 / 61 | yes |
|
|
38
|
+
| `src/validation.js` | 95.3% | 702 / 737 | 31 / 31 | yes |
|
|
39
|
+
| `src/persons.js` | 95.4% | 83 / 87 | 10 / 11 | yes |
|
|
40
|
+
| `src/provenance.js` | 95.9% | 140 / 146 | 6 / 6 | yes |
|
|
41
|
+
| `src/conformance.js` | 95.9% | 377 / 393 | 45 / 45 | yes |
|
|
42
|
+
| `src/guides.js` | 96.0% | 24 / 25 | 4 / 4 | yes |
|
|
43
|
+
| `src/content_analyzer.js` | 96.3% | 233 / 242 | 13 / 14 | yes |
|
|
44
|
+
| `src/session-graph.js` | 96.4% | 541 / 561 | 76 / 78 | yes |
|
|
45
|
+
| `src/layers.js` | 97.0% | 318 / 328 | 13 / 13 | yes |
|
|
46
|
+
| `src/redact.js` | 97.1% | 102 / 105 | 19 / 20 | yes |
|
|
47
|
+
| `src/invites.js` | 97.7% | 129 / 132 | 8 / 8 | yes |
|
|
48
|
+
| `src/startup-pages.js` | 97.9% | 233 / 238 | 41 / 42 | yes |
|
|
49
|
+
| `src/named-items.js` | 98.3% | 175 / 178 | 22 / 23 | yes |
|
|
50
|
+
| `src/lessons-to-checks.js` | 99.7% | 291 / 292 | 24 / 25 | yes |
|
|
51
|
+
| `src/aleph.js` | 100.0% | 227 / 227 | 20 / 20 | yes |
|
|
52
|
+
| `src/annotations.js` | 100.0% | 45 / 45 | 4 / 4 | yes |
|
|
53
|
+
| `src/approve-throttle.js` | 100.0% | 31 / 31 | 6 / 6 | yes |
|
|
54
|
+
| `src/atlas-role.js` | 100.0% | 21 / 21 | 2 / 2 | yes |
|
|
55
|
+
| `src/disciplines.js` | 100.0% | 11 / 11 | 0 / 0 | yes |
|
|
56
|
+
| `src/floor.js` | 100.0% | 121 / 121 | 1 / 1 | yes |
|
|
57
|
+
| `src/metadata.js` | 100.0% | 21 / 21 | 3 / 3 | yes |
|
|
58
|
+
| `src/mongo-connect.js` | 100.0% | 20 / 20 | 4 / 5 | yes |
|
|
59
|
+
| `src/request-log.js` | 100.0% | 65 / 65 | 8 / 8 | yes |
|
|
60
|
+
| `src/scopes.js` | 100.0% | 43 / 43 | 9 / 9 | yes |
|
|
61
|
+
| `src/security-headers.js` | 100.0% | 18 / 18 | 3 / 3 | yes |
|
|
62
|
+
| `src/startup-payload.js` | 100.0% | 69 / 69 | 10 / 10 | yes |
|
|
63
|
+
| `src/transcript-session.js` | 100.0% | 65 / 65 | 14 / 14 | yes |
|
|
64
|
+
| `src/version.js` | 100.0% | 1 / 1 | 0 / 0 | yes |
|