@functional-systems/srcx 0.1.0-dev.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/CONTRIBUTING.md +54 -0
  3. package/DESIGN.md +1057 -0
  4. package/LICENSE +202 -0
  5. package/README.md +209 -0
  6. package/RELEASING.md +137 -0
  7. package/VALIDATION.md +181 -0
  8. package/dist/build.d.ts +94 -0
  9. package/dist/build.js +433 -0
  10. package/dist/build.js.map +1 -0
  11. package/dist/chunk.d.ts +30 -0
  12. package/dist/chunk.js +296 -0
  13. package/dist/chunk.js.map +1 -0
  14. package/dist/cli.d.ts +2 -0
  15. package/dist/cli.js +276 -0
  16. package/dist/cli.js.map +1 -0
  17. package/dist/common.d.ts +17 -0
  18. package/dist/common.js +74 -0
  19. package/dist/common.js.map +1 -0
  20. package/dist/git.d.ts +38 -0
  21. package/dist/git.js +224 -0
  22. package/dist/git.js.map +1 -0
  23. package/dist/publish.d.ts +60 -0
  24. package/dist/publish.js +341 -0
  25. package/dist/publish.js.map +1 -0
  26. package/dist/releases.d.ts +8 -0
  27. package/dist/releases.js +79 -0
  28. package/dist/releases.js.map +1 -0
  29. package/dist/remote.d.ts +53 -0
  30. package/dist/remote.js +136 -0
  31. package/dist/remote.js.map +1 -0
  32. package/dist/repository.d.ts +29 -0
  33. package/dist/repository.js +180 -0
  34. package/dist/repository.js.map +1 -0
  35. package/dist/search.d.ts +46 -0
  36. package/dist/search.js +181 -0
  37. package/dist/search.js.map +1 -0
  38. package/dist/settings.d.ts +10 -0
  39. package/dist/settings.js +35 -0
  40. package/dist/settings.js.map +1 -0
  41. package/package.json +58 -0
  42. package/src/build.ts +587 -0
  43. package/src/chunk.ts +328 -0
  44. package/src/cli.ts +366 -0
  45. package/src/common.ts +71 -0
  46. package/src/git.ts +286 -0
  47. package/src/publish.ts +487 -0
  48. package/src/releases.ts +108 -0
  49. package/src/remote.ts +230 -0
  50. package/src/repository.ts +306 -0
  51. package/src/search.ts +282 -0
  52. package/src/settings.ts +59 -0
package/DESIGN.md ADDED
@@ -0,0 +1,1057 @@
1
+ # srcx: Initial Implementation Design
2
+
3
+ Status: initial CLI implemented with local tests and live synthetic A/B validation
4
+ on LambdaDB. See [README.md](README.md) for runnable interfaces and
5
+ [VALIDATION.md](VALIDATION.md) for the bounded live evidence and remaining scope.
6
+
7
+ Updated: 2026-09-25.
8
+
9
+ ## 1. Purpose, decisions, and implementation defaults
10
+
11
+ Build an independent code-search application on LambdaDB. A user selects
12
+ an exact repository version, searches its code, and reads the original source
13
+ supporting each result. The project name is `srcx`.
14
+
15
+ ### Project identity
16
+
17
+ | Surface | Name |
18
+ | --- | --- |
19
+ | Project and display name | `srcx` |
20
+ | Local directory | `srcx` |
21
+ | Intended GitHub repository | `lambdadb/srcx` |
22
+ | CLI executable | `srcx` |
23
+ | Intended npm package | `@functional-systems/srcx` |
24
+ | Short description | Version-aware code search on LambdaDB |
25
+
26
+ The name is selected; the GitHub repository and npm package have not been created
27
+ or published in this project. The package manifest and executable entry point are
28
+ present in the initial CLI. Keep display/configuration naming centralized and
29
+ distribution identity in `package.json`. Database IDs and the existing
30
+ `code-*` Collection naming and `purpose=code-search-v1` protocol marker remain
31
+ independent of the product name.
32
+
33
+ Confirmed boundaries from the discussion:
34
+
35
+ - Start with a local CLI and two explicitly selected commits, not full history.
36
+ - Read committed Git tree/blob objects, never a changing working tree.
37
+ - Use one code Collection per repository by default, with fixed index settings.
38
+ - Derive repository names from Git remotes rather than arbitrary user aliases.
39
+ - Map a Git commit to a validated immutable LambdaDB Tag.
40
+ - Map each Git tag to a LambdaDB Alias targeting its published commit Tag.
41
+ Multiple Git tags for the same commit share one commit Tag and Snapshot.
42
+ - Keep search results and subsequent source reads pinned to the selected version.
43
+ - Replace a changed file's entire chunk set initially; cache embeddings by input.
44
+ - Keep core LambdaDB work, GitHub App/webhooks, UI, MCP, and a public SaaS outside
45
+ the first deliverable. sbrain reference documents remain unchanged.
46
+ - No remote repository creation, application commit, push, publication, real
47
+ source upload, or paid embedding call is authorized by writing this design.
48
+
49
+ Current recommendations, distinguished from user-confirmed choices:
50
+
51
+ | Area | Initial recommendation |
52
+ | --- | --- |
53
+ | Runtime | TypeScript and a supported Node.js release compatible with the existing SDK |
54
+ | Database | LambdaDB only; no public backend selection or interchangeable database framework |
55
+ | API key | Read `LAMBDADB_API_KEY` by default; optional environment-variable-name override |
56
+ | Syntax | Java and TypeScript/JavaScript first; other text uses recorded fallback |
57
+ | Source | Exact UTF-8 source inside file documents, with local blob cache |
58
+ | File size | Start with a 1 MiB raw-source limit and explicit exclusions |
59
+ | Embedding | A fixed `none` preset first; with a model, embed meaningful code and prose chunks while recording policy-based skips |
60
+ | Discovery | LambdaDB is authoritative for repositories and published versions |
61
+ | Local state | Connection settings, checkout attachments, reproducible build artifacts, caches, and retry journals |
62
+
63
+ These recommendations supersede earlier proposals for `--backend local` and a
64
+ local-only repository/version registry. Keep offline build verification and test
65
+ doubles internal; they are not a second supported database product. Later database
66
+ comparisons can consume the same exported corpus and queries in a separate harness.
67
+
68
+ The founder confirmed deployment of the latest LambdaDB including versioning.
69
+ This document is not a deployed-revision audit or evidence of a passing live run.
70
+
71
+ ## 2. User journey and example commands
72
+
73
+ The initial command set below is implemented; run it as `node dist/cli.js` from
74
+ this checkout after `npm run build`. See README for exact options and recovery.
75
+ The first implementation uses fresh `work-*` Branches and observed-local-tag Alias
76
+ synchronization; persistent tracked branches and authoritative pruning remain
77
+ follow-up work. Immutable manifest `requestedRef` is normalized to the resolved
78
+ commit OID; the
79
+ original user spelling remains in the local build artifact. The broader contract
80
+ below remains the target design.
81
+
82
+ ```mermaid
83
+ flowchart TD
84
+ A[Configure the LambdaDB connection] --> B[Register a Git repository]
85
+ B --> C[Preview one commit's import]
86
+ C --> D[Import and validate]
87
+ D --> E[Select a published commit or Git release]
88
+ E --> F[Search code]
89
+ F --> G[Read exact source and cite it]
90
+ G --> F
91
+ G --> H[Explicitly select another repository or version]
92
+ H --> E
93
+ D --> I[Later: import a newer commit]
94
+ I --> C
95
+ ```
96
+
97
+ ```sh
98
+ # The API key is already supplied in LAMBDADB_API_KEY by the shell/secret manager.
99
+ srcx configure --endpoint https://api.lambdadb.ai --project engineering-search
100
+ srcx doctor
101
+ srcx repo add --path /path/to/lambdadb
102
+ srcx repo list
103
+ srcx repo show --repo lambdadb
104
+ srcx import --repo lambdadb --ref main --dry-run
105
+ # Pin exactly the commit shown by the preview.
106
+ srcx import --repo lambdadb --ref <full-commit-sha>
107
+ srcx versions --repo lambdadb
108
+ srcx search --repo lambdadb --version <published-version-id> --query consistentRead
109
+ srcx read --result <result-id> --context 20
110
+ srcx read --result <result-id> --full-file
111
+ # Read a known path without first searching.
112
+ srcx read --repo lambdadb --version <published-version-id> \
113
+ --path src/RetryPolicy.java --lines 40:90
114
+ ```
115
+
116
+ `--context` expands a result's source range; `--full-file` reads its whole parent
117
+ file. Direct path reads resolve the file within the specified immutable version.
118
+ Line ranges are one-based and inclusive. All three forms preserve the same version
119
+ and content-hash checks; they never substitute a local working-tree file.
120
+
121
+ The first demonstration prepares A, searches and reads A, prepares B with added,
122
+ changed, and deleted files, searches B, and reopens an old A result. A result never
123
+ silently changes to a newer source version. Initial lexical search is useful for
124
+ identifiers and text; semantic/hybrid relevance needs a separately evaluated model.
125
+
126
+ Users select familiar repository names, commits, and Git releases. Collection,
127
+ Branch, and Tag creation happens behind these actions. A version that has never
128
+ been imported is `not indexed`; preparation is `preparing` or `verifying`; only
129
+ successful publication is `available`. Failed attempts do not replace a usable
130
+ version. Exclusions and parser fallbacks remain visible in the coverage report.
131
+
132
+ If Git main is at B but only A is published, show requested B and available A
133
+ separately. Using A is an explicit choice, such as "latest available indexed
134
+ version". For repository-to-repository investigations, pin each selection
135
+ independently. No automatic cross-repository ranking or session service is needed.
136
+
137
+ ## 3. Connection configuration
138
+
139
+ `configure` saves an existing LambdaDB endpoint/project, the credential reference,
140
+ and the default fixed index preset. It does not create a project or Collection.
141
+ The example endpoint above must match the actual project's origin.
142
+
143
+ `--api-key-env` is optional and defaults to `LAMBDADB_API_KEY`:
144
+
145
+ ```sh
146
+ srcx configure --endpoint https://api.lambdadb.ai --project engineering-search \
147
+ --api-key-env TEAM_SEARCH_API_KEY
148
+ ```
149
+
150
+ Store the environment-variable name, never its secret value. A configuration file
151
+ can be saved before a key is present. Connected commands must fail clearly if the
152
+ selected key is unavailable. There is no implicit fallback to a different key.
153
+
154
+ Use one connection configuration initially. Keep the application's OS/XDG config
155
+ and state directories separate from the general LambdaDB CLI, while reusing its
156
+ endpoint validation, optional key-variable override, and atomic-write conventions.
157
+ Do not load secrets from checked-in repository files. Keep paths, display name,
158
+ and executable naming centralized; branding changes must not change data IDs.
159
+
160
+ `doctor` reads the project's Collection list to check authentication and read
161
+ access. This does not establish write permission or query readiness. Check those
162
+ through the actual provisioning/import operations. A nonexistent project is an
163
+ error; project creation stays in the LambdaDB Console for the first CLI.
164
+
165
+ Changing the configured project changes the remote discovery scope. Checkout
166
+ attachments, result handles, and retry journals include endpoint/project/Collection
167
+ identity and must never be silently reused against a different destination.
168
+ Credential rotation does not change repository or index identity.
169
+
170
+ ## 4. Repository identity, provisioning, and remote discovery
171
+
172
+ ### Repository names
173
+
174
+ `repo add --path ...` reads `origin` by default; `--remote upstream` selects another
175
+ remote. Normalize supported SSH and HTTPS URLs to a canonical key such as
176
+ `github.com/lambdadb/lambdadb`. Strip credentials and transport suffixes. Respect
177
+ host-specific path case; do not merge unrelated Git hosts or SSH aliases by guess.
178
+ If origin is absent but other remotes exist, require explicit remote selection.
179
+
180
+ A short name such as `lambdadb` is accepted only if unique in the connected project.
181
+ Otherwise use `owner/repo` or `host/owner/repo`. Forks remain separate repositories.
182
+ No arbitrary user alias is required. If no remote exists, use the directory's
183
+ basename for display and a persistent generated source identity, clearly labeled
184
+ as a local source. This case supports synthetic fixtures as well as local repos.
185
+
186
+ Repository and index IDs are persisted opaque identities. Explicit reconciliation
187
+ of a renamed/moved remote can retain them; source similarity alone cannot merge
188
+ registrations. Local checkout paths are attachments, not repository identity.
189
+
190
+ ### Collection naming and ownership
191
+
192
+ One fixed-config index uses one Collection. The proposed name is:
193
+
194
+ ```text
195
+ code-{repo-slug}-{digest}
196
+ repo-slug = lowercase ASCII letters/digits/hyphens, max 24 characters
197
+ (collapse separators; use "repo" if empty)
198
+ digest = first 16 hex characters of SHA-256 of the versioned canonical tuple
199
+ (initial canonical repository key, configHash)
200
+ ```
201
+
202
+ Example: `code-lambdadb-7a9c13e024b85d6f`, with an illustrative digest. Maximum
203
+ length is 46 characters. Persist the generated name; do not rename resources when
204
+ the repository or application branding changes. Verify full identity on collisions.
205
+ A new configuration requires an explicitly separate index, not silent migration.
206
+
207
+ Use Collection description and metadata labels to make the resource understandable
208
+ in both the Console and CLI. The inspected contract allows a description of up to
209
+ 255 characters and at most five metadata labels. These labels are distinct from
210
+ immutable version Tags and are not version provenance or a readiness signal.
211
+
212
+ | Surface | Contents | Ownership |
213
+ | --- | --- | --- |
214
+ | `description` | Human explanation of the repository and this index's purpose/scope | Generated default, optionally supplied by the user |
215
+ | `purpose` label | `code-search-v1` | Application discovery marker |
216
+ | `repository` label | `github.com/lambdadb/lambdadb`, when it fits | Human-readable source identity hint |
217
+ | `index-id` label | Stable opaque index ID | Application binding |
218
+ | `config-hash` label | Full fixed-configuration hash | Configuration compatibility |
219
+ | One optional label | For example `team=search` | User operational context |
220
+
221
+ Example metadata (ID/hash values are illustrative):
222
+
223
+ ```json
224
+ {
225
+ "description": "LambdaDB server code index for API contract and implementation investigations. Includes source, tests, docs, and build configuration.",
226
+ "tags": {
227
+ "purpose": "code-search-v1",
228
+ "repository": "github.com/lambdadb/lambdadb",
229
+ "index-id": "example-index-id",
230
+ "config-hash": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
231
+ "team": "search"
232
+ }
233
+ }
234
+ ```
235
+
236
+ Four label slots are reserved; leave the fifth unused unless context is supplied.
237
+ Store repo ID, full repository key, and complete settings in `__repo__` rather than
238
+ duplicating all machine identities in the limited label slots. The name prefix and
239
+ repository label are display hints; always validate full identity via the descriptor.
240
+
241
+ The inspected SDK limits label values to 127 characters and disallows colon, hash,
242
+ and comma characters. Use `host/owner/repo`, not an `https://` URL. If a full key
243
+ does not fit, use a visibly encoded `repo-<full-sha256>` hint in the label and retain
244
+ the unabridged key in `__repo__`; never truncate it into a false repository identity.
245
+
246
+ Allow optional `repo add --description ...` and `--tag team=search` at creation,
247
+ with reserved-key and size checks. Without supplied context, derive a short factual
248
+ description from the Git identity and selected scope. Do not invent the repository's
249
+ business purpose from its name or fetch external descriptions implicitly.
250
+ Repeated registration/import preserves existing descriptions and user labels;
251
+ changing context later is an explicit metadata edit. Descriptions and user labels
252
+ are mutable Collection context, excluded from the immutable index config hash.
253
+ Per-commit facts and exclusions remain in each published Tag's manifest.
254
+
255
+ ### Branch layout within each repository Collection
256
+
257
+ ```text
258
+ Collection code-<repo>-<digest>
259
+ Branch main application control documents only
260
+ Branch checkpoint-empty preserved empty source for clean code workspaces
261
+ Branch git-<ref-digest> mutable corpus for one tracked Git branch
262
+ Branch work-<id> explicit-commit imports or recovery workspace
263
+ Tag try-<candidate-id> unverified immutable candidate
264
+ Tag ver-<commit-digest> published immutable commit version
265
+ Alias rel-<git-tag-digest> Git release name -> published commit Tag
266
+ ```
267
+
268
+ This is an application convention, not a LambdaDB feature. LambdaDB `main` is
269
+ reserved here for control data; Git main maps to an encoded `git-*` Branch. Create
270
+ `checkpoint-empty` before writing any control documents to main. Code workspaces
271
+ start from that empty Branch or a validated suitable code Branch, never from
272
+ control-data main. No Branch is created from a Tag.
273
+
274
+ Control records use `kind=manifest` with distinct roles. On main, fixed ID
275
+ `__repo__` stores full canonical repository identity, original/display names,
276
+ repo/index IDs, exact immutable index configuration, schema version, and an
277
+ initialization marker. Ref records store original Git names, encoded Branch/Alias
278
+ names, observed commit and observation time, and applied target. They contain no
279
+ machine-specific checkout paths or secrets. Required publication validation
280
+ summaries are retained here, separately from immutable corpus manifests.
281
+
282
+ ### `repo add` sequence and retries
283
+
284
+ 1. Resolve the local Git identity and selected index configuration.
285
+ 2. List/describe matching application Collections in the configured project.
286
+ If an initialized compatible repository exists, reuse its IDs and attach the
287
+ local checkout; a fresh machine must not create a duplicate repository.
288
+ 3. Otherwise persist a provisioning journal, then create the Collection with the
289
+ fixed schema, readable description, and reserved/optional labels. LambdaDB
290
+ supplies default main.
291
+ 4. Create `checkpoint-empty` from still-empty main and confirm its empty head.
292
+ 5. Upsert `__repo__` onto main using ordinary document upsert. Fetch it back with
293
+ an explicit Branch ref and `consistentRead=true`; compare the exact descriptor.
294
+ 6. Mark the local provisioning attempt complete and report `registered`, with
295
+ zero published versions until the first import. No source contents are uploaded
296
+ and no embedding provider is called by this command.
297
+
298
+ A missing descriptor after Collection creation is `initializing`, not a nonexistent
299
+ repository. Reconcile labels, schema, journal, and Branch state on retry; never
300
+ blindly repeat an uncertain create or delete the Collection as rollback. Fail on
301
+ mismatched identity/configuration or an unrelated same-name Collection. Existing
302
+ remote registration can be recovered without local state, but an incomplete or
303
+ inconsistent registration must be explicitly diagnosed and repaired.
304
+
305
+ Control Branch readback confirms that control data is observable, not that corpus
306
+ Snapshots are ready. Handle the actual API's transient/overlay limits with bounded
307
+ retries; do not use a control record as an import readiness signal.
308
+
309
+ ### `repo list` and `repo show`
310
+
311
+ These commands use the connected project, not a local repository registry:
312
+
313
+ - Enumerate all Collection pages and select application ownership labels client-side.
314
+ The inspected list API has pagination but no assumed server-side metadata filter.
315
+ - Fetch `__repo__` from each matching Collection's main Branch to recover full names
316
+ and configuration. Do not parse a hashed Collection name into a Git identity.
317
+ - Show Collection name, full repository identity, description, index preset, and
318
+ initialization status. `repo show` also describes labels, actual schema, and
319
+ available refs. Preserve user context when reconciling registrations.
320
+ - Local checkout attachment is optional enrichment. Reading/searching remote data
321
+ works without a checkout; another import needs an attached clone or `--path`.
322
+ - If LambdaDB is unavailable, report that; do not silently present a stale local
323
+ cache as current remote state. A cached view, if added later, must be explicit.
324
+
325
+ Do not use Collection `numDocs` as the source corpus count: it describes main,
326
+ which holds control records under this layout. Use the selected code manifest.
327
+ Multiple experimental indexes for a repository are displayed separately; ambiguity
328
+ must require an explicit index selection before operations, never an arbitrary pick.
329
+
330
+ ## 5. What `import --ref` accepts
331
+
332
+ Accept branch names, explicit branch refs, Git tag names/refs, and commit OIDs:
333
+
334
+ ```sh
335
+ srcx import --repo lambdadb --ref main
336
+ srcx import --repo lambdadb --ref refs/heads/main
337
+ srcx import --repo lambdadb --ref refs/tags/v1.0.0
338
+ srcx import --repo lambdadb --ref <full-commit-sha>
339
+ ```
340
+
341
+ A short Git tag such as `v1.0.0` is accepted if unambiguous. If a branch and tag
342
+ share a name, require a qualified ref. An abbreviated commit is acceptable only
343
+ if unambiguous locally; persist the full resolved OID. Peel annotated tags to
344
+ commits, reject non-commit objects, and do not assume all object IDs have 40 digits.
345
+ General revision-expression support is not required initially.
346
+
347
+ Resolve once at the start and use only that commit thereafter. Use the attached
348
+ clone's declared ref view; a local main is not automatically remote origin/main.
349
+ No implicit fetch, checkout, LFS smudge, build-script execution, or working-tree
350
+ read is part of import. Report the selected ref and full commit before processing.
351
+
352
+ Dry-run and import are separate resolutions. To import exactly the previewed
353
+ source, pass its full SHA. A branch-name import tracks that explicit branch;
354
+ a commit/tag import uses a manual workspace without guessing a containing branch.
355
+
356
+ ## 6. File-by-file build and bounded upload
357
+
358
+ Git reading/chunking belongs to this application. Use the official SDK for database
359
+ calls. Start with a single process, bounded parsing concurrency, and serialized
360
+ writes per repository Collection. Multi-host concurrent import is not supported;
361
+ readers on multiple machines do not require local registration state.
362
+
363
+ ### Phase A: plan and materialize before any corpus mutation
364
+
365
+ 1. Resolve remote repository descriptor and exact config; attach/verify the clone.
366
+ Refuse configuration mismatch before writes. Reuse an existing published commit
367
+ only after checking its manifest identity.
368
+ 2. Resolve the target commit. Select the known validated previous corpus for the
369
+ intended writer Branch, or an empty baseline. Enumerate with NUL-delimited
370
+ `git ls-tree -r -z`; use `git cat-file --batch-check` and `--batch` for size/blob
371
+ reads. Disable replacement-object interpretation; missing objects are errors.
372
+ 3. Compare target path/blob/mode entries to the previous inventory. Classify each
373
+ path as unchanged, added, modified, deleted, or explicitly excluded. Initially
374
+ treat a rename as delete plus add; the two commits need not be adjacent.
375
+ 4. For each added/modified included file: read exact bytes, verify UTF-8 round-trip,
376
+ compute content hash, parse, derive complete source spans, form bounded chunks,
377
+ create one file record and its chunk records, and prepare embedding inputs.
378
+ 5. For unchanged files, retain file/chunk records and metadata verbatim. For each
379
+ changed/deleted file, compute obsolete IDs as previous file/chunk IDs minus
380
+ replacement IDs. A deleted file has an empty replacement set. Obtain previous
381
+ IDs from the inventory, not mutable query-by-path results.
382
+ 6. Apply the pinned per-chunk embedding policy. If embeddings are enabled, batch
383
+ eligible cache misses across chunks/files within the provider's token/request
384
+ limits. Validate successful vectors before caching.
385
+ Bound queue memory; do not load an entire repository's content into RAM.
386
+ 7. Materialize deterministic records and deletion lists as local build artifacts.
387
+ Produce size-bounded inventory parts and a root manifest template. Check all
388
+ serialized sizes and record-set hashes before starting uploads. The execution
389
+ journal supplies the separate attempt ID when sealing the final manifest.
390
+
391
+ Dry-run executes the same inventory/chunking path but performs no database mutation
392
+ or embedding call. For pending embedding misses, report tokens and projected vector
393
+ size separately; do not claim a completed vector/records hash. Report every entry,
394
+ exclusion reason, parse status, byte size, chunk/token counts, embedding eligibility
395
+ and skip reasons, and change summary. Dry-run plans may show pending embedding work;
396
+ published chunk records may not silently treat missing required vectors as skips.
397
+ Fixture-only dry-run can use `--path` and the built-in pinned preset without any
398
+ connection or remote repository lookup. No `--backend` option is needed for that.
399
+
400
+ ### Phase B: apply the build to one code Branch
401
+
402
+ 1. Establish the correct Branch baseline, acquire exclusive writer ownership, and
403
+ persist a mutation journal with this attempt's ID.
404
+ 2. Delete obsolete IDs in bounded batches, then upsert replacement file/chunk
405
+ records in batches bounded by serialized bytes and document count. Await each
406
+ request before issuing the next. Batches can span files; no per-file transaction
407
+ is assumed. Unchanged records need no write; changed positions are updated.
408
+ 3. Replace obsolete inventory parts. Record accepted/rejected/unknown outcomes for
409
+ every mutation, with transparent retries disabled. Resolve all failures and
410
+ unknown outcomes before proceeding; ACK is not yet indexing completion.
411
+ 4. After all preceding mutations have successful ACKs, upsert `__manifest__` alone
412
+ in a separate final request, with the intended build identity and this attempt's
413
+ ID. Do not rely on its position inside a multi-document request.
414
+ 5. Freeze further writes to this code Branch, wait for the marker, then create and
415
+ validate a candidate as described in section 9. Do not start another commit
416
+ until publication completes. A partial Branch is never served to users.
417
+
418
+ Use ordinary SDK upsert/delete for this workaround. Bulk ingestion remains later
419
+ work; do not assume its asynchronous processing obeys the same marker ordering.
420
+
421
+ ### Replacing one file
422
+
423
+ Replace a modified file's chunk set as a unit in the build plan, using the previous
424
+ inventory's explicit IDs for deletion. This makes retry targets fixed and removes
425
+ obsolete chunks when the new file produces fewer chunks. Retain any IDs shared by
426
+ the old and new sets. The default is ID deletion, not delete-by-filter.
427
+
428
+ If a filter-based replacement is introduced later, restrict chunk deletion to
429
+ `kind=chunk` and the previous `fileId`, and delete the old file record by ID.
430
+ Avoid path-only deletion: replaying it after upsert can delete the new file's
431
+ records too. Neither deletion method makes delete-plus-upsert atomic. Readers stay
432
+ on the previous published Tag until the replacement version passes validation.
433
+
434
+ Source collection and batching are distinct. A 20-chunk file contributes one file
435
+ record and 20 chunk records; these can share upload requests with other files.
436
+ Original text appears once in its file record, with exact source ranges in chunks.
437
+ Search context can repeat in chunk search text without changing the quoted source.
438
+
439
+ ## 7. Code-search schema v1
440
+
441
+ The Collection uses one sparse document schema with `kind` distinguishing file,
442
+ chunk, and manifest records. Only chunks participate in normal search. Manifest
443
+ roles distinguish corpus metadata/inventory from main-Branch control documents.
444
+
445
+ The lexical preset's concrete `indexConfigs` is:
446
+
447
+ ```json
448
+ {
449
+ "kind": { "type": "keyword" },
450
+ "path": { "type": "keyword" },
451
+ "language": { "type": "keyword" },
452
+ "fileId": { "type": "keyword" },
453
+ "symbol": { "type": "keyword" },
454
+ "searchText": { "type": "text", "analyzers": ["standard"] }
455
+ }
456
+ ```
457
+
458
+ LambdaDB returns an additional built-in `id: keyword` index in Collection metadata;
459
+ compatibility checks allow that field without accepting other schema changes.
460
+ Only fields used by initial search/filter operations are explicitly configured. Byte/line
461
+ positions, hashes, commit identity, and control roles are stored for source reads
462
+ and validation, not indexed merely because they appear in the payload. Resolve
463
+ control documents by ID and inventory parts through the root manifest. Collection
464
+ `description` and metadata `tags` describe the resource; they are not document
465
+ fields or versioning Tags.
466
+
467
+ ### Document payload contract
468
+
469
+ Every record stores `id`, `kind`, `schemaVersion`, and `configHash`. The following
470
+ fields are additional payload, not additional `indexConfigs` entries. Optional
471
+ fields are omitted when absent; records of different kinds need not share them.
472
+
473
+ | Record | Additional stored fields |
474
+ | --- | --- |
475
+ | File (`kind=file`) | `path`, `blobOid`, `contentHash`, `byteLength`, `sourceText`, `language`, `parseStatus`, `chunkCount` |
476
+ | Chunk (`kind=chunk`) | `fileId`, `path`, parent `contentHash`, `language`, `chunkKind`, `startByte`, `endByte`, `startLine`, `endLine`, `ordinal`, `searchText`, `embeddingStatus`; optional `symbol`, `scope`, `signature`, `embeddingSkipReason`, `embeddingInputHash`, `embedding` |
477
+ | Corpus root (`kind=manifest`, `role=corpus`, ID `__manifest__`) | `repoId`, `indexId`, full `commitOid`, `commitTime`, `requestedRef`, full `config`, `inventoryHash`, `recordsHash`, `counts`, `buildId`, `attemptId`, `inventoryPartIds` |
478
+ | Inventory part (`kind=manifest`, `role=inventory`) | `partOrdinal`, `partHash`, ordered `entries` with path, file/chunk IDs, blob/content identities, inclusion/exclusion reasons, parse states, sizes, and embedding coverage |
479
+ | Repository control (`kind=manifest`, `role=repository`, main ID `__repo__`) | Full source identity, repo/index IDs, immutable preset/config, initialization state |
480
+ | Ref control (`kind=manifest`, `role=git-ref`, main) | Full Git ref name, encoded Alias/Branch name, observed commit/time, applied version and synchronization state |
481
+ | Validation summary (`kind=manifest`, `role=validation`, main) | Candidate name/Snapshot, build/config/attempt identity, verifier version and checked counts/hashes; no premature claim of publication |
482
+
483
+ `startByte`/`endByte` are half-open; display lines are one-based/inclusive.
484
+ `contentHash` on a chunk refers to its parent file's bytes. `chunkKind` describes
485
+ content such as function, declaration, documentation, imports, or fallback; it is
486
+ separate from the file/chunk/manifest discriminator. `counts` includes included and
487
+ excluded files, chunks, and embedded/skipped chunks with reason totals.
488
+
489
+ In a completed corpus, `embeddingStatus=embedded` requires a valid vector and
490
+ `embeddingInputHash`, and omits the skip reason. `embeddingStatus=skipped` requires
491
+ an explicit policy reason and omits the vector and input hash. The lexical-only
492
+ preset records `embedding-disabled`; an embedding-enabled preset records its
493
+ specific exclusion reason. Pending or failed required embedding work stays in the
494
+ local journal and blocks publication, rather than becoming an undocumented skip.
495
+
496
+ Illustrative upsert payload for a file containing one import line. ID/hash strings
497
+ are placeholders; the UTF-8 byte length and source span are concrete:
498
+
499
+ ```json
500
+ {
501
+ "docs": [
502
+ {
503
+ "id": "file-example",
504
+ "kind": "file",
505
+ "schemaVersion": 1,
506
+ "configHash": "example-config-hash",
507
+ "path": "src/Example.java",
508
+ "blobOid": "example-git-blob-oid",
509
+ "contentHash": "example-source-hash",
510
+ "byteLength": 21,
511
+ "sourceText": "import java.io.File;\n",
512
+ "language": "java",
513
+ "parseStatus": "parsed",
514
+ "chunkCount": 1
515
+ },
516
+ {
517
+ "id": "chunk-example",
518
+ "kind": "chunk",
519
+ "schemaVersion": 1,
520
+ "configHash": "example-config-hash",
521
+ "fileId": "file-example",
522
+ "path": "src/Example.java",
523
+ "contentHash": "example-source-hash",
524
+ "language": "java",
525
+ "chunkKind": "imports",
526
+ "startByte": 0,
527
+ "endByte": 21,
528
+ "startLine": 1,
529
+ "endLine": 1,
530
+ "ordinal": 0,
531
+ "searchText": "src/Example.java\nimport java.io.File;\n",
532
+ "embeddingStatus": "skipped",
533
+ "embeddingSkipReason": "imports-only"
534
+ }
535
+ ]
536
+ }
537
+ ```
538
+
539
+ This example uses an embedding-enabled preset that skips imports-only chunks. The
540
+ actual request must also target the intended writable Branch. The complete source
541
+ is stored in the file; enriched chunk search text is never the citation authority.
542
+
543
+ `sourceText`, role, byte/line positions, hashes, commit identity, scope/signature,
544
+ embedding diagnostics, and inventory/config objects are stored without entries in
545
+ `indexConfigs`. Public documentation states that fields are stored even when not
546
+ indexed. Do not invent an `index: false` option. The `standard` analyzer is a
547
+ baseline, not a proven code-specific ranking solution. An initial enrichment
548
+ candidate preserves original identifiers while adding camelCase/snake_case terms;
549
+ pin and evaluate that transformation before adopting it as the preset.
550
+
551
+ An embedding-enabled preset adds an unmanaged `embedding` vector field with a
552
+ concrete model-selected dimension and similarity metric, fixed before Collection
553
+ creation. An indexed vector field does not require a vector on every chunk; file
554
+ and manifest records also omit it. The `none` preset omits the vector index entirely.
555
+ Changing presets creates a separate index; do not silently mutate an existing
556
+ serving index. Do not write placeholder or test vectors into a real corpus.
557
+
558
+ All code-search queries require `kind=chunk` and an explicit published Tag. File reads
559
+ fetch a parent file by ID through that same Tag and check its content hash. A
560
+ result includes endpoint/project/Collection, repo/index, full commit, published
561
+ Tag/Snapshot, file ID, path, and source range. Handles carry or persist enough
562
+ version-bound data to reproduce a read; no current-branch substitution is allowed.
563
+
564
+ ### Deterministic identities and limits
565
+
566
+ - `contentHash`: SHA-256 of original bytes, separate from Git object hashing.
567
+ - File ID: hash of a versioned `(path, contentHash)` tuple.
568
+ - Chunk ID: hash of `(fileId, configHash, startByte, endByte, ordinal)`.
569
+ - Config hash: canonical schema/policy/parser/grammar/chunker/tokenizer/enrichment
570
+ and embedding configuration, including per-chunk eligibility rules, with pinned
571
+ versions.
572
+ - Build ID: hash of `(repoId, commitOid, configHash, builderIdentity)`.
573
+ - Attempt ID: unique execution identity, persisted in the journal and final root
574
+ manifest. A new import attempt gets a new ID even for the same build; resuming
575
+ that journal preserves its ID. It is not an embedding-cache or content identity.
576
+ - Inventory hash: canonical complete ordered inventory. Store large inventories
577
+ in bounded parts; include their source and chunk membership identities.
578
+ - Records hash: canonical expected file/chunk records, excluding manifests to
579
+ avoid circular hashing. Validate vectors against the serialized input contract.
580
+
581
+ No brand, new commit SHA, build ID, or attempt ID is stamped onto unchanged
582
+ file/chunk records. The selected manifest supplies the citable commit; content
583
+ identity and spans supply the source.
584
+ Keep timestamps and attempt IDs outside deterministic content identities.
585
+
586
+ The inspected public limits are 5 MB per document, 6 MB per upsert request, ID
587
+ length 512, and vector dimension at most 4,096. Inspected server source counts
588
+ serialized JSON bytes, with a 5 MiB document limit. Validate final UTF-8 JSON size,
589
+ including escaping and vectors; batch with headroom. This source checkout is a
590
+ feature branch, not proof of the exact deployed artifact. Full live verification
591
+ must include stored-only source round-trip and mixed record kinds.
592
+
593
+ ## 8. File policy, chunking, and embedding reuse
594
+
595
+ Every Git tree entry must be accounted for. Include source, tests, documents,
596
+ configuration, build definitions, and unknown readable text by default. Maintain
597
+ explicit versioned rules for binaries, generated output, and vendored dependencies;
598
+ do not treat working-tree ignore rules as a complete policy. Lockfiles are included
599
+ unless an explicit generated/size rule excludes them.
600
+
601
+ | Special entry | Initial handling |
602
+ | --- | --- |
603
+ | Submodule | Record gitlink OID/path; no recursive import |
604
+ | LFS pointer | Record metadata; no payload download or pointer indexing |
605
+ | Symlink | Record target bytes; never follow or index as source |
606
+ | Oversized file | Exclude with actual bytes and configured limit |
607
+ | Invalid UTF-8 content/path | Record a diagnostic and lossless path identity; do not decode lossily |
608
+ | Empty text file | File record, zero chunks |
609
+ | Unsupported language or parse failure | Include bounded fallback chunks and distinguish the reason |
610
+
611
+ Preserve raw UTF-8 bytes, BOM, CRLF, case, Unicode, and final newlines. Byte ranges
612
+ are authoritative `[startByte, endByte)`; display lines are one-based/inclusive.
613
+ JavaScript UTF-16 offsets must be converted explicitly. Preserve unusual Git paths
614
+ via NUL-delimited parsing and safe subprocess arguments; never shell-interpolate refs.
615
+
616
+ ### Approach and supporting evidence
617
+
618
+ Use a syntax-aware split/merge implementation as the initial code chunker, with
619
+ Tree-sitter as the parser candidate. Tree-sitter supplies syntax nodes and source
620
+ positions; chunk sizing, comment attachment, gap coverage, and merging remain
621
+ application policies. Inspect the chosen binding and grammar versions before
622
+ adoption, especially byte offsets versus JavaScript string offsets.
623
+
624
+ Existing approaches provide a starting point rather than a universal standard:
625
+
626
+ - [LlamaIndex CodeSplitter](https://developers.llamaindex.ai/python/framework-api-reference/node_parsers/code/)
627
+ provides an existing AST-based splitting implementation to inspect. Treat it as
628
+ a reference, not a requirement to add the Python framework to this TypeScript
629
+ application. Check the selected source revision, actual parameter behavior,
630
+ source-span preservation, and license before reusing implementation details.
631
+ - [cAST](https://arxiv.org/abs/2506.15655v2) describes recursively splitting large
632
+ syntax nodes and merging sibling nodes within a size budget. This supports the
633
+ design direction, but srcx does not claim to reproduce that algorithm or its
634
+ reported benchmark results.
635
+ - A [controlled code-completion study](https://arxiv.org/abs/2605.04763v1) reports
636
+ competitive sliding-window and cAST results and weaker function-only results in
637
+ its evaluated settings. Code completion is not the same task as srcx's source
638
+ investigation; do not assume syntax-aware chunks always retrieve better.
639
+
640
+ Start implementation after a bounded review of these approaches. Selecting a
641
+ binding and verifying correctness are immediate work; inventing a new algorithm
642
+ or reproducing all published benchmarks is not a prerequisite. The default below
643
+ preserves useful syntax boundaries while allowing both splitting and merging; it
644
+ is not an unconditional one-function-per-chunk rule.
645
+
646
+ ### Initial boundary and size rules
647
+
648
+ Prefer functions/methods and split large nodes along internal statement boundaries.
649
+ Cover class headers, imports, types, fields, constants, top-level code, comments,
650
+ punctuation, and gaps. Merge small adjacent units only within one scope and budget.
651
+ If a node or long line is still too large, text-split it and record the fallback.
652
+ Initially an unusable/error parse falls back for the whole file. Markdown uses
653
+ headings/paragraphs/fences; structured config uses position-preserving keys/sections
654
+ where supported, otherwise recorded text fallback.
655
+
656
+ Start at a 500–1,000 token target, 1,500 ceiling, no syntax overlap, and about 10%
657
+ fallback overlap. These are experiments, not optimal values. Keep small units small.
658
+ Pin the tokenizer and count the entire enriched embedding input against its budget
659
+ and the model limit. Cap path/scope/signature enrichment before splitting source.
660
+
661
+ Coverage checks use the union of source spans over all included bytes, allowing
662
+ only declared overlap. Attach whitespace gaps to neighboring spans; whitespace-only
663
+ files still receive bounded spans. Do not concatenate overlapping chunks to rebuild
664
+ source. Retrieval enrichment never expands the quoted raw source range.
665
+
666
+ ### Small chunking comparison
667
+
668
+ Keep one simple line-boundary, token-budget window splitter as an internal
669
+ comparison baseline. It may reuse the bounded text fallback implementation.
670
+ Record its size and overlap explicitly; retain the same source-span contract.
671
+ This comparison does not add a public chunker-selection interface or another
672
+ storage backend.
673
+
674
+ First verify correctness for both paths: complete included-byte coverage, exact
675
+ UTF-8/line spans, bounded enriched inputs, deterministic output, and visible parse
676
+ fallbacks. Include large functions, small declarations, attached comments,
677
+ Unicode/CRLF, and long lines. These checks can run on local fixtures before any
678
+ credentials, source upload, or embedding calls are needed.
679
+
680
+ Once retrieval is available, compare the syntax-aware default and the simple
681
+ baseline using 10-20 real investigation queries. Include exact identifiers,
682
+ behavior described in natural language, configuration/documentation lookups, and
683
+ version-specific changes. Pin repository commits and label expected files,
684
+ symbols, and source spans before examining either method's results; do not define
685
+ relevance by one chunker's boundaries. Treat this as a diagnostic pilot, not a
686
+ statistically general benchmark.
687
+
688
+ Hold corpus inclusion, tokenizer, enrichment rules, retrieval settings, and (when
689
+ used) embedding model and eligibility policy constant. Give each chunker its own
690
+ config identity and separate evaluation index/artifacts. Vary chunking first;
691
+ evaluate embedding coverage policies in a separate comparison. Document any
692
+ content-classification differences that make eligibility incomparable.
693
+
694
+ Record per-query results and summarize:
695
+
696
+ - Expected evidence found in the top 5 results, plus evidence coverage under a
697
+ fixed returned-token budget shared by both methods. Match original source spans
698
+ and deduplicate overlapping hits so small or overlapping chunks do not inflate
699
+ the score. Choose and record the token budget before running the comparison.
700
+ - Tokens actually returned, duplicate/overlapping context, and whether a result
701
+ cuts off source needed to understand the behavior. Count any context expansion
702
+ under the same policy and budget for both methods.
703
+ - Corpus chunk count and enriched token volume; actual embedding input tokens
704
+ and measured provider cost only if an authorized embedding run occurred.
705
+
706
+ Keep the syntax-aware default provisional until this pilot is run. Investigate
707
+ misses before changing size, overlap, comment attachment, or path/scope enrichment;
708
+ record the reason for each adjustment rather than running a broad parameter sweep.
709
+ Validate adjustments on fresh queries before making wider quality claims. The
710
+ pilot tunes retrieval quality after the minimal pipeline works; it does not block
711
+ bootstrap or replace the two-commit correctness completion criterion.
712
+
713
+ ### Per-chunk embedding policy
714
+
715
+ With an embedding-enabled preset, meaningful pure code remains eligible even when
716
+ it has no comments: users may describe behavior without knowing its identifiers.
717
+ The initial recommendation is to include useful code and prose and skip clearly
718
+ structural fragments, rather than build a complex value classifier.
719
+
720
+ | Chunk content | Initial recommendation |
721
+ | --- | --- |
722
+ | Functions, methods, meaningful top-level logic | Embed, including uncommented code |
723
+ | Tests | Embed usage examples and expected behavior |
724
+ | Documentation, explanatory comments/docstrings | Embed; keep attached explanations with their code where practical |
725
+ | Meaningful type/configuration declarations | Embed initially, then evaluate |
726
+ | Imports-only or whitespace/punctuation-only fragments | Skip with a recorded reason |
727
+ | Repeated license headers and mechanical listings | Candidates for explicit, versioned skip rules after evaluation |
728
+ | Parser fallback | Do not exclude solely because parsing failed; apply content policy |
729
+
730
+ Skipped chunks remain in inventory and source coverage. Retain lexical search text
731
+ where meaningful; a chunk without a vector cannot contribute a vector candidate.
732
+ Search must retain lexical candidates when combining lexical and vector results.
733
+ Keep the query/document embedding spaces compatible across code and prose; do not
734
+ mix separate models' vectors merely because their dimensions happen to match.
735
+
736
+ Record eligibility policy in configHash and count embedded/skipped chunks in the
737
+ manifest. Compare lexical-only, prose-only embedding, and code-plus-prose embedding
738
+ on the same corpus and queries before claiming a quality or cost benefit. Model
739
+ choice and the finer skip rules remain evaluation decisions, not measured results.
740
+
741
+ ### Embedding reuse
742
+
743
+ Cache embeddings by the exact full input and provider/model/revision/dimensions/
744
+ preprocessing settings. Do not include commit, line numbers, file IDs, or build IDs
745
+ in that input. A line shift can update positions while reusing the same vector;
746
+ changed chunk boundaries or a renamed path in the input can legitimately miss.
747
+ Cache only successful validated outputs atomically. Query embeddings use the same
748
+ compatible contract and have their own cache/budget accounting. Provider aliases
749
+ may drift if no immutable model revision exists; record that limitation.
750
+
751
+ ## 9. Candidate validation, publication, and `versions`
752
+
753
+ ### Why candidate and published Tags are separate
754
+
755
+ A raw Tag proves Snapshot immutability, not completed ingestion. Local validation
756
+ state alone is insufficient when a fresh CLI installation must list usable versions.
757
+ Use two application naming namespaces under the inspected ref-name limits:
758
+
759
+ - `try-<candidate-id>`: candidate. Hidden from normal `versions`; available under
760
+ `versions --all` as unverified/failed/abandoned where evidence exists.
761
+ - `ver-<commit-digest>`: published. Use a deterministic bounded digest of the full
762
+ commit OID within this fixed-config Collection; verify full identity on collision.
763
+
764
+ Publication is a protocol enforced by the importer, not a server-provided status.
765
+ Manual or foreign resources that violate it are reported as inconsistent.
766
+
767
+ ### Temporary completion marker for committed indexing
768
+
769
+ On September 24-25, the user confirmed that current Tag creation selects the latest
770
+ indexed Snapshot even after write ACK, and reported indexing in acknowledged write
771
+ order. Work to snapshot WAL plus indexed data is in progress; this design does not
772
+ assume that future behavior is deployed.
773
+
774
+ Use the final root manifest as the completion marker for ordinary upsert/delete.
775
+ The ordering premise is that a committed Snapshot exposing this marker contains
776
+ all preceding acknowledged mutations, including deletes, across the corpus. This
777
+ is user-reported behavior, not a live verification performed in this project.
778
+ Verify that premise with the live fixture, including deletes and all affected
779
+ partitions/indexes; do not infer it solely from a marker in one document.
780
+
781
+ After all data and inventory mutations have successful ACKs, write `__manifest__`
782
+ as a separate final request (section 6). Fetch it by ID from the same code Branch
783
+ with explicit `consistentRead=false`, using bounded backoff/deadline. Match this
784
+ attemptId, buildId, commitOid, configHash, and expected hashes, not merely document
785
+ existence. A previous attempt's marker for the same commit cannot satisfy the wait.
786
+ The stable build ID and unique attempt ID have different purposes.
787
+
788
+ Hold exclusive writer ownership through Tag validation and publication. Do not
789
+ write the next commit or mutate source records after the marker. Starting B before
790
+ A is captured could produce a Snapshot containing both phases without a usable
791
+ A-only state. Do not use `consistentRead=true`, an ACK timestamp with `asOf`, a fixed
792
+ sleep, or a Branch head change alone as completion proof.
793
+
794
+ The marker is an ordering check, not evidence that the importer generated correct
795
+ records. Keep candidate content validation below. If the ordering premise is not
796
+ established, marker polling remains only a hint and full immutable-candidate
797
+ validation decides correctness. Timeouts leave a resumable, unpublished attempt;
798
+ they do not authorize the next commit on that workspace.
799
+
800
+ ### Publication steps
801
+
802
+ 1. Freeze code-Branch writes after the final manifest ACK and wait for its matching
803
+ marker as above. Reject unresolved write or required embedding failures.
804
+ 2. Create a unique candidate Tag from that Branch and record its Snapshot ID and
805
+ originating attemptId. Each probe uses a fresh candidate ID under ref-name limits.
806
+ 3. Read the root manifest through that exact Tag and require the same attempt and
807
+ build identity. A Branch read may precede Tag metadata propagation; a mismatch
808
+ cannot be published. Then compare complete file/chunk ID sets, inventory parts,
809
+ deletions, actual content/record hashes, byte/line spans, embedding eligibility
810
+ and vector shape, and representative query/read results. Recompute hashes from
811
+ the actual records, paging through the complete immutable corpus; a declared
812
+ manifest hash or count equality is insufficient.
813
+ 4. Persist a validation summary on control main, with candidate/Snapshot/build/
814
+ attempt identity and verifier version. Use an ID derived from the full commit
815
+ OID and candidate Snapshot ID so attempts cannot overwrite another Snapshot's
816
+ evidence. Confirm its readback before publication.
817
+ 5. Create the deterministic published Tag **from the validated candidate Tag**,
818
+ not from the mutable Branch. Verify both Tags have the same Snapshot ID and
819
+ matching manifest. Publication changes naming, not corpus content.
820
+ 6. Update optional branch-progress/control records and return the published version.
821
+ A delayed bookkeeping write does not erase an already published immutable Tag.
822
+
823
+ An empty Snapshot or incomplete candidate never becomes published. A stale Tag
824
+ will not become complete by waiting; keep the Branch frozen, wait for committed
825
+ progress, and probe a fresh candidate. Head changes only trigger another check;
826
+ avoid repeatedly validating known stale Snapshot IDs. A payload/build defect
827
+ requires explicit same-build recovery, not endless polling. Publication must
828
+ finish before the same code Branch starts a later commit.
829
+
830
+ ### `versions` reads LambdaDB
831
+
832
+ 1. Resolve the repository Collection through remote metadata.
833
+ 2. List its Tags; select the reserved published namespace for the normal view.
834
+ 3. Fetch `__manifest__` through each published Tag, using bounded concurrency, and
835
+ verify full commit/config identity and deterministic name. Recover commit and
836
+ counts from the manifest, not by reversing a short hash in a Tag name.
837
+ 4. Read the matching validation summary from control main. If it is missing or
838
+ inconsistent, show `needs verification` rather than silently asserting validity.
839
+ Listing checks publication evidence; it does not rerun full corpus validation.
840
+ 5. List Aliases, select release mappings, and join them to published Tags. Full Git
841
+ names come from ref-control records, not a lossy reverse mapping of Alias names.
842
+ 6. Display commit, Git release names if present, publication time, coverage/counts,
843
+ and availability. Distinguish Git commit time from Tag creation time.
844
+
845
+ Only imported/published commits are listed, not all commits or all tags in Git.
846
+ A published commit with no Git tag still appears. A Git tag pointing to an unimported
847
+ commit is pending in synchronization output, not an available search version.
848
+ Listing and source reads work without a local Git clone. Alias/ref observation
849
+ freshness is shown; this command does not claim to have polled GitHub for current refs.
850
+
851
+ If creation of a published Tag has an unknown result, list and inspect the expected
852
+ name/Snapshot/manifest before retrying. Existing valid publication is reused.
853
+ A crash after candidate validation but before publication can be recovered by
854
+ revalidating that candidate and publishing; a `try-*` name alone is never enough.
855
+
856
+ ## 10. Git tags, exact version selection, and recovery
857
+
858
+ ### Git release Alias synchronization
859
+
860
+ `sync-tags` reads an explicitly authoritative Git ref view. Record the original
861
+ ref, encoded Alias name, desired commit, and observation time on control main
862
+ before mutation. Create/retarget the Alias only to an already published `ver-*`
863
+ Tag. It does not import missing commits or call embeddings implicitly.
864
+
865
+ The initial ref view is the attached local clone's currently present `refs/tags/*`,
866
+ with its observation time and completeness recorded. This is not a reconstruction
867
+ of deleted tags, historical tag movements, or a claim to know all remote tags.
868
+ Peel annotated tags to commits and reject non-commit targets. Synchronizing all
869
+ observed names does not import all target commits: missing ones remain pending.
870
+
871
+ Multiple Git tags pointing to one commit create multiple Aliases targeting the
872
+ same canonical commit Tag. Import, chunking, embedding, and validation happen once
873
+ for that commit/configuration. Encode each full Git ref into a distinct bounded
874
+ Alias name and keep the original name in its control record; raw Git names need
875
+ not satisfy LambdaDB ref-name rules.
876
+
877
+ ```text
878
+ Git refs/tags/v1.0.0 -> Alias rel-<ref-X-digest> --+
879
+ +-> Tag ver-<commit-A-digest> -> Snapshot S
880
+ Git refs/tags/stable -> Alias rel-<ref-Y-digest> --+
881
+ ```
882
+
883
+ Do not create a separate LambdaDB release Tag for every Git tag. Moving or deleting
884
+ one Git tag affects only its Alias; other Aliases and the canonical commit Tag stay
885
+ intact. Search resolves any selected Alias to that immutable commit Tag before use.
886
+
887
+ Full Git history replay is unnecessary. To index every desired release, import the
888
+ unique target commits only. Each target supplies a complete Git tree: build it from
889
+ an empty workspace or diff it against a known validated writer baseline. For
890
+ A -> B -> C -> D -> E with releases at A/C/E, B and D need no imports. Chronological
891
+ order is optional for reuse, not a correctness rule; do not assume Tag-to-Branch
892
+ creation when choosing a baseline. Import remains separate from `sync-tags`.
893
+
894
+ A moved Git tag leaves its previous Alias target until the new target is published.
895
+ If the app knows the requested Git name now points elsewhere, report pending rather
896
+ than quietly treating the stale target as current. Deletion removes only the Alias;
897
+ retention of commit Tags is separate. Do not infer deletion from a shallow/incomplete
898
+ clone or an absent fetch. Interrupted ref-control/Alias updates reconcile against
899
+ actual Alias target and recorded intent; they are not a cross-resource transaction.
900
+
901
+ `resolve --ref` returns a published version identity. Search/read then use that
902
+ immutable Tag, never a moving Alias or Branch. Tag and Alias metadata/API calls
903
+ are accessed through the SDK; Branch-from-Tag and arbitrary Snapshot reset are not
904
+ assumed. The earlier sbrain release-Tag mapping is superseded by Git tag -> Alias.
905
+
906
+ ### Failures and operational boundaries
907
+
908
+ Use a single designated importing process/host initially and a local exclusive
909
+ Collection lock. Remote discovery does not imply a distributed locking protocol.
910
+ Unexpected writers or uncertain baselines block further corpus mutation. Read-only
911
+ clients may operate from multiple machines without local registry replication.
912
+
913
+ Disable transparent mutation retries. Record accepted/rejected/unknown batches.
914
+ On partial or unknown writes, freeze the affected workspace and reconcile the
915
+ journal against the same intended build. Never apply a newer commit over an
916
+ uncertain baseline. Explicit same-build upsert/delete replay is allowed only under
917
+ exclusive ownership; it is not an assumed API idempotency receipt.
918
+
919
+ If baseline recovery is impossible, preserve the failed workspace and rebuild from
920
+ Git on a fresh Branch sourced from checkpoint-empty. Validate and publish before
921
+ serving. Do not assume Branch merge/reset, Tag-to-Branch creation, or an implemented
922
+ readiness endpoint. Branch `consistentRead` is useful for small control documents,
923
+ not proof that a code Tag contains accepted mutations.
924
+
925
+ Keep bounded attempt/deadline policies and failure reports. Do not delete failed
926
+ resources as automatic rollback. Candidate cleanup and published-version retention
927
+ are explicit later operations, protecting active Alias targets and investigations.
928
+ Missing original versions fail clearly rather than substituting newer source.
929
+
930
+ ## 11. Local preparation, implementation stages, and tests
931
+
932
+ The application always targets LambdaDB for shared storage and serving. For work
933
+ without credentials, implement a pure Git-to-build pipeline, exported JSONL/
934
+ inventory/deletion plans, fixture source readers, and small SDK test doubles. Keep
935
+ these behind tests or developer scripts, with no public backend selection. They
936
+ can also feed a later comparison benchmark without generalizing the product.
937
+
938
+ ```sh
939
+ # Credential-free inspection of a fixture; no repository registration required.
940
+ srcx import --path /path/to/fixture --ref <commit-A> --dry-run
941
+ ```
942
+
943
+ | Stage | Deliverable | Exit evidence |
944
+ | --- | --- | --- |
945
+ | 1. Bootstrap/config | English README, TypeScript package, pinned dependencies/preset, optional key override, Git identity | Config/identity fixtures pass; no secret stored |
946
+ | 2. Inventory/chunking | Pure build planner and path-based dry-run | Every entry accounted for; precise spans and bounded chunks |
947
+ | 3. Two-commit local verification | Materialized A/B artifacts, deletion plan, cache and search/read fixture harness | A/B inventories and original evidence remain correct; no remote claim |
948
+ | 4. LambdaDB integration | Remote provisioning/discovery, schema, batches, final-marker wait, candidate validation/publication, versions/search/read | SDK mocks pass; separately authorized live fixture checks actual APIs and marker ordering |
949
+ | 5. Git release names | Alias synchronization and ref-control recovery | Moves/deletions and pinned investigations behave correctly |
950
+
951
+ The first completion criterion remains: process two commits, reflect additions/
952
+ modifications/deletions, and connect each version's chunks to exact source. Report
953
+ local artifact/mock completion separately from LambdaDB live completion.
954
+
955
+ Implement the internal window baseline alongside stage 2's chunker. Run the
956
+ section 8 query comparison once a retrieval path is available, and report whether
957
+ it used local fixtures, actual lexical serving, or an authorized embedding run.
958
+ No retrieval-quality result is implied by local chunking correctness checks.
959
+
960
+ Required meaningful checks:
961
+
962
+ - Default API key variable works; override is optional; no key is saved/logged.
963
+ - Configure/doctor have no resource-creation effects. Project changes never redirect
964
+ an old result handle or retry journal to another resource.
965
+ - SSH/HTTPS identity normalization and fork/name collisions behave correctly.
966
+ - A fresh local state directory can discover repos/versions and read evidence from
967
+ the same project. Missing descriptors/ref records report partial initialization.
968
+ - Provisioning retries resume safely without duplicate or unrelated resource adoption.
969
+ - Dirty working files and a moving ref do not alter the initially pinned import.
970
+ - Every tree entry has inclusion/exclusion evidence; special files are not traversed.
971
+ - Byte coverage, Unicode/BOM/CRLF/trailing-newline/long-line spans are exact.
972
+ - Parse failures and huge nodes stay bounded and visible in reports.
973
+ - B contains additions/replacements/deletions while A reads remain unchanged.
974
+ - A controlled line-shift fixture updates positions and reuses identical embeddings.
975
+ - Different paths remain distinct even with identical bytes; reuse follows input.
976
+ - Fixed-config mismatches fail before writes; fake vectors never enter a real corpus.
977
+ - Explicit obsolete-ID deletion preserves replacement IDs and removes surplus chunks.
978
+ - Eligible code/prose chunks have valid vectors; policy skips remain covered and
979
+ lexically retrievable where meaningful. Required embedding failures block publication.
980
+ - The last manifest is a separate request after every prior ACK; a stale attempt's
981
+ marker, unresolved mutation, or `consistentRead=true` read cannot complete the wait.
982
+ - Candidate Tag readback matches the marker even if Branch and Tag observations lag.
983
+ Verify ordered marker visibility across deletes and affected partitions/indexes live.
984
+ - A marker does not hide an intentionally corrupted/missing record from validation.
985
+ - Partial writes and stale candidates cannot appear in normal published versions.
986
+ - The final Tag has exactly the validated candidate's Snapshot, even if a Branch moves.
987
+ - Publication and Alias crash points recover without local-only version truth.
988
+ - Two Git tags for one commit create two Aliases to one commit Tag without repeated
989
+ import/embedding; moving/deleting one leaves the other mapping intact.
990
+ - Missing release commits stay pending; importing selected nonadjacent commits does
991
+ not require intermediate commits or historical/deleted Git tag reconstruction.
992
+ - Search filters to chunks and reads original source through the same published Tag.
993
+ Context, whole-file, and direct path/line reads preserve that version and its spans.
994
+
995
+ Do not write tests that merely mirror implementation. Test doubles establish workflow
996
+ behavior only; actual serving, mixed schema, metadata discovery, Tag-from-Tag,
997
+ readback, and deletion visibility need a fixture live run. Paid model relevance,
998
+ latency, and operational cost are separate measurements.
999
+
1000
+ ## 12. Remaining decisions and inspected evidence
1001
+
1002
+ | Decision | When needed |
1003
+ | --- | --- |
1004
+ | First real repositories and parser priority | Real-repository evaluation; defaults do not block fixtures |
1005
+ | Exact parser/tokenizer/preset versions, enrichment and embedding skip rules | Bootstrap and retrieval evaluation; pin before publishing a corpus |
1006
+ | Chunk size/overlap and syntax-versus-window tradeoff | Section 8 pilot after retrieval works; current values are starting points |
1007
+ | Embedding model/dimensions/provider, data destination, spending cap | Before any real source upload or paid experiment |
1008
+ | LambdaDB endpoint/project and credentials | Provisioning and live fixture run |
1009
+ | Authoritative Git-tag source and observed-ref freshness policy | Manual Alias synchronization |
1010
+ | Concurrent multi-host writers, retention/cleanup, configuration migration | Later internal operation, outside first CLI |
1011
+
1012
+ Sources and evidence used during this design discussion:
1013
+
1014
+ - September 24-25 user discussion: current ACK/Tag timing, acknowledged-write
1015
+ indexing order, and ongoing WAL-plus-indexed Snapshot work. Marker ordering is
1016
+ an implementation premise requiring the live checks in section 11. The user
1017
+ reconfirmed Git tag -> Alias, including multiple names for one commit.
1018
+ - SDK versioning contract (`lambdadb-typescript-client/docs/data-versioning.md`):
1019
+ Tag-from-Tag Snapshot identity and Branch-only consistent reads, inspected during
1020
+ the discussion; not proof of the deployed revision.
1021
+ - Internal pilot and product-scope notes: prior boundaries and deployment
1022
+ confirmation; these notes are not included in this repository.
1023
+ - Existing CLI configuration (`lambdadb-cli/src/config.ts`):
1024
+ optional API-key environment override with default `LAMBDADB_API_KEY`.
1025
+ - CLI import workflow (`lambdadb-cli/src/import-workflow.ts`):
1026
+ byte-aware batching and accepted/failed/unknown outcomes.
1027
+ - SDK local revision `856abf48a014185de54ccc541c2f6ee3871133ee`:
1028
+ Collection list (`lambdadb-typescript-client/src/models/operations/listcollections.ts`),
1029
+ Collection response (`lambdadb-typescript-client/src/models/collectionresponse.ts`),
1030
+ create (`lambdadb-typescript-client/src/models/operations/createcollection.ts`),
1031
+ metadata labels (`lambdadb-typescript-client/src/lib/collectionContract.ts`),
1032
+ field types (`lambdadb-typescript-client/src/models/indexconfigsunion.ts`),
1033
+ ref models (`lambdadb-typescript-client/src/models/versioning.ts`),
1034
+ versioning calls (`lambdadb-typescript-client/src/versioning.ts`),
1035
+ and fetch contract (`lambdadb-typescript-client/src/models/operations/fetchdocs.ts`).
1036
+ - [Public Collection creation](https://docs.lambdadb.ai/guides/collections/create-a-collection)
1037
+ and [index types](https://docs.lambdadb.ai/guides/collections/index-types):
1038
+ creation/schema/metadata constraints and stored-only fields, checked September 22;
1039
+ description/metadata limits rechecked September 23.
1040
+ - [Public upsert limits](https://docs.lambdadb.ai/guides/documents/upsert-data),
1041
+ checked earlier in this discussion, and
1042
+ local size validation (`lambdadb/core/src/main/java/ai/lambdadb/application/validation/Validation.java`)
1043
+ at feature revision `eddc1953d71389f8ad302b40eec3df90b137c8d7`.
1044
+ - [Tree-sitter parsing](https://tree-sitter.github.io/tree-sitter/using-parsers/2-basic-parsing.html):
1045
+ source ranges and encodings; verify the selected binding during implementation.
1046
+
1047
+ Development checkout references identify the inspected files, not runtime
1048
+ dependencies. No
1049
+ application tests, source uploads, embeddings, or live LambdaDB validation have
1050
+ been performed as part of writing this document.
1051
+
1052
+ Document validation: the revised lexical `indexConfigs` JSON, description, four
1053
+ reserved metadata labels, and one optional context label passed the local built
1054
+ SDK's Collection-create input validator on September 25. All three JSON examples,
1055
+ the illustrative source span, then-local links, code fences, and whitespace also passed
1056
+ document checks. These checks do not establish server acceptance, marker ordering,
1057
+ or search quality.