@dikolab/kbdb 0.4.3 → 0.6.0
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/CLA.md +68 -0
- package/LICENSE +676 -12
- package/LICENSING.md +58 -0
- package/README.md +50 -27
- package/README.md.bak +320 -0
- package/dist/README.md +320 -0
- package/dist/{chunk-BJXEVALU.mjs → chunk-QLJ33C74.mjs} +44 -44
- package/dist/chunk-QLJ33C74.mjs.map +7 -0
- package/dist/cli.cjs +550 -232
- package/dist/cli.cjs.map +4 -4
- package/dist/cli.d.ts +0 -8
- package/dist/cli.mjs +483 -154
- package/dist/cli.mjs.map +4 -4
- package/dist/kbdb-worker.cjs +36 -5
- package/dist/kbdb-worker.cjs.map +3 -3
- package/dist/mod.cjs +89 -30
- package/dist/mod.cjs.map +4 -4
- package/dist/mod.mjs +88 -30
- package/dist/mod.mjs.map +4 -4
- package/dist/src/cli.d.ts +0 -8
- package/dist/src/shared/cli/constants/defaults.constant.d.ts +1 -1
- package/dist/src/shared/cli/constants/recfile-command-field-map.constant.d.ts +8 -0
- package/dist/src/shared/cli/constants/recfile-field-maps.constant.d.ts +21 -0
- package/dist/src/shared/cli/functions/compute-directory-level.function.d.ts +14 -0
- package/dist/src/shared/cli/functions/dispatch-command.function.d.ts +2 -28
- package/dist/src/shared/cli/functions/format-command-output.function.d.ts +14 -0
- package/dist/src/shared/cli/functions/format-db-not-found.function.d.ts +20 -0
- package/dist/src/shared/cli/functions/format-output.function.d.ts +1 -0
- package/dist/src/shared/cli/functions/format-recfile-output.function.d.ts +11 -0
- package/dist/src/shared/cli/functions/render-recfile-value.function.d.ts +11 -0
- package/dist/src/shared/cli/functions/resolve-db-dir.function.d.ts +24 -0
- package/dist/src/shared/cli/functions/resolve-recfile-key.function.d.ts +9 -0
- package/dist/src/shared/cli/functions/run-db-path.function.d.ts +10 -0
- package/dist/src/shared/cli/functions/run-export.function.d.ts +8 -4
- package/dist/src/shared/cli/functions/run-import.function.d.ts +4 -0
- package/dist/src/shared/cli/functions/run-learn.function.d.ts +12 -0
- package/dist/src/shared/cli/index.d.ts +4 -1
- package/dist/src/shared/cli/typings/cli-options.interface.d.ts +9 -2
- package/dist/src/shared/cli/typings/db-resolution.interface.d.ts +9 -0
- package/dist/src/shared/cli/typings/recfile-field-map.type.d.ts +10 -0
- package/dist/src/shared/version/constants/version.constant.d.ts +1 -1
- package/dist/src/shared/wasm-codec/functions/decode-option-u8.function.d.ts +9 -0
- package/dist/src/shared/wasm-codec/functions/decode-section-records.function.d.ts +4 -0
- package/dist/src/shared/wasm-codec/functions/encode-add-section-params.function.d.ts +2 -45
- package/dist/src/shared/wasm-codec/functions/encode-update-section-params.function.d.ts +10 -1
- package/dist/src/shared/wasm-codec/index.d.ts +1 -1
- package/dist/src/shared/wasm-codec/typings/add-section-input.model.d.ts +6 -0
- package/dist/src/shared/wasm-codec/typings/section-record-trailing.model.d.ts +5 -0
- package/dist/src/shared/wasm-codec/typings/section-record.model.d.ts +5 -0
- package/dist/src/shared/worker-client/functions/build-deno-permissions.function.d.ts +11 -0
- package/dist/src/shared/worker-client/functions/read-crash-reason.function.d.ts +9 -0
- package/dist/src/shared/worker-client/functions/resolve-spawn-script.function.d.ts +6 -0
- package/dist/src/shared/worker-client/functions/spawn-daemon.function.d.ts +1 -1
- package/dist/src/shared/worker-client/typings/section.model.d.ts +5 -0
- package/dist/src/shared/worker-client/typings/worker-client-options.interface.d.ts +0 -6
- package/dist/src/shared/worker-daemon/functions/count-files.function.d.ts +12 -0
- package/dist/src/shared/worker-daemon/functions/handle-import.function.d.ts +2 -0
- package/dist/src/shared/worker-daemon/functions/handle-read-ops.function.d.ts +8 -0
- package/dist/src/shared/worker-daemon/functions/validate-daemon-path.function.d.ts +15 -0
- package/dist/src/worker.d.ts +0 -7
- package/dist/wasm/default-embedding/kbdb_default_embedding_bg.wasm +0 -0
- package/dist/wasm/default-embedding/package.json +1 -1
- package/dist/wasm/fs-database/kbdb_fs_database_bg.wasm +0 -0
- package/dist/wasm/fs-database/package.json +1 -1
- package/dist/wasm/fs-migration/kbdb_fs_migration_bg.wasm +0 -0
- package/dist/wasm/fs-migration/package.json +1 -1
- package/dist/wasm/kb-worker/kbdb_worker_bg.wasm +0 -0
- package/dist/wasm/kb-worker/package.json +1 -1
- package/dist/wasm/query-parser/kbdb_query_parser_bg.wasm +0 -0
- package/dist/wasm/query-parser/package.json +1 -1
- package/dist/worker.d.ts +0 -7
- package/dist/worker.mjs +37 -6
- package/dist/worker.mjs.map +3 -3
- package/package.json +13 -12
- package/dist/chunk-BJXEVALU.mjs.map +0 -7
- package/dist/src/shared/cli/functions/resolve-raw-db-path.function.d.ts +0 -10
- package/docs/details/README.md +0 -30
- package/docs/details/agent-tooling.md +0 -132
- package/docs/details/cli.md +0 -777
- package/docs/details/knowledge-base.md +0 -180
- package/docs/details/library-api.md +0 -495
- package/docs/details/mcp-server.md +0 -482
- package/docs/details/search-and-ranking.md +0 -575
- package/docs/details/storage.md +0 -531
- package/docs/goals/agents.md +0 -751
- package/docs/goals/architecture.svg +0 -198
- package/docs/goals/auto-capture.md +0 -378
- package/docs/goals/benchmarking.md +0 -296
- package/docs/goals/cli.md +0 -2654
- package/docs/goals/concurrency.md +0 -259
- package/docs/goals/content-composer.md +0 -609
- package/docs/goals/content-parser.md +0 -279
- package/docs/goals/database.md +0 -1679
- package/docs/goals/document.md +0 -368
- package/docs/goals/hybrid-search.md +0 -465
- package/docs/goals/mcp.md +0 -1541
- package/docs/goals/overview.md +0 -124
- package/docs/goals/query-parser.md +0 -373
- package/docs/goals/query-result.md +0 -860
- package/docs/goals/semantic-dedup.md +0 -233
- package/docs/goals/skills.md +0 -810
- package/docs/goals/sync.md +0 -217
- package/docs/goals/worker-client.md +0 -1005
- package/docs/goals/worker-daemon.md +0 -1547
- package/docs/modules/overview.md +0 -319
- package/docs/modules/rust/embedding/module.md +0 -91
- package/docs/modules/rust/fs-database/functions/document.md +0 -48
- package/docs/modules/rust/fs-database/functions/integrity.md +0 -79
- package/docs/modules/rust/fs-database/functions/io.md +0 -87
- package/docs/modules/rust/fs-database/functions/module.md +0 -22
- package/docs/modules/rust/fs-database/functions/query-exec.md +0 -44
- package/docs/modules/rust/fs-database/functions/section.md +0 -76
- package/docs/modules/rust/fs-database/indexes/btree.md +0 -35
- package/docs/modules/rust/fs-database/indexes/corpus.md +0 -61
- package/docs/modules/rust/fs-database/indexes/inverted.md +0 -60
- package/docs/modules/rust/fs-database/indexes/module.md +0 -64
- package/docs/modules/rust/fs-database/indexes/positional.md +0 -39
- package/docs/modules/rust/fs-database/indexes/vectors.md +0 -110
- package/docs/modules/rust/fs-database/module.md +0 -150
- package/docs/modules/rust/fs-database/types/catalog.md +0 -53
- package/docs/modules/rust/fs-database/types/module.md +0 -12
- package/docs/modules/rust/fs-database/types/section.md +0 -127
- package/docs/modules/rust/kb-worker/functions/compose.md +0 -57
- package/docs/modules/rust/kb-worker/functions/module.md +0 -20
- package/docs/modules/rust/kb-worker/functions/retrieve.md +0 -194
- package/docs/modules/rust/kb-worker/functions/search.md +0 -173
- package/docs/modules/rust/kb-worker/functions/write.md +0 -172
- package/docs/modules/rust/kb-worker/module.md +0 -171
- package/docs/modules/rust/kb-worker/types/cache.md +0 -90
- package/docs/modules/rust/kb-worker/types/context.md +0 -26
- package/docs/modules/rust/kb-worker/types/module.md +0 -16
- package/docs/modules/rust/kb-worker/types/status.md +0 -29
- package/docs/modules/rust/kb-worker/types/token.md +0 -50
- package/docs/modules/rust/overview.md +0 -531
- package/docs/modules/rust/query-parser/functions/extract.md +0 -56
- package/docs/modules/rust/query-parser/functions/module.md +0 -18
- package/docs/modules/rust/query-parser/functions/parse.md +0 -33
- package/docs/modules/rust/query-parser/functions/pipeline.md +0 -9
- package/docs/modules/rust/query-parser/functions/rank.md +0 -85
- package/docs/modules/rust/query-parser/module.md +0 -131
- package/docs/modules/rust/query-parser/types/cache.md +0 -39
- package/docs/modules/rust/query-parser/types/keyphrase.md +0 -71
- package/docs/modules/rust/query-parser/types/module.md +0 -18
- package/docs/modules/rust/query-parser/types/token.md +0 -46
- package/docs/modules/rust/shared/content-composer/functions.md +0 -114
- package/docs/modules/rust/shared/content-composer/module.md +0 -147
- package/docs/modules/rust/shared/content-composer/types.md +0 -93
- package/docs/modules/rust/shared/content-parser/functions.md +0 -72
- package/docs/modules/rust/shared/content-parser/module.md +0 -99
- package/docs/modules/rust/shared/content-parser/types.md +0 -71
- package/docs/modules/rust/shared/corpus/module.md +0 -24
- package/docs/modules/rust/shared/corpus/types.md +0 -141
- package/docs/modules/rust/shared/document/module.md +0 -25
- package/docs/modules/rust/shared/document/types.md +0 -154
- package/docs/modules/rust/shared/encode/module.md +0 -22
- package/docs/modules/rust/shared/encode/traits.md +0 -304
- package/docs/modules/rust/shared/error/module.md +0 -28
- package/docs/modules/rust/shared/error/types.md +0 -302
- package/docs/modules/rust/shared/kbid/module.md +0 -24
- package/docs/modules/rust/shared/kbid/types.md +0 -147
- package/docs/modules/rust/shared/memory/functions.md +0 -209
- package/docs/modules/rust/shared/memory/module.md +0 -24
- package/docs/modules/rust/shared/module.md +0 -196
- package/docs/modules/rust/shared/pipeline/functions.md +0 -141
- package/docs/modules/rust/shared/pipeline/module.md +0 -62
- package/docs/modules/rust/shared/pipeline/types.md +0 -43
- package/docs/modules/rust/shared/query/module.md +0 -27
- package/docs/modules/rust/shared/query/types.md +0 -236
- package/docs/modules/rust/shared/section/module.md +0 -25
- package/docs/modules/rust/shared/section/types.md +0 -294
- package/docs/modules/rust/shared/term/module.md +0 -25
- package/docs/modules/rust/shared/term/types.md +0 -139
- package/docs/modules/typescript/cli.md +0 -131
- package/docs/modules/typescript/kbdb-worker.md +0 -150
- package/docs/modules/typescript/overview.md +0 -400
- package/docs/modules/typescript/shared/auto-capture/module.md +0 -73
- package/docs/modules/typescript/shared/cli/constants.md +0 -23
- package/docs/modules/typescript/shared/cli/functions.md +0 -809
- package/docs/modules/typescript/shared/cli/module.md +0 -138
- package/docs/modules/typescript/shared/cli/typings.md +0 -197
- package/docs/modules/typescript/shared/embedding/functions.md +0 -200
- package/docs/modules/typescript/shared/embedding/module.md +0 -77
- package/docs/modules/typescript/shared/embedding/typings.md +0 -124
- package/docs/modules/typescript/shared/hash/functions.md +0 -20
- package/docs/modules/typescript/shared/hash/module.md +0 -21
- package/docs/modules/typescript/shared/log/constants.md +0 -82
- package/docs/modules/typescript/shared/log/functions.md +0 -131
- package/docs/modules/typescript/shared/log/module.md +0 -153
- package/docs/modules/typescript/shared/log/typings.md +0 -82
- package/docs/modules/typescript/shared/mcp/classes.md +0 -179
- package/docs/modules/typescript/shared/mcp/functions.md +0 -386
- package/docs/modules/typescript/shared/mcp/module.md +0 -160
- package/docs/modules/typescript/shared/mcp/typings.md +0 -529
- package/docs/modules/typescript/shared/module.md +0 -110
- package/docs/modules/typescript/shared/platform/functions.md +0 -42
- package/docs/modules/typescript/shared/platform/module.md +0 -25
- package/docs/modules/typescript/shared/runtime/functions.md +0 -26
- package/docs/modules/typescript/shared/runtime/module.md +0 -27
- package/docs/modules/typescript/shared/runtime/typings.md +0 -13
- package/docs/modules/typescript/shared/version/module.md +0 -27
- package/docs/modules/typescript/shared/wasm-codec/functions.md +0 -391
- package/docs/modules/typescript/shared/wasm-codec/module.md +0 -98
- package/docs/modules/typescript/shared/worker-client/classes.md +0 -264
- package/docs/modules/typescript/shared/worker-client/functions.md +0 -175
- package/docs/modules/typescript/shared/worker-client/module.md +0 -92
- package/docs/modules/typescript/shared/worker-client/typings.md +0 -511
- package/docs/modules/typescript/shared/worker-daemon/classes.md +0 -239
- package/docs/modules/typescript/shared/worker-daemon/constants.md +0 -37
- package/docs/modules/typescript/shared/worker-daemon/functions.md +0 -234
- package/docs/modules/typescript/shared/worker-daemon/module.md +0 -118
- package/docs/modules/typescript/shared/worker-daemon/typings.md +0 -132
- package/docs/overview.md +0 -191
- package/docs/release-notes/0.1.0.md +0 -189
- package/docs/release-notes/0.1.1.md +0 -46
- package/docs/release-notes/0.1.2.md +0 -38
- package/docs/release-notes/0.1.3.md +0 -42
- package/docs/release-notes/0.2.0.md +0 -147
- package/docs/release-notes/0.3.0.md +0 -89
- package/docs/release-notes/0.3.1.md +0 -121
- package/docs/release-notes/0.3.2.md +0 -64
- package/docs/release-notes/0.4.0.md +0 -80
- package/docs/release-notes/0.4.1.md +0 -149
- package/docs/release-notes/0.4.3.md +0 -60
- package/docs/release-notes/README.md +0 -13
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
# Concurrent Write Safety
|
|
2
|
-
|
|
3
|
-
*One writer at a time, unlimited concurrent readers --
|
|
4
|
-
formalizing the locking model, multi-daemon prevention,
|
|
5
|
-
crash recovery, and stress-test methodology.*
|
|
6
|
-
|
|
7
|
-
## Goal
|
|
8
|
-
|
|
9
|
-
The worker daemon serializes all write operations
|
|
10
|
-
through a single-writer lock. Multiple concurrent
|
|
11
|
-
readers proceed without any lock. This document
|
|
12
|
-
formalizes the locking model, multi-daemon prevention,
|
|
13
|
-
atomic write guarantees, crash recovery, and
|
|
14
|
-
stress-test methodology.
|
|
15
|
-
|
|
16
|
-
This goal addresses gap #3 from the issue
|
|
17
|
-
[2026-06-23 Opus 4.8 Second Brain Review](../issues/2026-06-23-opus-48-second-brain-review.md):
|
|
18
|
-
the single-writer lock in the worker daemon must be
|
|
19
|
-
validated under concurrent load before concurrent
|
|
20
|
-
multi-agent use can be trusted.
|
|
21
|
-
|
|
22
|
-
## Single-Writer Lock
|
|
23
|
-
|
|
24
|
-
The daemon acquires an exclusive file lock on
|
|
25
|
-
`kbdb-{ctx}.lock` in the OS temporary directory during
|
|
26
|
-
write operations. The lock file uses the same context
|
|
27
|
-
ID as the PID file and IPC socket (see
|
|
28
|
-
[Worker Daemon](worker-daemon.md) for context ID
|
|
29
|
-
derivation).
|
|
30
|
-
|
|
31
|
-
- **Read operations** -- search, recall, retrieve,
|
|
32
|
-
content, dbStatus, and listByType -- proceed without
|
|
33
|
-
acquiring the lock. Concurrent read requests from
|
|
34
|
-
multiple worker client connections are fully parallel.
|
|
35
|
-
- **Write operations** -- addSection, updateSection,
|
|
36
|
-
removeSection, groupSections, removeGrouping,
|
|
37
|
-
initDirectory, gc, rebuildIndexes, and export --
|
|
38
|
-
acquire the exclusive lock before calling the
|
|
39
|
-
corresponding WASM export. If another write is
|
|
40
|
-
already in progress, the new write queues behind the
|
|
41
|
-
lock and waits.
|
|
42
|
-
- The lock is held only for the duration of a single
|
|
43
|
-
write operation. It is released immediately after
|
|
44
|
-
the operation completes. It is never held across
|
|
45
|
-
multiple operations or across client connections.
|
|
46
|
-
- The locking model is implemented in TypeScript inside
|
|
47
|
-
the worker daemon (`src/shared/worker-daemon/`), not
|
|
48
|
-
inside any WASM module.
|
|
49
|
-
|
|
50
|
-
This model is equivalent to SQLite's default locking:
|
|
51
|
-
readers never block, and writers take turns one at a
|
|
52
|
-
time.
|
|
53
|
-
|
|
54
|
-
### Write Operations Subject to the Lock
|
|
55
|
-
|
|
56
|
-
| IPC Method | WASM Export |
|
|
57
|
-
|--------------------------|----------------------------|
|
|
58
|
-
| `addSection` | `worker_add_section` |
|
|
59
|
-
| `updateSection` | `worker_update_section` |
|
|
60
|
-
| `removeSection` | `worker_remove_section` |
|
|
61
|
-
| `groupSections` | `worker_group_sections` |
|
|
62
|
-
| `removeGrouping` | `worker_remove_grouping` |
|
|
63
|
-
| `initDirectory` | `worker_init_directory` |
|
|
64
|
-
| `gc` | `worker_garbage_collect` |
|
|
65
|
-
| `rebuildIndexes` | `worker_rebuild_indexes` |
|
|
66
|
-
| `export` | `db_export` |
|
|
67
|
-
|
|
68
|
-
## Multi-Daemon Prevention
|
|
69
|
-
|
|
70
|
-
Each database context gets exactly one daemon process
|
|
71
|
-
at a time, enforced by a PID file keyed to the context
|
|
72
|
-
ID.
|
|
73
|
-
|
|
74
|
-
- The PID file is named `kbdb-{ctx}.pid` and lives in
|
|
75
|
-
the OS temporary directory. Its presence means a
|
|
76
|
-
daemon for that context is either running or died
|
|
77
|
-
without cleaning up.
|
|
78
|
-
- Before spawning a new daemon, the worker client reads
|
|
79
|
-
the PID file (if present) and checks whether the
|
|
80
|
-
recorded process is alive.
|
|
81
|
-
- **PID file absent** -- no running daemon; spawn a
|
|
82
|
-
new one.
|
|
83
|
-
- **PID file present, process alive** -- connect to
|
|
84
|
-
the existing daemon; do not spawn.
|
|
85
|
-
- **PID file present, process dead** -- stale PID
|
|
86
|
-
file from a prior crash; remove the file and spawn
|
|
87
|
-
a new daemon.
|
|
88
|
-
- The daemon writes its PID file only after all startup
|
|
89
|
-
preconditions pass and the WASM module is loaded
|
|
90
|
-
successfully. See [Worker Daemon](worker-daemon.md)
|
|
91
|
-
for the full startup sequence.
|
|
92
|
-
- On graceful shutdown, the daemon removes its PID
|
|
93
|
-
file before exiting.
|
|
94
|
-
|
|
95
|
-
This protocol ensures that the same database directory
|
|
96
|
-
is never served by two concurrent daemon processes.
|
|
97
|
-
|
|
98
|
-
## Atomic Write Guarantees
|
|
99
|
-
|
|
100
|
-
All file writes in the database use the atomic
|
|
101
|
-
write pattern: content is written to a temporary file
|
|
102
|
-
first, then the temporary file is renamed to the final
|
|
103
|
-
path. Rename is an atomic operation on all supported
|
|
104
|
-
filesystems (POSIX and Windows NTFS).
|
|
105
|
-
|
|
106
|
-
- **Section files** (`sections/{prefix}/{kbid}.sec`)
|
|
107
|
-
are written to `sections/{prefix}/{kbid}.sec.tmp`
|
|
108
|
-
then renamed.
|
|
109
|
-
- **Document manifests** (`documents/{docid}.toml`)
|
|
110
|
-
are written to `documents/{docid}.toml.tmp` then
|
|
111
|
-
renamed.
|
|
112
|
-
- **Index files** (`indexes/terms.idx`, etc.) are
|
|
113
|
-
rebuilt to temporary paths then renamed into place.
|
|
114
|
-
- **Catalog** (`catalog.toml`) is written last,
|
|
115
|
-
after all data files are in place. A crash
|
|
116
|
-
before the catalog rename leaves the catalog
|
|
117
|
-
consistent with the previous complete state.
|
|
118
|
-
|
|
119
|
-
If the daemon crashes mid-write, the temporary file
|
|
120
|
-
is orphaned but the original file is intact. On next
|
|
121
|
-
daemon startup, orphaned temporary files (matching
|
|
122
|
-
`*.tmp`) in the database directory are cleaned up.
|
|
123
|
-
|
|
124
|
-
The atomic write pattern is specified in
|
|
125
|
-
[Database](database.md) under Storage Design.
|
|
126
|
-
|
|
127
|
-
## Crash Recovery
|
|
128
|
-
|
|
129
|
-
The table below describes every identified failure
|
|
130
|
-
scenario, the resulting disk state, and the recovery
|
|
131
|
-
action.
|
|
132
|
-
|
|
133
|
-
| Scenario | State After Crash | Recovery |
|
|
134
|
-
|---|---|---|
|
|
135
|
-
| Crash during section write | `*.sec.tmp` orphaned, original `.sec` intact | Startup cleans `*.tmp` files |
|
|
136
|
-
| Crash during index rebuild | Partial `*.idx.tmp`, originals intact | Startup cleans `*.tmp`; next `rebuildIndexes` overwrites |
|
|
137
|
-
| Crash during GC | Some unreferenced sections deleted, others not | Re-run `gc`; idempotent |
|
|
138
|
-
| Crash during catalog write | `catalog.toml.tmp` orphaned, original intact | Startup cleans `*.tmp` |
|
|
139
|
-
| PID file not removed | Stale `kbdb-{ctx}.pid` on disk | Worker client detects dead process, removes PID, spawns new daemon |
|
|
140
|
-
| Lock file not released | `kbdb-{ctx}.lock` orphaned | Daemon startup acquires the exclusive lock fresh; OS releases orphaned file locks when the process that held them exits |
|
|
141
|
-
| WASM crash inside write | Partial in-memory state, temp file may exist | Daemon exits; startup cleans `*.tmp`; next operation starts clean |
|
|
142
|
-
|
|
143
|
-
All recovery actions are automatic. No manual
|
|
144
|
-
intervention is required for any scenario in this
|
|
145
|
-
table.
|
|
146
|
-
|
|
147
|
-
## Stress Test Specification
|
|
148
|
-
|
|
149
|
-
The following test harness validates concurrent write
|
|
150
|
-
safety. It must pass on both Deno and Node.js runtimes
|
|
151
|
-
before a release can claim concurrent safety.
|
|
152
|
-
|
|
153
|
-
### Setup
|
|
154
|
-
|
|
155
|
-
1. Create a fresh, empty database directory.
|
|
156
|
-
2. Prepare N unique documents (N in the range 10--50).
|
|
157
|
-
Each document must have distinct content to avoid
|
|
158
|
-
content-address collisions that would make section
|
|
159
|
-
count verification meaningless.
|
|
160
|
-
|
|
161
|
-
### Execution
|
|
162
|
-
|
|
163
|
-
3. Launch N concurrent `kbdb learn` invocations, all
|
|
164
|
-
targeting the same database directory. Each
|
|
165
|
-
invocation learns one of the N unique documents.
|
|
166
|
-
4. Use a process pool or parallel shell to launch all
|
|
167
|
-
N invocations simultaneously -- not sequentially.
|
|
168
|
-
5. Wait for all N invocations to complete. Record any
|
|
169
|
-
non-zero exit codes as failures.
|
|
170
|
-
|
|
171
|
-
### Verification
|
|
172
|
-
|
|
173
|
-
6. Run `kbdb check` against the database.
|
|
174
|
-
The response must have `ok: true`. Any errors in the
|
|
175
|
-
response are test failures.
|
|
176
|
-
7. Query the section count. The count must equal the
|
|
177
|
-
expected number of sections derived from the N
|
|
178
|
-
documents (no duplicates from race conditions, no
|
|
179
|
-
losses from interleaved writes).
|
|
180
|
-
8. Verify that no section has a checksum mismatch.
|
|
181
|
-
A mismatch indicates a torn write -- the atomic
|
|
182
|
-
rename pattern failed or was bypassed.
|
|
183
|
-
|
|
184
|
-
### Pass Criteria
|
|
185
|
-
|
|
186
|
-
| Check | Expected Result |
|
|
187
|
-
|---|---|
|
|
188
|
-
| All `kbdb learn` exit codes | `0` |
|
|
189
|
-
| `kbdb check` response | `ok: true`, zero errors |
|
|
190
|
-
| Section count | Exactly the expected count |
|
|
191
|
-
| Checksum mismatches | Zero |
|
|
192
|
-
|
|
193
|
-
### Runtime Matrix
|
|
194
|
-
|
|
195
|
-
Run the full harness on both runtimes:
|
|
196
|
-
|
|
197
|
-
| Runtime | Command prefix |
|
|
198
|
-
|---|---|
|
|
199
|
-
| Node.js >= 20 | `node dist/kbdb.mjs` |
|
|
200
|
-
| Deno | `deno run --allow-all src/cli.ts` |
|
|
201
|
-
|
|
202
|
-
Both must pass. A failure on one runtime but not the
|
|
203
|
-
other indicates a runtime-specific locking bug.
|
|
204
|
-
|
|
205
|
-
## Edge Cases
|
|
206
|
-
|
|
207
|
-
### Two CLI Invocations Through the Same Daemon
|
|
208
|
-
|
|
209
|
-
When two `kbdb` CLI processes connect to the same
|
|
210
|
-
daemon (same database directory), their write requests
|
|
211
|
-
share the single-writer lock automatically. No user
|
|
212
|
-
action is required. The second write waits for the
|
|
213
|
-
first to complete.
|
|
214
|
-
|
|
215
|
-
### MCP Server Connections
|
|
216
|
-
|
|
217
|
-
An MCP server connection routes all requests through
|
|
218
|
-
a worker client to the daemon, the same as a CLI
|
|
219
|
-
invocation. Multiple MCP client connections routed to
|
|
220
|
-
the same daemon share the write lock:
|
|
221
|
-
|
|
222
|
-
- Concurrent read requests from multiple MCP clients
|
|
223
|
-
are served in parallel.
|
|
224
|
-
- Concurrent write requests from multiple MCP clients
|
|
225
|
-
are serialized through the lock one at a time.
|
|
226
|
-
|
|
227
|
-
There is no per-connection or per-client lock; the
|
|
228
|
-
lock is global to the daemon process.
|
|
229
|
-
|
|
230
|
-
### Direct File Access
|
|
231
|
-
|
|
232
|
-
Accessing or modifying `.kbdb` files directly -- via
|
|
233
|
-
text editor, shell commands, or any process other than
|
|
234
|
-
the daemon -- is not supported. Direct writes bypass
|
|
235
|
-
the single-writer lock and the atomic write pattern,
|
|
236
|
-
and may corrupt the database. All mutations must go
|
|
237
|
-
through the daemon's IPC API.
|
|
238
|
-
|
|
239
|
-
## Design Constraints
|
|
240
|
-
|
|
241
|
-
- **Per-daemon locking, not per-file** -- The lock
|
|
242
|
-
covers all writes to a database context, not writes
|
|
243
|
-
to individual files. This means writes to unrelated
|
|
244
|
-
sections still serialize behind the same lock. The
|
|
245
|
-
simplicity of a single lock outweighs the throughput
|
|
246
|
-
cost at current scale. If per-section parallelism
|
|
247
|
-
becomes necessary, this constraint is the place to
|
|
248
|
-
revisit.
|
|
249
|
-
- **Single-machine only** -- The locking model
|
|
250
|
-
relies on OS-level file locks and process identity
|
|
251
|
-
on a single machine. It provides no guarantees across
|
|
252
|
-
network filesystems or multiple machines. Cross-machine
|
|
253
|
-
scenarios require an external sync mechanism (see
|
|
254
|
-
[Sync](sync.md) when available).
|
|
255
|
-
- **Lock implemented in TypeScript** -- The write lock
|
|
256
|
-
is managed by the TypeScript worker daemon layer, not
|
|
257
|
-
by any WASM module. WASM modules have no knowledge of
|
|
258
|
-
concurrent callers; they process one call at a time
|
|
259
|
-
through the host.
|