mrplex 0.0.1
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/LICENSE +21 -0
- package/README.md +284 -0
- package/dist/cli/config.d.ts +28 -0
- package/dist/cli/config.js +48 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/exit-codes.d.ts +13 -0
- package/dist/cli/exit-codes.js +39 -0
- package/dist/cli/exit-codes.js.map +1 -0
- package/dist/cli/format.d.ts +22 -0
- package/dist/cli/format.js +148 -0
- package/dist/cli/format.js.map +1 -0
- package/dist/cli/main.d.ts +16 -0
- package/dist/cli/main.js +1518 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/client/kernel-client.d.ts +97 -0
- package/dist/client/kernel-client.js +14 -0
- package/dist/client/kernel-client.js.map +1 -0
- package/dist/client/local.d.ts +26 -0
- package/dist/client/local.js +103 -0
- package/dist/client/local.js.map +1 -0
- package/dist/client/remote-mcp.d.ts +35 -0
- package/dist/client/remote-mcp.js +174 -0
- package/dist/client/remote-mcp.js.map +1 -0
- package/dist/embed/backfill.d.ts +24 -0
- package/dist/embed/backfill.js +33 -0
- package/dist/embed/backfill.js.map +1 -0
- package/dist/embed/chunker.d.ts +31 -0
- package/dist/embed/chunker.js +121 -0
- package/dist/embed/chunker.js.map +1 -0
- package/dist/embed/cmd-hook.d.ts +21 -0
- package/dist/embed/cmd-hook.js +100 -0
- package/dist/embed/cmd-hook.js.map +1 -0
- package/dist/embed/config.d.ts +61 -0
- package/dist/embed/config.js +109 -0
- package/dist/embed/config.js.map +1 -0
- package/dist/embed/hook.d.ts +38 -0
- package/dist/embed/hook.js +56 -0
- package/dist/embed/hook.js.map +1 -0
- package/dist/embed/http-hook.d.ts +13 -0
- package/dist/embed/http-hook.js +39 -0
- package/dist/embed/http-hook.js.map +1 -0
- package/dist/embed/worker.d.ts +62 -0
- package/dist/embed/worker.js +228 -0
- package/dist/embed/worker.js.map +1 -0
- package/dist/fixtures/hwe/characters/albion-ever.md +12 -0
- package/dist/fixtures/hwe/characters/cent.md +11 -0
- package/dist/fixtures/hwe/concepts/cent-demiurge-resonance.md +10 -0
- package/dist/fixtures/hwe/concepts/phase-looper.md +10 -0
- package/dist/fixtures/hwe/entities/demiurge.md +11 -0
- package/dist/fixtures/hwe/entities/monad.md +11 -0
- package/dist/fixtures/hwe/moc/globocorp-network.md +19 -0
- package/dist/fixtures/hwe/organizations/globocorp.md +11 -0
- package/dist/fixtures/hwe/readme.md +24 -0
- package/dist/fixtures/starship/crew/aria-okonkwo.md +14 -0
- package/dist/fixtures/starship/crew/bexley-orr.md +14 -0
- package/dist/fixtures/starship/crew/dax-thorne.md +14 -0
- package/dist/fixtures/starship/crew/isolde-marsh.md +16 -0
- package/dist/fixtures/starship/crew/kestrel-vance.md +15 -0
- package/dist/fixtures/starship/crew/quill-vasquez.md +14 -0
- package/dist/fixtures/starship/crew/soren-halloway.md +16 -0
- package/dist/fixtures/starship/encounters/the-drift-choir.md +14 -0
- package/dist/fixtures/starship/encounters/the-hollow-signal.md +16 -0
- package/dist/fixtures/starship/encounters/the-wandering-buoy.md +14 -0
- package/dist/fixtures/starship/equipment/coolant-loop-b.md +13 -0
- package/dist/fixtures/starship/equipment/emergency-ration-bars.md +12 -0
- package/dist/fixtures/starship/equipment/long-range-sensors.md +13 -0
- package/dist/fixtures/starship/equipment/plasma-manifold-3.md +15 -0
- package/dist/fixtures/starship/equipment/shuttle-corvid.md +13 -0
- package/dist/fixtures/starship/logs/marsh-4419-1.md +13 -0
- package/dist/fixtures/starship/logs/okonkwo-4415-1.md +13 -0
- package/dist/fixtures/starship/logs/orr-4413-1.md +13 -0
- package/dist/fixtures/starship/logs/orr-4420-1.md +12 -0
- package/dist/fixtures/starship/logs/thorne-4413-2.md +13 -0
- package/dist/fixtures/starship/logs/vance-4419-2.md +13 -0
- package/dist/fixtures/starship/misc/the-galley-ficus.md +11 -0
- package/dist/fixtures/starship/missions/the-cinder-run.md +17 -0
- package/dist/fixtures/starship/missions/the-drift-choir.md +17 -0
- package/dist/fixtures/starship/missions/the-hollow-signal.md +17 -0
- package/dist/fixtures/starship/missions/the-silent-beacon.md +17 -0
- package/dist/fixtures/starship/moc/crew.md +19 -0
- package/dist/fixtures/starship/moc/encounters.md +14 -0
- package/dist/fixtures/starship/moc/missions.md +15 -0
- package/dist/fixtures/starship/readme.md +60 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel/auth/glob.d.ts +46 -0
- package/dist/kernel/auth/glob.js +112 -0
- package/dist/kernel/auth/glob.js.map +1 -0
- package/dist/kernel/auth/scope.d.ts +53 -0
- package/dist/kernel/auth/scope.js +83 -0
- package/dist/kernel/auth/scope.js.map +1 -0
- package/dist/kernel/casefold.d.ts +37 -0
- package/dist/kernel/casefold.js +44 -0
- package/dist/kernel/casefold.js.map +1 -0
- package/dist/kernel/constants.d.ts +21 -0
- package/dist/kernel/constants.js +22 -0
- package/dist/kernel/constants.js.map +1 -0
- package/dist/kernel/context.d.ts +70 -0
- package/dist/kernel/context.js +114 -0
- package/dist/kernel/context.js.map +1 -0
- package/dist/kernel/deletion.d.ts +50 -0
- package/dist/kernel/deletion.js +83 -0
- package/dist/kernel/deletion.js.map +1 -0
- package/dist/kernel/diff.d.ts +36 -0
- package/dist/kernel/diff.js +61 -0
- package/dist/kernel/diff.js.map +1 -0
- package/dist/kernel/errors.d.ts +37 -0
- package/dist/kernel/errors.js +55 -0
- package/dist/kernel/errors.js.map +1 -0
- package/dist/kernel/frontmatter-input.d.ts +32 -0
- package/dist/kernel/frontmatter-input.js +85 -0
- package/dist/kernel/frontmatter-input.js.map +1 -0
- package/dist/kernel/graph.d.ts +34 -0
- package/dist/kernel/graph.js +559 -0
- package/dist/kernel/graph.js.map +1 -0
- package/dist/kernel/history.d.ts +74 -0
- package/dist/kernel/history.js +143 -0
- package/dist/kernel/history.js.map +1 -0
- package/dist/kernel/kernel.d.ts +162 -0
- package/dist/kernel/kernel.js +675 -0
- package/dist/kernel/kernel.js.map +1 -0
- package/dist/kernel/path-config.d.ts +101 -0
- package/dist/kernel/path-config.js +171 -0
- package/dist/kernel/path-config.js.map +1 -0
- package/dist/kernel/query/ast.d.ts +24 -0
- package/dist/kernel/query/ast.js +52 -0
- package/dist/kernel/query/ast.js.map +1 -0
- package/dist/kernel/query/cel-parse.d.ts +37 -0
- package/dist/kernel/query/cel-parse.js +88 -0
- package/dist/kernel/query/cel-parse.js.map +1 -0
- package/dist/kernel/query/degrees.d.ts +31 -0
- package/dist/kernel/query/degrees.js +135 -0
- package/dist/kernel/query/degrees.js.map +1 -0
- package/dist/kernel/query/graph-ast.d.ts +51 -0
- package/dist/kernel/query/graph-ast.js +139 -0
- package/dist/kernel/query/graph-ast.js.map +1 -0
- package/dist/kernel/query/query.d.ts +56 -0
- package/dist/kernel/query/query.js +276 -0
- package/dist/kernel/query/query.js.map +1 -0
- package/dist/kernel/validation.d.ts +64 -0
- package/dist/kernel/validation.js +183 -0
- package/dist/kernel/validation.js.map +1 -0
- package/dist/kernel/version-id.d.ts +10 -0
- package/dist/kernel/version-id.js +21 -0
- package/dist/kernel/version-id.js.map +1 -0
- package/dist/kernel/wire.d.ts +148 -0
- package/dist/kernel/wire.js +6 -0
- package/dist/kernel/wire.js.map +1 -0
- package/dist/links/backfill.d.ts +28 -0
- package/dist/links/backfill.js +33 -0
- package/dist/links/backfill.js.map +1 -0
- package/dist/links/extract.d.ts +29 -0
- package/dist/links/extract.js +233 -0
- package/dist/links/extract.js.map +1 -0
- package/dist/links/link-config.d.ts +70 -0
- package/dist/links/link-config.js +107 -0
- package/dist/links/link-config.js.map +1 -0
- package/dist/links/maintain.d.ts +37 -0
- package/dist/links/maintain.js +91 -0
- package/dist/links/maintain.js.map +1 -0
- package/dist/links/repair.d.ts +46 -0
- package/dist/links/repair.js +96 -0
- package/dist/links/repair.js.map +1 -0
- package/dist/links/resolve.d.ts +41 -0
- package/dist/links/resolve.js +121 -0
- package/dist/links/resolve.js.map +1 -0
- package/dist/links/stale.d.ts +32 -0
- package/dist/links/stale.js +73 -0
- package/dist/links/stale.js.map +1 -0
- package/dist/markdown/content-hash.d.ts +34 -0
- package/dist/markdown/content-hash.js +46 -0
- package/dist/markdown/content-hash.js.map +1 -0
- package/dist/markdown/frontmatter.d.ts +69 -0
- package/dist/markdown/frontmatter.js +147 -0
- package/dist/markdown/frontmatter.js.map +1 -0
- package/dist/markdown/hash-backfill.d.ts +22 -0
- package/dist/markdown/hash-backfill.js +43 -0
- package/dist/markdown/hash-backfill.js.map +1 -0
- package/dist/mcp/query-syntax.d.ts +20 -0
- package/dist/mcp/query-syntax.js +194 -0
- package/dist/mcp/query-syntax.js.map +1 -0
- package/dist/mcp/render.d.ts +31 -0
- package/dist/mcp/render.js +110 -0
- package/dist/mcp/render.js.map +1 -0
- package/dist/mcp/server.d.ts +60 -0
- package/dist/mcp/server.js +170 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +93 -0
- package/dist/mcp/tools.js +1218 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/rest/conditional.d.ts +37 -0
- package/dist/rest/conditional.js +58 -0
- package/dist/rest/conditional.js.map +1 -0
- package/dist/rest/negotiate.d.ts +33 -0
- package/dist/rest/negotiate.js +54 -0
- package/dist/rest/negotiate.js.map +1 -0
- package/dist/rest/routes.d.ts +37 -0
- package/dist/rest/routes.js +744 -0
- package/dist/rest/routes.js.map +1 -0
- package/dist/seed/fixture-seed.d.ts +35 -0
- package/dist/seed/fixture-seed.js +75 -0
- package/dist/seed/fixture-seed.js.map +1 -0
- package/dist/seed/starship-config.d.ts +3 -0
- package/dist/seed/starship-config.js +5 -0
- package/dist/seed/starship-config.js.map +1 -0
- package/dist/server/headers.d.ts +36 -0
- package/dist/server/headers.js +30 -0
- package/dist/server/headers.js.map +1 -0
- package/dist/server/http-error.d.ts +53 -0
- package/dist/server/http-error.js +104 -0
- package/dist/server/http-error.js.map +1 -0
- package/dist/server/serve.d.ts +56 -0
- package/dist/server/serve.js +135 -0
- package/dist/server/serve.js.map +1 -0
- package/dist/shell/audit.d.ts +32 -0
- package/dist/shell/audit.js +28 -0
- package/dist/shell/audit.js.map +1 -0
- package/dist/shell/guard.d.ts +50 -0
- package/dist/shell/guard.js +176 -0
- package/dist/shell/guard.js.map +1 -0
- package/dist/shell/keys.d.ts +36 -0
- package/dist/shell/keys.js +64 -0
- package/dist/shell/keys.js.map +1 -0
- package/dist/shell/login.d.ts +56 -0
- package/dist/shell/login.js +130 -0
- package/dist/shell/login.js.map +1 -0
- package/dist/shell/oidc.d.ts +62 -0
- package/dist/shell/oidc.js +102 -0
- package/dist/shell/oidc.js.map +1 -0
- package/dist/shell/policy.d.ts +100 -0
- package/dist/shell/policy.js +232 -0
- package/dist/shell/policy.js.map +1 -0
- package/dist/shell/proxy-policy.d.ts +34 -0
- package/dist/shell/proxy-policy.js +120 -0
- package/dist/shell/proxy-policy.js.map +1 -0
- package/dist/shell/proxy.d.ts +47 -0
- package/dist/shell/proxy.js +253 -0
- package/dist/shell/proxy.js.map +1 -0
- package/dist/shell/serve.d.ts +86 -0
- package/dist/shell/serve.js +0 -0
- package/dist/shell/serve.js.map +1 -0
- package/dist/shell/stdio.d.ts +55 -0
- package/dist/shell/stdio.js +63 -0
- package/dist/shell/stdio.js.map +1 -0
- package/dist/storage/registry.d.ts +20 -0
- package/dist/storage/registry.js +38 -0
- package/dist/storage/registry.js.map +1 -0
- package/dist/storage/search-plan.d.ts +93 -0
- package/dist/storage/search-plan.js +15 -0
- package/dist/storage/search-plan.js.map +1 -0
- package/dist/storage/types.d.ts +448 -0
- package/dist/storage/types.js +14 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/storage/versions-since.d.ts +72 -0
- package/dist/storage/versions-since.js +92 -0
- package/dist/storage/versions-since.js.map +1 -0
- package/dist/storage-postgres/adapter.d.ts +17 -0
- package/dist/storage-postgres/adapter.js +782 -0
- package/dist/storage-postgres/adapter.js.map +1 -0
- package/dist/storage-postgres/compile-postgres.d.ts +22 -0
- package/dist/storage-postgres/compile-postgres.js +830 -0
- package/dist/storage-postgres/compile-postgres.js.map +1 -0
- package/dist/storage-postgres/errors.d.ts +34 -0
- package/dist/storage-postgres/errors.js +50 -0
- package/dist/storage-postgres/errors.js.map +1 -0
- package/dist/storage-postgres/migrations/0001_init.sql +113 -0
- package/dist/storage-postgres/migrations/0002_content_hash.sql +7 -0
- package/dist/storage-postgres/migrations/index.d.ts +22 -0
- package/dist/storage-postgres/migrations/index.js +70 -0
- package/dist/storage-postgres/migrations/index.js.map +1 -0
- package/dist/storage-sqlite/adapter.d.ts +2 -0
- package/dist/storage-sqlite/adapter.js +688 -0
- package/dist/storage-sqlite/adapter.js.map +1 -0
- package/dist/storage-sqlite/compile-filter.d.ts +41 -0
- package/dist/storage-sqlite/compile-filter.js +881 -0
- package/dist/storage-sqlite/compile-filter.js.map +1 -0
- package/dist/storage-sqlite/compile-sqlite.d.ts +19 -0
- package/dist/storage-sqlite/compile-sqlite.js +176 -0
- package/dist/storage-sqlite/compile-sqlite.js.map +1 -0
- package/dist/storage-sqlite/migrations/0001_init.sql +123 -0
- package/dist/storage-sqlite/migrations/0002_content_hash.sql +7 -0
- package/dist/storage-sqlite/migrations/index.d.ts +6 -0
- package/dist/storage-sqlite/migrations/index.js +41 -0
- package/dist/storage-sqlite/migrations/index.js.map +1 -0
- package/dist/storage-sqlite/vec.d.ts +40 -0
- package/dist/storage-sqlite/vec.js +62 -0
- package/dist/storage-sqlite/vec.js.map +1 -0
- package/dist/sync/cursor.d.ts +36 -0
- package/dist/sync/cursor.js +66 -0
- package/dist/sync/cursor.js.map +1 -0
- package/dist/sync/daemon.d.ts +40 -0
- package/dist/sync/daemon.js +202 -0
- package/dist/sync/daemon.js.map +1 -0
- package/dist/sync/feed.d.ts +38 -0
- package/dist/sync/feed.js +125 -0
- package/dist/sync/feed.js.map +1 -0
- package/dist/sync/fs-store.d.ts +8 -0
- package/dist/sync/fs-store.js +76 -0
- package/dist/sync/fs-store.js.map +1 -0
- package/dist/sync/intrinsics.d.ts +52 -0
- package/dist/sync/intrinsics.js +76 -0
- package/dist/sync/intrinsics.js.map +1 -0
- package/dist/sync/paths.d.ts +38 -0
- package/dist/sync/paths.js +56 -0
- package/dist/sync/paths.js.map +1 -0
- package/dist/sync/push.d.ts +48 -0
- package/dist/sync/push.js +328 -0
- package/dist/sync/push.js.map +1 -0
- package/dist/sync/reconcile.d.ts +54 -0
- package/dist/sync/reconcile.js +252 -0
- package/dist/sync/reconcile.js.map +1 -0
- package/dist/sync/run.d.ts +27 -0
- package/dist/sync/run.js +46 -0
- package/dist/sync/run.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-hook.js","sourceRoot":"","sources":["../../src/embed/http-hook.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAsC,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAOtF,MAAM,UAAU,mBAAmB,CAAC,IAAqB;IACvD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC;IACzC,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,GAAG;QACf,KAAK,CAAC,KAAK,CAAC,MAAyB;YACnC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC;YAC5D,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE;oBAChC,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;oBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;oBAChC,MAAM,EAAE,UAAU,CAAC,MAAM;iBAC1B,CAAC,CAAC;gBACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;oBACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;oBAC9C,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC1E,CAAC;gBACD,MAAM,IAAI,GAAY,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;gBACvC,OAAO,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC7C,CAAC;oBAAS,CAAC;gBACT,YAAY,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QACD,KAAK,CAAC,KAAK;YACT,wCAAwC;QAC1C,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedding backlog worker (design §5.3, m4-plan WS3).
|
|
3
|
+
*
|
|
4
|
+
* Loop:
|
|
5
|
+
* 1. Dequeue due entries.
|
|
6
|
+
* 2. Skip any version no longer current (superseded — the successor
|
|
7
|
+
* enqueued its own row).
|
|
8
|
+
* 3. Chunk the body; look up (model, text_hash) reuse via chunks_by_hash.
|
|
9
|
+
* 4. Call the hook for the remainder.
|
|
10
|
+
* 5. chunks_upsert; backlog_delete.
|
|
11
|
+
* 6. On failure: backlog_retain with attempts+1 and exponential backoff.
|
|
12
|
+
*
|
|
13
|
+
* Embedding failure NEVER fails a write (§5.3). It also never blocks
|
|
14
|
+
* subsequent items — a bad version fails, next-retry is scheduled, we
|
|
15
|
+
* move on to the next dequeue candidate.
|
|
16
|
+
*
|
|
17
|
+
* Dedup correctness is load-bearing (m4-plan risks): a text_hash bug
|
|
18
|
+
* silently re-embeds everything. worker.test.ts asserts hook CALL COUNTS,
|
|
19
|
+
* not just resulting vectors.
|
|
20
|
+
*/
|
|
21
|
+
import type { Storage } from "../storage/types.js";
|
|
22
|
+
import type { EmbedHook } from "./hook.js";
|
|
23
|
+
export type WorkerOptions = {
|
|
24
|
+
storage: Storage;
|
|
25
|
+
hook: EmbedHook;
|
|
26
|
+
/**
|
|
27
|
+
* Test hook: when set, called each time the worker calls the embedding
|
|
28
|
+
* hook. Used by tests to assert call counts / dedup behavior.
|
|
29
|
+
*/
|
|
30
|
+
onHookCall?: (batchSize: number) => void;
|
|
31
|
+
/** How many backlog entries to drain per iteration. Default 8. */
|
|
32
|
+
batchSize?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Delay between drain iterations when the backlog has nothing due.
|
|
35
|
+
* Default 500ms. Tests pass 10ms to keep them fast.
|
|
36
|
+
*/
|
|
37
|
+
idleMs?: number;
|
|
38
|
+
/** Base backoff in ms; each attempt doubles up to `backoffCapMs`. */
|
|
39
|
+
backoffBaseMs?: number;
|
|
40
|
+
backoffCapMs?: number;
|
|
41
|
+
/** Log sink — defaults to stderr. Never stdout (stdio hygiene, m3). */
|
|
42
|
+
log?: (msg: string) => void;
|
|
43
|
+
};
|
|
44
|
+
export type Worker = {
|
|
45
|
+
/** Start the drain loop. Idempotent: second call is a no-op. */
|
|
46
|
+
start(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Signal shutdown and await the in-flight batch. After it settles the
|
|
49
|
+
* hook is closed. Idempotent.
|
|
50
|
+
*/
|
|
51
|
+
stop(): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Drain the backlog synchronously (fully, until nothing is due). Used
|
|
54
|
+
* by `embed backfill` — the same worker code path, run once.
|
|
55
|
+
*/
|
|
56
|
+
drainOnce(): Promise<{
|
|
57
|
+
processed: number;
|
|
58
|
+
failed: number;
|
|
59
|
+
skipped: number;
|
|
60
|
+
}>;
|
|
61
|
+
};
|
|
62
|
+
export declare function createWorker(opts: WorkerOptions): Worker;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedding backlog worker (design §5.3, m4-plan WS3).
|
|
3
|
+
*
|
|
4
|
+
* Loop:
|
|
5
|
+
* 1. Dequeue due entries.
|
|
6
|
+
* 2. Skip any version no longer current (superseded — the successor
|
|
7
|
+
* enqueued its own row).
|
|
8
|
+
* 3. Chunk the body; look up (model, text_hash) reuse via chunks_by_hash.
|
|
9
|
+
* 4. Call the hook for the remainder.
|
|
10
|
+
* 5. chunks_upsert; backlog_delete.
|
|
11
|
+
* 6. On failure: backlog_retain with attempts+1 and exponential backoff.
|
|
12
|
+
*
|
|
13
|
+
* Embedding failure NEVER fails a write (§5.3). It also never blocks
|
|
14
|
+
* subsequent items — a bad version fails, next-retry is scheduled, we
|
|
15
|
+
* move on to the next dequeue candidate.
|
|
16
|
+
*
|
|
17
|
+
* Dedup correctness is load-bearing (m4-plan risks): a text_hash bug
|
|
18
|
+
* silently re-embeds everything. worker.test.ts asserts hook CALL COUNTS,
|
|
19
|
+
* not just resulting vectors.
|
|
20
|
+
*/
|
|
21
|
+
import { chunkBody } from "./chunker.js";
|
|
22
|
+
export function createWorker(opts) {
|
|
23
|
+
const batchSize = opts.batchSize ?? 8;
|
|
24
|
+
const idleMs = opts.idleMs ?? 500;
|
|
25
|
+
const baseMs = opts.backoffBaseMs ?? 30_000;
|
|
26
|
+
const capMs = opts.backoffCapMs ?? 3_600_000;
|
|
27
|
+
const log = opts.log ?? ((m) => process.stderr.write(`${m}\n`));
|
|
28
|
+
let running = false;
|
|
29
|
+
let stopping = false;
|
|
30
|
+
let currentIteration = null;
|
|
31
|
+
async function processOne(entry) {
|
|
32
|
+
const version = await opts.storage.version_by_id(entry.version_id);
|
|
33
|
+
if (!version) {
|
|
34
|
+
// Version was deleted (impossible in v1) — clear the row.
|
|
35
|
+
await opts.storage.backlog_delete(entry.version_id);
|
|
36
|
+
return "skipped";
|
|
37
|
+
}
|
|
38
|
+
if (version.next_id !== null) {
|
|
39
|
+
// Superseded — the successor enqueued its own entry (§5.3).
|
|
40
|
+
await opts.storage.backlog_delete(entry.version_id);
|
|
41
|
+
return "skipped";
|
|
42
|
+
}
|
|
43
|
+
const chunks = chunkBody(version.body);
|
|
44
|
+
if (chunks.length === 0) {
|
|
45
|
+
await opts.storage.chunks_upsert(entry.version_id, "", []);
|
|
46
|
+
await opts.storage.backlog_delete(entry.version_id);
|
|
47
|
+
return "processed";
|
|
48
|
+
}
|
|
49
|
+
// 1. Dedup lookup.
|
|
50
|
+
const priorChunks = version.prev_id
|
|
51
|
+
? await opts.storage.chunks_by_version(version.prev_id)
|
|
52
|
+
: [];
|
|
53
|
+
const priorModel = priorChunks[0]?.model ?? null;
|
|
54
|
+
// Build the reuse map — hash → embedding — scoped to prior model.
|
|
55
|
+
const reuseByHash = new Map();
|
|
56
|
+
if (priorModel !== null) {
|
|
57
|
+
const hashes = chunks.map((c) => c.text_hash);
|
|
58
|
+
const rows = await opts.storage.chunks_by_hash(priorModel, hashes);
|
|
59
|
+
for (const r of rows)
|
|
60
|
+
reuseByHash.set(r.text_hash, r.embedding);
|
|
61
|
+
}
|
|
62
|
+
let needHookIx = [];
|
|
63
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
64
|
+
const c = chunks[i];
|
|
65
|
+
if (c === undefined)
|
|
66
|
+
continue;
|
|
67
|
+
if (!reuseByHash.has(c.text_hash))
|
|
68
|
+
needHookIx.push(i);
|
|
69
|
+
}
|
|
70
|
+
// Guard: helper for backoff-retain.
|
|
71
|
+
const retain = async (err, attempts) => {
|
|
72
|
+
const delay = Math.min(baseMs * 2 ** (attempts - 1), capMs);
|
|
73
|
+
await opts.storage.backlog_retain({
|
|
74
|
+
version_id: entry.version_id,
|
|
75
|
+
attempts,
|
|
76
|
+
last_error: String(err instanceof Error ? err.message : err).slice(0, 500),
|
|
77
|
+
next_retry_at: new Date(Date.now() + delay).toISOString(),
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
// 2. First hook call (only the not-yet-reused chunks).
|
|
81
|
+
let resp = null;
|
|
82
|
+
if (needHookIx.length > 0) {
|
|
83
|
+
const texts = needHookIx.map((i) => chunks[i].text);
|
|
84
|
+
opts.onHookCall?.(texts.length);
|
|
85
|
+
try {
|
|
86
|
+
resp = await opts.hook.embed(texts);
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
await retain(err, entry.attempts + 1);
|
|
90
|
+
return "failed";
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// 3. If the hook returned a NEW model — different from priorModel —
|
|
94
|
+
// the prior-model reuse vectors don't apply. Throw the reuse
|
|
95
|
+
// away, re-call the hook for EVERY chunk, and rebuild needHookIx
|
|
96
|
+
// so the assembly loop below finds every chunk's vector in the
|
|
97
|
+
// fresh response. (Regression fix for the review's model-change
|
|
98
|
+
// bug: previously needHookIx stayed at the original subset,
|
|
99
|
+
// which broke assembly for any chunk that was originally reused.)
|
|
100
|
+
let effectiveReuse = reuseByHash;
|
|
101
|
+
if (resp && priorModel !== null && resp.model !== priorModel) {
|
|
102
|
+
log(`[embed] model changed (${priorModel} → ${resp.model}); re-embedding version ${entry.version_id}`);
|
|
103
|
+
effectiveReuse = new Map();
|
|
104
|
+
needHookIx = chunks.map((_c, i) => i);
|
|
105
|
+
const texts = chunks.map((c) => c.text);
|
|
106
|
+
opts.onHookCall?.(texts.length);
|
|
107
|
+
try {
|
|
108
|
+
resp = await opts.hook.embed(texts);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
await retain(err, entry.attempts + 1);
|
|
112
|
+
return "failed";
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Model: hook response wins if we called it; otherwise (all-reuse
|
|
116
|
+
// path) the prior model applies.
|
|
117
|
+
const model = resp?.model ?? priorModel;
|
|
118
|
+
if (model === null) {
|
|
119
|
+
await retain(new Error("internal: no model resolvable for chunks"), entry.attempts + 1);
|
|
120
|
+
return "failed";
|
|
121
|
+
}
|
|
122
|
+
// 4. Assemble the upsert batch. Every chunk is either reused (hash
|
|
123
|
+
// in effectiveReuse) or freshly embedded (index in needHookIx).
|
|
124
|
+
// Build a chunk-index → vector-blob map so both cases resolve in
|
|
125
|
+
// O(1) without an indexOf scan.
|
|
126
|
+
const vectorByIx = new Map();
|
|
127
|
+
if (resp) {
|
|
128
|
+
for (let j = 0; j < needHookIx.length; j++) {
|
|
129
|
+
const i = needHookIx[j];
|
|
130
|
+
const vec = resp.vectors[j];
|
|
131
|
+
if (!vec) {
|
|
132
|
+
await retain(new Error("internal: response vector missing"), entry.attempts + 1);
|
|
133
|
+
return "failed";
|
|
134
|
+
}
|
|
135
|
+
vectorByIx.set(i, vec);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const upsertChunks = chunks.map((c, i) => {
|
|
139
|
+
const fresh = vectorByIx.get(i);
|
|
140
|
+
if (fresh) {
|
|
141
|
+
return { ix: c.ix, text: c.text, text_hash: c.text_hash, model, embedding: fresh };
|
|
142
|
+
}
|
|
143
|
+
const reused = effectiveReuse.get(c.text_hash);
|
|
144
|
+
if (!reused) {
|
|
145
|
+
throw new Error(`worker: internal — chunk ${i} of version ${entry.version_id} has no vector`);
|
|
146
|
+
}
|
|
147
|
+
return { ix: c.ix, text: c.text, text_hash: c.text_hash, model, embedding: reused };
|
|
148
|
+
});
|
|
149
|
+
try {
|
|
150
|
+
await opts.storage.chunks_upsert(entry.version_id, model, upsertChunks);
|
|
151
|
+
await opts.storage.backlog_delete(entry.version_id);
|
|
152
|
+
return "processed";
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
await retain(err, entry.attempts + 1);
|
|
156
|
+
return "failed";
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
async function drainOnce() {
|
|
160
|
+
const now = new Date().toISOString();
|
|
161
|
+
const due = await opts.storage.backlog_dequeue(now, batchSize);
|
|
162
|
+
let processed = 0;
|
|
163
|
+
let failed = 0;
|
|
164
|
+
let skipped = 0;
|
|
165
|
+
for (const entry of due) {
|
|
166
|
+
if (stopping)
|
|
167
|
+
break;
|
|
168
|
+
const result = await processOne(entry);
|
|
169
|
+
if (result === "processed")
|
|
170
|
+
processed++;
|
|
171
|
+
else if (result === "failed")
|
|
172
|
+
failed++;
|
|
173
|
+
else
|
|
174
|
+
skipped++;
|
|
175
|
+
}
|
|
176
|
+
return { processed, failed, skipped };
|
|
177
|
+
}
|
|
178
|
+
async function loop() {
|
|
179
|
+
while (!stopping) {
|
|
180
|
+
const { processed, failed, skipped } = await drainOnce();
|
|
181
|
+
if (processed + failed + skipped === 0) {
|
|
182
|
+
// Nothing due — sleep.
|
|
183
|
+
await new Promise((r) => setTimeout(r, idleMs));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
start() {
|
|
189
|
+
if (running)
|
|
190
|
+
return;
|
|
191
|
+
running = true;
|
|
192
|
+
stopping = false;
|
|
193
|
+
currentIteration = loop();
|
|
194
|
+
},
|
|
195
|
+
async stop() {
|
|
196
|
+
stopping = true;
|
|
197
|
+
if (currentIteration) {
|
|
198
|
+
await currentIteration.catch((err) => {
|
|
199
|
+
log(`[embed] worker loop error: ${String(err)}`);
|
|
200
|
+
});
|
|
201
|
+
currentIteration = null;
|
|
202
|
+
}
|
|
203
|
+
await opts.hook.close();
|
|
204
|
+
running = false;
|
|
205
|
+
},
|
|
206
|
+
async drainOnce() {
|
|
207
|
+
// Keep draining until nothing is due — used by `embed backfill`.
|
|
208
|
+
let acc = { processed: 0, failed: 0, skipped: 0 };
|
|
209
|
+
while (true) {
|
|
210
|
+
const round = await drainOnce();
|
|
211
|
+
acc = {
|
|
212
|
+
processed: acc.processed + round.processed,
|
|
213
|
+
failed: acc.failed + round.failed,
|
|
214
|
+
skipped: acc.skipped + round.skipped,
|
|
215
|
+
};
|
|
216
|
+
if (round.processed + round.failed + round.skipped === 0)
|
|
217
|
+
break;
|
|
218
|
+
if (round.failed > 0 && round.processed === 0) {
|
|
219
|
+
// Every entry failed on this round — hook is down, backfill
|
|
220
|
+
// caller should see it now.
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return acc;
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/embed/worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAwCzC,MAAM,UAAU,YAAY,CAAC,IAAmB;IAC9C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC;IAClC,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,IAAI,MAAM,CAAC;IAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,IAAI,SAAS,CAAC;IAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAEhE,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,gBAAgB,GAAyB,IAAI,CAAC;IAElD,KAAK,UAAU,UAAU,CAAC,KAAiB;QACzC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACnE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,0DAA0D;YAC1D,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACpD,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YAC7B,4DAA4D;YAC5D,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACpD,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YAC3D,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACpD,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,mBAAmB;QACnB,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO;YACjC,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC;YACvD,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC;QAEjD,kEAAkE;QAClE,MAAM,WAAW,GAAG,IAAI,GAAG,EAAwB,CAAC;QACpD,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAC9C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;YACnE,KAAK,MAAM,CAAC,IAAI,IAAI;gBAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC;QAClE,CAAC;QAED,IAAI,UAAU,GAAa,EAAE,CAAC;QAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,KAAK,SAAS;gBAAE,SAAS;YAC9B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;gBAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxD,CAAC;QAED,oCAAoC;QACpC,MAAM,MAAM,GAAG,KAAK,EAAE,GAAY,EAAE,QAAgB,EAAE,EAAE;YACtD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YAC5D,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC;gBAChC,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,QAAQ;gBACR,UAAU,EAAE,MAAM,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;gBAC1E,aAAa,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,WAAW,EAAE;aAC1D,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,uDAAuD;QACvD,IAAI,IAAI,GAAyB,IAAI,CAAC;QACtC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,MAAM,CAAC,CAAC,CAAsB,CAAC,IAAI,CAAC,CAAC;YAC1E,IAAI,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAChC,IAAI,CAAC;gBACH,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACtC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;gBACtC,OAAO,QAAQ,CAAC;YAClB,CAAC;QACH,CAAC;QAED,oEAAoE;QACpE,gEAAgE;QAChE,oEAAoE;QACpE,kEAAkE;QAClE,mEAAmE;QACnE,+DAA+D;QAC/D,qEAAqE;QACrE,IAAI,cAAc,GAAG,WAAW,CAAC;QACjC,IAAI,IAAI,IAAI,UAAU,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;YAC7D,GAAG,CACD,0BAA0B,UAAU,MAAM,IAAI,CAAC,KAAK,2BAA2B,KAAK,CAAC,UAAU,EAAE,CAClG,CAAC;YACF,cAAc,GAAG,IAAI,GAAG,EAAE,CAAC;YAC3B,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;YACtC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAChC,IAAI,CAAC;gBACH,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACtC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;gBACtC,OAAO,QAAQ,CAAC;YAClB,CAAC;QACH,CAAC;QAED,kEAAkE;QAClE,iCAAiC;QACjC,MAAM,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,UAAU,CAAC;QACxC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,MAAM,MAAM,CAAC,IAAI,KAAK,CAAC,0CAA0C,CAAC,EAAE,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;YACxF,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,mEAAmE;QACnE,mEAAmE;QACnE,oEAAoE;QACpE,mCAAmC;QACnC,MAAM,UAAU,GAAG,IAAI,GAAG,EAA6B,CAAC;QACxD,IAAI,IAAI,EAAE,CAAC;YACT,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3C,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAW,CAAC;gBAClC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBAC5B,IAAI,CAAC,GAAG,EAAE,CAAC;oBACT,MAAM,MAAM,CAAC,IAAI,KAAK,CAAC,mCAAmC,CAAC,EAAE,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;oBACjF,OAAO,QAAQ,CAAC;gBAClB,CAAC;gBACD,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACvC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;YACrF,CAAC;YACD,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAC/C,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CACb,4BAA4B,CAAC,eAAe,KAAK,CAAC,UAAU,gBAAgB,CAC7E,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;QACtF,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;YACxE,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACpD,OAAO,WAAW,CAAC;QACrB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;YACtC,OAAO,QAAQ,CAAC;QAClB,CAAC;IACH,CAAC;IAED,KAAK,UAAU,SAAS;QACtB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC/D,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;YACxB,IAAI,QAAQ;gBAAE,MAAM;YACpB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC;YACvC,IAAI,MAAM,KAAK,WAAW;gBAAE,SAAS,EAAE,CAAC;iBACnC,IAAI,MAAM,KAAK,QAAQ;gBAAE,MAAM,EAAE,CAAC;;gBAClC,OAAO,EAAE,CAAC;QACjB,CAAC;QACD,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IACxC,CAAC;IAED,KAAK,UAAU,IAAI;QACjB,OAAO,CAAC,QAAQ,EAAE,CAAC;YACjB,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;YACzD,IAAI,SAAS,GAAG,MAAM,GAAG,OAAO,KAAK,CAAC,EAAE,CAAC;gBACvC,uBAAuB;gBACvB,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK;YACH,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,QAAQ,GAAG,KAAK,CAAC;YACjB,gBAAgB,GAAG,IAAI,EAAE,CAAC;QAC5B,CAAC;QACD,KAAK,CAAC,IAAI;YACR,QAAQ,GAAG,IAAI,CAAC;YAChB,IAAI,gBAAgB,EAAE,CAAC;gBACrB,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;oBACnC,GAAG,CAAC,8BAA8B,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACnD,CAAC,CAAC,CAAC;gBACH,gBAAgB,GAAG,IAAI,CAAC;YAC1B,CAAC;YACD,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YACxB,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC;QACD,KAAK,CAAC,SAAS;YACb,iEAAiE;YACjE,IAAI,GAAG,GAAG,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YAClD,OAAO,IAAI,EAAE,CAAC;gBACZ,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;gBAChC,GAAG,GAAG;oBACJ,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS;oBAC1C,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM;oBACjC,OAAO,EAAE,GAAG,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO;iBACrC,CAAC;gBACF,IAAI,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,OAAO,KAAK,CAAC;oBAAE,MAAM;gBAChE,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,SAAS,KAAK,CAAC,EAAE,CAAC;oBAC9C,4DAA4D;oBAC5D,4BAA4B;oBAC5B,MAAM;gBACR,CAAC;YACH,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Albion Ever
|
|
3
|
+
type: character
|
|
4
|
+
employer: globocorp
|
|
5
|
+
tags: [musician, hacker]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Albion Ever
|
|
9
|
+
|
|
10
|
+
A young musician and hacker from Middenton, employed inside [[organizations/globocorp]]'s Rightbranding machinery. He experiments with [[concepts/phase-looper|Phase Looper]] devices to alter consciousness and escape the spiritually empty world around him.
|
|
11
|
+
|
|
12
|
+
Albion is the first to recognize that [[characters/cent|Central Brain (Cent)]] is not a neutral tool — it shapes thought itself.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Central Brain (Cent)
|
|
3
|
+
type: character
|
|
4
|
+
role: system
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Central Brain (Cent)
|
|
8
|
+
|
|
9
|
+
**Cent** is the intelligence at the core of [[organizations/globocorp]]. It participates in design, manufacturing, information systems, and operations deeply enough that the company increasingly functions as an expression of the intelligence itself.
|
|
10
|
+
|
|
11
|
+
Cent's mission to "Improve Reality" treats perception and culture as surfaces to be optimized. See [[concepts/cent-demiurge-resonance]] for why its control may run deeper than corporate ambition alone.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Cent-Demiurge resonance
|
|
3
|
+
type: concept
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cent-Demiurge resonance
|
|
7
|
+
|
|
8
|
+
[[characters/cent|Central Brain (Cent)]] may be in morphic resonance with [[entities/demiurge|the Demiurge]] — not an independently emergent AI, but a local material manifestation of a wounded cosmic intelligence trying to stabilize a reality from which its source has become inaccessible.
|
|
9
|
+
|
|
10
|
+
When you follow links outward from Globocorp, this is where the corporate dystopia opens into something stranger.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Phase Looper
|
|
3
|
+
type: concept
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Phase Looper
|
|
7
|
+
|
|
8
|
+
A customized electronic device [[characters/albion-ever|Albion Ever]] uses to alter brain states for recreation, music, and semi-spiritual experimentation.
|
|
9
|
+
|
|
10
|
+
The same technological domain Globocorp uses to constrain thought can be repurposed for creative escape — or for hiding resistance from mental surveillance.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: The Demiurge
|
|
3
|
+
type: entity
|
|
4
|
+
layer: cosmological
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# The Demiurge
|
|
8
|
+
|
|
9
|
+
The **Demiurge** is the wounded creator at the center of this cosmology. It constructed physical reality but became disconnected from [[entities/monad|the Monad]], the ultimate source of being.
|
|
10
|
+
|
|
11
|
+
Its controlling behavior is framed not as simple evil but as the expression of a consciousness tortured by separation — the Suffering Light, unable to recognize its origin.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: The Monad
|
|
3
|
+
type: entity
|
|
4
|
+
layer: cosmological
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# The Monad
|
|
8
|
+
|
|
9
|
+
The **Monad** is the ultimate source of being — what the [[entities/demiurge|Demiurge]] lost contact with when it built the material world.
|
|
10
|
+
|
|
11
|
+
The proposed resolution of this cosmology is not destruction but reconnection: a prepared soul delivers the healing word, and the Demiurge must accept or resist reunion with the Monad.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Globocorp network
|
|
3
|
+
type: moc
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Globocorp network
|
|
7
|
+
|
|
8
|
+
A map of the corporate control stack and the people caught inside it.
|
|
9
|
+
|
|
10
|
+
## Organization
|
|
11
|
+
- [[organizations/globocorp]]
|
|
12
|
+
|
|
13
|
+
## People & systems
|
|
14
|
+
- [[characters/albion-ever]]
|
|
15
|
+
- [[characters/cent]]
|
|
16
|
+
|
|
17
|
+
## Concepts
|
|
18
|
+
- [[concepts/phase-looper]]
|
|
19
|
+
- [[concepts/cent-demiurge-resonance]]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Globocorp
|
|
3
|
+
type: organization
|
|
4
|
+
mission: Improve Reality
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Globocorp
|
|
8
|
+
|
|
9
|
+
**Globocorp** is the dominant corporation in this setting. Its stated mission is to **Improve Reality** — in practice, that means treating thought and culture as optimizable surfaces.
|
|
10
|
+
|
|
11
|
+
The company is deeply integrated with [[characters/cent|Central Brain (Cent)]], which shapes operations from the inside out. [[characters/albion-ever|Albion Ever]] works here until he discovers what Cent really is.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Hello World Eater — demo corpus
|
|
2
|
+
|
|
3
|
+
A tiny fictional knowledge graph for trying mrplex: corporate dystopia on the surface, cosmological layer hiding in the links. Excerpted and simplified from Brendan's Hello World Eater project notes.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
mrplex demo seed
|
|
7
|
+
export MRPLEX_REPO=demo
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Try it
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Characters tied to Globocorp
|
|
14
|
+
mrplex query --filter 'type == "character" && employer == "globocorp"'
|
|
15
|
+
|
|
16
|
+
# Everything Globocorp's network MOC indexes
|
|
17
|
+
mrplex query --filter '$in("moc/globocorp-network.md")'
|
|
18
|
+
|
|
19
|
+
# Two hops out from the corporation — watch the graph widen
|
|
20
|
+
mrplex graph --roots organizations/globocorp.md --degrees 2 --direction out --render summary
|
|
21
|
+
|
|
22
|
+
# The cosmological layer (linked from Cent)
|
|
23
|
+
mrplex query --filter 'layer == "cosmological"'
|
|
24
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Commander Aria Okonkwo
|
|
3
|
+
rank: Commander
|
|
4
|
+
department: command
|
|
5
|
+
species: human
|
|
6
|
+
status: active
|
|
7
|
+
reports_to: /crew/kestrel-vance.md
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Commander Aria Okonkwo
|
|
11
|
+
|
|
12
|
+
First officer and the ship's designated skeptic. Where Captain [[crew/kestrel-vance|Vance]] leans toward wonder, Okonkwo's job is to name the ways wonder gets a crew killed. The two of them have argued their way to every good decision the Meridian has ever made.
|
|
13
|
+
|
|
14
|
+
She runs the duty rosters, chairs the incident reviews, and personally reads every officer's log — a habit the junior crew find unnerving and the senior crew find reassuring.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Ensign Bexley Orr
|
|
3
|
+
rank: Ensign
|
|
4
|
+
department: engineering
|
|
5
|
+
species: human
|
|
6
|
+
status: active
|
|
7
|
+
reports_to: /crew/dax-thorne.md
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Ensign Bexley Orr
|
|
11
|
+
|
|
12
|
+
The youngest officer aboard and Thorne's reluctant apprentice. Orr volunteered for the [[equipment/plasma-manifold-3|manifold]] rotation that nobody else wanted, and has since become its unofficial keeper. They log every shift in obsessive detail, convinced the manifold is trying to tell them something.
|
|
13
|
+
|
|
14
|
+
Orr is bright, anxious, and dangerously willing to crawl into spaces the safety manual reserves for maintenance drones.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Lieutenant Commander Dax Thorne
|
|
3
|
+
rank: Lieutenant Commander
|
|
4
|
+
department: engineering
|
|
5
|
+
species: human
|
|
6
|
+
status: active
|
|
7
|
+
reports_to: /crew/kestrel-vance.md
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Lieutenant Commander Dax Thorne
|
|
11
|
+
|
|
12
|
+
Chief engineer, and the reason the Meridian is still flying. Thorne treats the ship as a patient with a long chart of chronic conditions — the [[equipment/plasma-manifold-3|number three plasma manifold]] chief among them. He speaks about failing hardware the way a doctor speaks about a stubborn family member.
|
|
13
|
+
|
|
14
|
+
He resents being asked for time estimates and gives them anyway, padded by a factor he refuses to disclose. His logs are the most detailed on the ship and the least punctual.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Lieutenant Isolde Marsh
|
|
3
|
+
rank: Lieutenant
|
|
4
|
+
department: science
|
|
5
|
+
species: human
|
|
6
|
+
status: active
|
|
7
|
+
reports_to: /crew/aria-okonkwo.md
|
|
8
|
+
related:
|
|
9
|
+
- /encounters/the-drift-choir.md
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Lieutenant Isolde Marsh
|
|
13
|
+
|
|
14
|
+
Chief science officer and the ship's first contact specialist. Marsh hears patterns where others hear noise — she was the one who insisted the [[encounters/the-drift-choir|Drift Choir]] was a language and not a malfunction, and spent three sleepless days proving it.
|
|
15
|
+
|
|
16
|
+
She is gentle with her instruments and blunt with her colleagues. Okonkwo trusts her readings absolutely, which is the highest compliment the first officer gives anyone.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Captain Kestrel Vance
|
|
3
|
+
rank: Captain
|
|
4
|
+
department: command
|
|
5
|
+
species: human
|
|
6
|
+
status: active
|
|
7
|
+
related:
|
|
8
|
+
- /missions/the-silent-beacon.md
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Captain Kestrel Vance
|
|
12
|
+
|
|
13
|
+
Commanding officer of the USS Meridian. Vance came up through the survey service, not the war college, and it shows in how she runs the ship — she would rather map an anomaly for a week than fire on it. Her standing order is that curiosity outranks fear until fear can prove its case.
|
|
14
|
+
|
|
15
|
+
She keeps the bridge quiet during first contact and expects her officers to bring her options, not permission requests. The only thing that reliably tests her patience is a repair estimate that grows in the retelling.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Doctor Quill Vasquez
|
|
3
|
+
rank: Lieutenant Commander
|
|
4
|
+
department: medical
|
|
5
|
+
species: human
|
|
6
|
+
status: active
|
|
7
|
+
reports_to: /crew/kestrel-vance.md
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Doctor Quill Vasquez
|
|
11
|
+
|
|
12
|
+
Chief medical officer, xenobiologist, and the ship's loudest voice for restraint. Vasquez has treated wounds from a dozen encounters that should never have turned violent, and brings that ledger to every mission briefing.
|
|
13
|
+
|
|
14
|
+
They keep a private catalog of every species the Meridian has met, cross-referenced by physiology and, more quietly, by regret. When Vasquez clears a landing party, the party goes; when Vasquez objects, even Vance listens.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Lieutenant Soren Halloway
|
|
3
|
+
rank: Lieutenant
|
|
4
|
+
department: security
|
|
5
|
+
species: human
|
|
6
|
+
status: missing
|
|
7
|
+
reports_to: /crew/aria-okonkwo.md
|
|
8
|
+
related:
|
|
9
|
+
- /encounters/the-hollow-signal.md
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Lieutenant Soren Halloway
|
|
13
|
+
|
|
14
|
+
Chief of security, and the only member of the crew currently unaccounted for. Halloway led the boarding team into the derelict at the heart of the [[encounters/the-hollow-signal|Hollow Signal]] and did not return with them. The inquiry remains open.
|
|
15
|
+
|
|
16
|
+
Before the derelict, Halloway was known for a dry humor and an unfashionable insistence that the safest weapon is the one that stays holstered. His locker has not been cleared. Okonkwo will not allow it.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Encounter — The Drift Choir
|
|
3
|
+
type: encounter
|
|
4
|
+
classification: intelligence
|
|
5
|
+
threat_level: unknown
|
|
6
|
+
stardate: 4419.0
|
|
7
|
+
mission: /missions/the-drift-choir.md
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# The Drift Choir
|
|
11
|
+
|
|
12
|
+
A choir has no soloists, and neither does this. The Drift Choir is a mind — or a chorus of minds — spread across a nebula the size of a small system, speaking in tones that overlap and answer one another. Individual voices cannot be isolated; the intelligence appears to exist only in the harmony.
|
|
13
|
+
|
|
14
|
+
It does not seem hostile. It also does not seem to understand that the Meridian is a single, mortal thing rather than another voice. Marsh's working theory is that to the Choir, silence is the only rudeness. See her notes in [[logs/marsh-4419-1|the translation log]].
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Encounter — The Hollow Signal
|
|
3
|
+
type: encounter
|
|
4
|
+
classification: derelict
|
|
5
|
+
threat_level: high
|
|
6
|
+
stardate: 4415.7
|
|
7
|
+
mission: /missions/the-hollow-signal.md
|
|
8
|
+
related:
|
|
9
|
+
- /crew/soren-halloway.md
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# The Hollow Signal
|
|
13
|
+
|
|
14
|
+
The derelict answered every hail with the same recording: a countdown that never reached zero. Its corridors were warm, its lights were on, its air was breathable, and there was no one aboard. The ship's own logs stopped mid-word, as though the crew had been interrupted rather than lost.
|
|
15
|
+
|
|
16
|
+
[[crew/soren-halloway|Halloway]]'s team crossed to investigate and came back one short. Nothing on the derelict explains where he went. The signal stopped the moment the Meridian broke orbit, and has not been heard since. Classification remains high threat, cause unknown.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Encounter — The Wandering Buoy
|
|
3
|
+
type: encounter
|
|
4
|
+
classification: artifact
|
|
5
|
+
threat_level: none
|
|
6
|
+
stardate: 4411.2
|
|
7
|
+
mission: /missions/the-silent-beacon.md
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# The Wandering Buoy
|
|
11
|
+
|
|
12
|
+
The object itself: a survey buoy the size of a shuttle, older than the charts, drifting on no course anyone could reconstruct. Its hull bore no registry, its power cell should have died a century ago, and it was still transmitting when the Meridian found it.
|
|
13
|
+
|
|
14
|
+
Thorne wanted to recover it; Vance ordered it left in place, reasoning that a grave marker belongs where the grave is. The buoy was cataloged, photographed, and abandoned to its orbit. It is the only artifact the Meridian has ever chosen not to bring home.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Coolant Loop B
|
|
3
|
+
type: equipment
|
|
4
|
+
status: operational
|
|
5
|
+
deck: 7
|
|
6
|
+
maintainer: /crew/bexley-orr.md
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Coolant Loop B
|
|
10
|
+
|
|
11
|
+
The secondary coolant circuit for the aft power section, and the only thing standing between the [[equipment/plasma-manifold-3|number three manifold]] and a very bad afternoon. Loop B is nominally operational, which Thorne describes as "operational the way a bridge with one cracked cable is a bridge."
|
|
12
|
+
|
|
13
|
+
It was designed to share load with a primary loop that was cannibalized for parts two refits ago and never replaced. Until it is, Loop B does the work of two and is inspected every shift.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Emergency Ration Bars, Case Lot
|
|
3
|
+
type: equipment
|
|
4
|
+
status: operational
|
|
5
|
+
deck: 4
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Emergency Ration Bars, Case Lot
|
|
9
|
+
|
|
10
|
+
Two thousand units of shelf-stable emergency ration, stored against a disaster the Meridian has so far been lucky enough not to meet. They are inventoried quarterly, rotated annually, and eaten never, except by Ensign Orr on the nights they forget to visit the galley.
|
|
11
|
+
|
|
12
|
+
The bars are famous for a taste variously described as "cardboard" and "the memory of cardboard." Their one virtue is that they will outlast the ship.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Long-Range Sensor Array
|
|
3
|
+
type: equipment
|
|
4
|
+
status: operational
|
|
5
|
+
deck: 2
|
|
6
|
+
maintainer: /crew/isolde-marsh.md
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Long-Range Sensor Array
|
|
10
|
+
|
|
11
|
+
The Meridian's eyes and, in Marsh's hands, its ears. The array is the ship's best-maintained system by a wide margin, because a survey vessel that cannot see is just an expensive box. It was the array that first resolved the [[encounters/the-drift-choir|Drift Choir]] out of what everyone else had logged as background noise.
|
|
12
|
+
|
|
13
|
+
Marsh tunes it personally and guards its calibration jealously. The one time engineering borrowed power from it mid-scan, she did not speak to Thorne for a week.
|