@nomos-arc/arc 0.1.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.
Files changed (160) hide show
  1. package/.claude/settings.local.json +10 -0
  2. package/.nomos-config.json +5 -0
  3. package/CLAUDE.md +108 -0
  4. package/LICENSE +190 -0
  5. package/README.md +569 -0
  6. package/dist/cli.js +21120 -0
  7. package/docs/auth/googel_plan.yaml +1093 -0
  8. package/docs/auth/google_task.md +235 -0
  9. package/docs/auth/hardened_blueprint.yaml +1658 -0
  10. package/docs/auth/red_team_report.yaml +336 -0
  11. package/docs/auth/session_state.yaml +162 -0
  12. package/docs/certificate/cer_enhance_plan.md +605 -0
  13. package/docs/certificate/certificate_report.md +338 -0
  14. package/docs/dev_overview.md +419 -0
  15. package/docs/feature_assessment.md +156 -0
  16. package/docs/how_it_works.md +78 -0
  17. package/docs/infrastructure/map.md +867 -0
  18. package/docs/init/master_plan.md +3581 -0
  19. package/docs/init/red_team_report.md +215 -0
  20. package/docs/init/report_phase_1a.md +304 -0
  21. package/docs/integrity-gate/enhance_drift.md +703 -0
  22. package/docs/integrity-gate/overview.md +108 -0
  23. package/docs/management/manger-task.md +99 -0
  24. package/docs/management/scafffold.md +76 -0
  25. package/docs/map/ATOMIC_BLUEPRINT.md +1349 -0
  26. package/docs/map/RED_TEAM_REPORT.md +159 -0
  27. package/docs/map/map_task.md +147 -0
  28. package/docs/map/semantic_graph_task.md +792 -0
  29. package/docs/map/semantic_master_plan.md +705 -0
  30. package/docs/phase7/TEAM_RED.md +249 -0
  31. package/docs/phase7/plan.md +1682 -0
  32. package/docs/phase7/task.md +275 -0
  33. package/docs/prompts/USAGE.md +312 -0
  34. package/docs/prompts/architect.md +165 -0
  35. package/docs/prompts/executer.md +190 -0
  36. package/docs/prompts/hardener.md +190 -0
  37. package/docs/prompts/red_team.md +146 -0
  38. package/docs/verification/goveranance-overview.md +396 -0
  39. package/docs/verification/governance-overview.md +245 -0
  40. package/docs/verification/verification-arc-ar.md +560 -0
  41. package/docs/verification/verification-architecture.md +560 -0
  42. package/docs/very_next.md +52 -0
  43. package/docs/whitepaper.md +89 -0
  44. package/overview.md +1469 -0
  45. package/package.json +63 -0
  46. package/src/adapters/__tests__/git.test.ts +296 -0
  47. package/src/adapters/__tests__/stdio.test.ts +70 -0
  48. package/src/adapters/git.ts +226 -0
  49. package/src/adapters/pty.ts +159 -0
  50. package/src/adapters/stdio.ts +113 -0
  51. package/src/cli.ts +83 -0
  52. package/src/commands/apply.ts +47 -0
  53. package/src/commands/auth.ts +301 -0
  54. package/src/commands/certificate.ts +89 -0
  55. package/src/commands/discard.ts +24 -0
  56. package/src/commands/drift.ts +116 -0
  57. package/src/commands/index.ts +78 -0
  58. package/src/commands/init.ts +121 -0
  59. package/src/commands/list.ts +75 -0
  60. package/src/commands/map.ts +55 -0
  61. package/src/commands/plan.ts +30 -0
  62. package/src/commands/review.ts +58 -0
  63. package/src/commands/run.ts +63 -0
  64. package/src/commands/search.ts +147 -0
  65. package/src/commands/show.ts +63 -0
  66. package/src/commands/status.ts +59 -0
  67. package/src/core/__tests__/budget.test.ts +213 -0
  68. package/src/core/__tests__/certificate.test.ts +385 -0
  69. package/src/core/__tests__/config.test.ts +191 -0
  70. package/src/core/__tests__/preflight.test.ts +24 -0
  71. package/src/core/__tests__/prompt.test.ts +358 -0
  72. package/src/core/__tests__/review.test.ts +161 -0
  73. package/src/core/__tests__/state.test.ts +362 -0
  74. package/src/core/auth/__tests__/manager.test.ts +166 -0
  75. package/src/core/auth/__tests__/server.test.ts +220 -0
  76. package/src/core/auth/gcp-projects.ts +160 -0
  77. package/src/core/auth/manager.ts +114 -0
  78. package/src/core/auth/server.ts +141 -0
  79. package/src/core/budget.ts +119 -0
  80. package/src/core/certificate.ts +502 -0
  81. package/src/core/config.ts +212 -0
  82. package/src/core/errors.ts +54 -0
  83. package/src/core/factory.ts +49 -0
  84. package/src/core/graph/__tests__/builder.test.ts +272 -0
  85. package/src/core/graph/__tests__/contract-writer.test.ts +175 -0
  86. package/src/core/graph/__tests__/enricher.test.ts +299 -0
  87. package/src/core/graph/__tests__/parser.test.ts +200 -0
  88. package/src/core/graph/__tests__/pipeline.test.ts +202 -0
  89. package/src/core/graph/__tests__/renderer.test.ts +128 -0
  90. package/src/core/graph/__tests__/resolver.test.ts +185 -0
  91. package/src/core/graph/__tests__/scanner.test.ts +231 -0
  92. package/src/core/graph/__tests__/show.test.ts +134 -0
  93. package/src/core/graph/builder.ts +303 -0
  94. package/src/core/graph/constraints.ts +94 -0
  95. package/src/core/graph/contract-writer.ts +93 -0
  96. package/src/core/graph/drift/__tests__/classifier.test.ts +215 -0
  97. package/src/core/graph/drift/__tests__/comparator.test.ts +335 -0
  98. package/src/core/graph/drift/__tests__/drift.test.ts +453 -0
  99. package/src/core/graph/drift/__tests__/reporter.test.ts +203 -0
  100. package/src/core/graph/drift/classifier.ts +165 -0
  101. package/src/core/graph/drift/comparator.ts +205 -0
  102. package/src/core/graph/drift/reporter.ts +77 -0
  103. package/src/core/graph/enricher.ts +251 -0
  104. package/src/core/graph/grammar-paths.ts +30 -0
  105. package/src/core/graph/html-template.ts +493 -0
  106. package/src/core/graph/map-schema.ts +137 -0
  107. package/src/core/graph/parser.ts +336 -0
  108. package/src/core/graph/pipeline.ts +209 -0
  109. package/src/core/graph/renderer.ts +92 -0
  110. package/src/core/graph/resolver.ts +195 -0
  111. package/src/core/graph/scanner.ts +145 -0
  112. package/src/core/logger.ts +46 -0
  113. package/src/core/orchestrator.ts +792 -0
  114. package/src/core/plan-file-manager.ts +66 -0
  115. package/src/core/preflight.ts +64 -0
  116. package/src/core/prompt.ts +173 -0
  117. package/src/core/review.ts +95 -0
  118. package/src/core/state.ts +294 -0
  119. package/src/core/worktree-coordinator.ts +77 -0
  120. package/src/search/__tests__/chunk-extractor.test.ts +339 -0
  121. package/src/search/__tests__/embedder-auth.test.ts +124 -0
  122. package/src/search/__tests__/embedder.test.ts +267 -0
  123. package/src/search/__tests__/graph-enricher.test.ts +178 -0
  124. package/src/search/__tests__/indexer.test.ts +518 -0
  125. package/src/search/__tests__/integration.test.ts +649 -0
  126. package/src/search/__tests__/query-engine.test.ts +334 -0
  127. package/src/search/__tests__/similarity.test.ts +78 -0
  128. package/src/search/__tests__/vector-store.test.ts +281 -0
  129. package/src/search/chunk-extractor.ts +167 -0
  130. package/src/search/embedder.ts +209 -0
  131. package/src/search/graph-enricher.ts +95 -0
  132. package/src/search/indexer.ts +483 -0
  133. package/src/search/lexical-searcher.ts +190 -0
  134. package/src/search/query-engine.ts +225 -0
  135. package/src/search/vector-store.ts +311 -0
  136. package/src/types/index.ts +572 -0
  137. package/src/utils/__tests__/ansi.test.ts +54 -0
  138. package/src/utils/__tests__/frontmatter.test.ts +79 -0
  139. package/src/utils/__tests__/sanitize.test.ts +229 -0
  140. package/src/utils/ansi.ts +19 -0
  141. package/src/utils/context.ts +44 -0
  142. package/src/utils/frontmatter.ts +27 -0
  143. package/src/utils/sanitize.ts +78 -0
  144. package/test/e2e/lifecycle.test.ts +330 -0
  145. package/test/fixtures/mock-planner-hang.ts +5 -0
  146. package/test/fixtures/mock-planner.ts +26 -0
  147. package/test/fixtures/mock-reviewer-bad.ts +8 -0
  148. package/test/fixtures/mock-reviewer-retry.ts +34 -0
  149. package/test/fixtures/mock-reviewer.ts +18 -0
  150. package/test/fixtures/sample-project/src/circular-a.ts +6 -0
  151. package/test/fixtures/sample-project/src/circular-b.ts +6 -0
  152. package/test/fixtures/sample-project/src/config.ts +15 -0
  153. package/test/fixtures/sample-project/src/main.ts +19 -0
  154. package/test/fixtures/sample-project/src/services/product-service.ts +20 -0
  155. package/test/fixtures/sample-project/src/services/user-service.ts +18 -0
  156. package/test/fixtures/sample-project/src/types.ts +14 -0
  157. package/test/fixtures/sample-project/src/utils/index.ts +14 -0
  158. package/test/fixtures/sample-project/src/utils/validate.ts +12 -0
  159. package/tsconfig.json +20 -0
  160. package/vitest.config.ts +12 -0
@@ -0,0 +1,249 @@
1
+ # Adversarial Architect — Zero-Trust Audit Report
2
+
3
+ **Subject:** Phase 7: Global Semantic Search — Atomic Implementation Blueprint
4
+ **Auditor Role:** Chief Adversarial Architect & Lead SRE
5
+ **Date:** 2026-04-06
6
+ **Classification:** Production Readiness Assessment
7
+
8
+ ---
9
+
10
+ ## 1. VETO STATUS: CONDITIONAL
11
+
12
+ The plan is **not safe for production execution** in its current form. While architecturally competent at surface level, it contains multiple race conditions, unguarded failure modes, and silent data corruption vectors that would cause outages in a live system under non-trivial load. Execution is conditional on resolution of all Critical Blockers below.
13
+
14
+ ---
15
+
16
+ ## 2. CRITICAL BLOCKERS (System Killers)
17
+
18
+ ### BLOCKER-1: Full Index `reset()` + `upsert()` Is Not Atomic — Zero-Availability Window
19
+
20
+ **Location:** Step 7.4.1, Full Index Flow, steps 5–6.
21
+
22
+ The plan calls `VectorStore.reset()` (drop table) followed by `VectorStore.upsert(records)`. Between these two operations, the vector index is **empty**. Any concurrent `arc search` query hitting the store during this window will either:
23
+ - Return zero results (silent failure — user believes nothing matches).
24
+ - Throw an error because the table does not exist (crash).
25
+
26
+ The plan states "LanceDB uses Lance format with transactional writes — no partial corruption on crash." This is true for individual writes, but **the plan does not wrap reset+upsert in a single transaction**. LanceDB's transaction guarantee applies per-operation, not across two sequential operations. The plan conflates operation-level atomicity with pipeline-level atomicity.
27
+
28
+ **Severity:** Data loss / availability gap during every full re-index.
29
+
30
+ **Mitigation:** Write to a new table (`nomos_vectors_tmp`), then atomically swap by dropping old and renaming new. Or use LanceDB's versioning/overwrite mode if available.
31
+
32
+ ---
33
+
34
+ ### BLOCKER-2: `index-meta.json` Write Is Inconsistent With Vector Store State
35
+
36
+ **Location:** Step 7.4.1, Full Index Flow, steps 6–7.
37
+
38
+ The upsert to LanceDB (step 6) and the metadata write to `index-meta.json` (step 7) are two separate, non-transactional operations. If the process crashes after step 6 but before step 7:
39
+ - The vector store contains the new data.
40
+ - The metadata file references the **old** state (or doesn't exist).
41
+ - Incremental index reads stale metadata → re-indexes everything unnecessarily, or worse, computes wrong diffs.
42
+
43
+ If the process crashes after step 7's `.tmp` write but before the rename:
44
+ - Metadata is lost. The `.tmp` file is orphaned.
45
+ - Next incremental index falls back to full index (stated behavior), but the full index calls `reset()` — destroying a perfectly valid vector store.
46
+
47
+ **Severity:** State corruption on crash during indexing.
48
+
49
+ **Mitigation:** Write metadata **before** the upsert with a `status: "in_progress"` field. Mark `status: "complete"` after upsert succeeds. On startup, if status is `in_progress`, force a full re-index.
50
+
51
+ ---
52
+
53
+ ### BLOCKER-3: No Vector Dimension Validation on Incremental Index
54
+
55
+ **Location:** Step 7.4.1, Incremental Index Flow. Risk Register mentions this but provides no implementation.
56
+
57
+ The Risk Register identifies "Vector dimensions mismatch" and states "Validate on incremental index — force full re-index if dimensions changed." However, the incremental index flow (steps 1–11) contains **zero** dimension validation logic. If the `embedding_model` config changes between a full index and an incremental index:
58
+ - New 768-dim vectors get upserted alongside old vectors of a different dimension.
59
+ - Cosine similarity calculations between mismatched dimensions produce garbage results.
60
+ - LanceDB may or may not reject this at the Arrow schema level — the plan does not verify.
61
+
62
+ **Severity:** Silent data corruption. Search returns nonsense results with no error signal.
63
+
64
+ **Mitigation:** Step 2 of incremental flow must compare `IndexMetadata.embedding_model` and `IndexMetadata.vector_dimensions` against current config. Mismatch → force full re-index with explicit log message.
65
+
66
+ ---
67
+
68
+ ### BLOCKER-4: Unbounded Memory During Embedding Composition
69
+
70
+ **Location:** Step 7.4.1, Full Index Flow, step 4.
71
+
72
+ The plan states: "Never hold all vectors in memory simultaneously." However, step 4 composes `VectorRecord[]` from **all** `TextChunks + vectors`. This means:
73
+ - All `Float32Array` vectors from `embedBatch()` are held in memory.
74
+ - All `VectorRecord` objects (which include the vectors) are constructed in a single array.
75
+ - Then passed to `VectorStore.upsert(records)` as a single batch.
76
+
77
+ For a 500-file project with ~1500 chunks, each with a 768-dim Float32Array (3KB per vector): `1500 * 3KB = 4.5MB` in vectors alone, plus the record metadata. For a 5000-file project: ~45MB. This is manageable, but the plan claims streaming batch processing (Risk Register) while the implementation design does not deliver it.
78
+
79
+ **Severity:** Memory pressure / OOM on large projects. The plan's own Risk Register contradicts its implementation.
80
+
81
+ **Mitigation:** Upsert in batches matching the embedding batch size. After each embedding batch completes, compose records and upsert immediately, then release references.
82
+
83
+ ---
84
+
85
+ ## 3. AMBIGUITY TRAPS
86
+
87
+ ### TRAP-1: `mergeInsert` Fallback Strategy Is Undefined
88
+
89
+ **Location:** Step 7.1.1, Internal Design point 4.
90
+
91
+ > "If `mergeInsert` is unavailable in the installed version, fall back to delete-then-add."
92
+
93
+ The plan fails to specify **how** to detect whether `mergeInsert` is available. Runtime feature detection? Try-catch? Version string comparison? An AI agent implementing this will likely:
94
+ - Wrap in try-catch, masking real errors as "feature unavailable."
95
+ - Implement the fallback path (delete-then-add) which is **not atomic** and creates a window where records are deleted but not yet re-added.
96
+
97
+ This is an instruction to an implementer that will produce non-deterministic behavior.
98
+
99
+ ---
100
+
101
+ ### TRAP-2: "Process Chunks Sequentially" vs. `max_concurrent_requests` Config
102
+
103
+ **Location:** Step 7.2.1, Internal Design point 4 vs. Config Step 7.0.4.
104
+
105
+ The config defines `max_concurrent_requests: 5`, implying concurrent batch processing. The embedder design says "Process chunks sequentially to respect rate limits." These are contradictory. An implementer will either:
106
+ - Ignore `max_concurrent_requests` entirely (dead config).
107
+ - Implement concurrency, violating the sequential processing instruction and creating rate limit violations.
108
+
109
+ The plan must pick one: sequential with rate-limit delays, or concurrent with a semaphore. Not both.
110
+
111
+ ---
112
+
113
+ ### TRAP-3: De-duplication Logic Lacks Determinism
114
+
115
+ **Location:** Step 7.5.2, Internal Design step 7.
116
+
117
+ > "If same file_path appears as both 'file' and 'symbol' type, the symbol entry takes priority in ranking when scores are within 0.05."
118
+
119
+ What does "takes priority" mean? Swap their positions? Remove the file-level result? Boost the symbol score? And "within 0.05" — is that absolute difference or relative? If two symbol chunks from the same file both appear alongside the file chunk, which symbol "takes priority"?
120
+
121
+ This is insufficiently specified for deterministic implementation.
122
+
123
+ ---
124
+
125
+ ### TRAP-4: `graph_depth: -1` Sentinel Value
126
+
127
+ **Location:** Step 7.5.1, Internal Design point 3.
128
+
129
+ Using `-1` as a sentinel for "file was deleted after indexing" is a type-unsafe convention that will leak into downstream formatting. The CLI output (Step 7.6.2) shows `depth {N}` — will it print `depth -1`? The plan does not address how the CLI formats stale results. An implementer may print `depth -1` to the user, or crash on negative depth, or silently omit the result.
130
+
131
+ ---
132
+
133
+ ### TRAP-5: `.semantic.md` Path Derivation Is Fragile
134
+
135
+ **Location:** Step 7.3.1, Internal Design point 3.
136
+
137
+ > `fs.readFile(path.join(projectRoot, file_path.replace(/\.[^.]+$/, '.semantic.md')))`
138
+
139
+ This regex replaces the **last** extension. For files like `config.test.ts`, this produces `config.test.semantic.md`, not `config.semantic.md`. For extensionless files (e.g., `Makefile`), the regex matches nothing and appends `.semantic.md` nowhere — the path is unchanged. The plan does not specify the actual `.semantic.md` naming convention from prior phases, leaving the implementer to guess.
140
+
141
+ ---
142
+
143
+ ## 4. RESILIENCE GAPS
144
+
145
+ ### GAP-1: Gemini API Outage During Indexing — Partial State, No Recovery
146
+
147
+ **Location:** Step 7.4.1, Error handling.
148
+
149
+ The plan states: "Embedding failure on a single batch: log error, continue with remaining batches. Track failed file paths."
150
+
151
+ This means if batches 3–7 fail (e.g., Gemini 503 for 2 minutes), the resulting index is **partial**: it contains vectors for batches 1–2 but not 3–7. The metadata is written with `total_chunks` reflecting only the successfully embedded count. On next incremental index, the content hashes for batches 3–7 files are unchanged — so they are **not re-indexed**. The partial index becomes permanent.
152
+
153
+ The plan has no mechanism to detect or repair a partial index. There is no `failed_files` field in `IndexMetadata`. The incremental diff only checks `content_hash`, not "was this file actually embedded."
154
+
155
+ **Impact:** Permanent search blind spots after any transient API failure.
156
+
157
+ **Mitigation:** Record failed file paths in `IndexMetadata.failed_files[]`. On next incremental index, treat failed files as "changed" regardless of hash. Or: fail the entire index operation on any batch failure (safer, simpler).
158
+
159
+ ---
160
+
161
+ ### GAP-2: LanceDB Corruption / Version Mismatch Has No Detection
162
+
163
+ The plan pins no specific LanceDB version and acknowledges the package is "pre-1.0" (Risk Register). If `npm install` pulls a new minor version that changes the on-disk format:
164
+ - Existing vector index may fail to open.
165
+ - No error handling is specified for `lancedb.connect()` failure.
166
+ - No schema migration path exists.
167
+
168
+ The plan's `VectorStore.init()` has no try-catch, no version validation, no schema compatibility check.
169
+
170
+ ---
171
+
172
+ ### GAP-3: SIGINT During `reset()` + `upsert()` Sequence
173
+
174
+ **Location:** Step 7.6.1, SIGINT handling.
175
+
176
+ The SIGINT handler sets `cancellationFlag.cancelled = true`, which is checked "between embedding batches." But the critical danger zone is between `reset()` and `upsert()` (BLOCKER-1). If SIGINT fires after `reset()` but before `upsert()` completes:
177
+ - The vector store is empty.
178
+ - The "partial metadata" write records zero chunks.
179
+ - The system is in an unrecoverable state without manual intervention (`arc index --force`).
180
+
181
+ The cancellation check granularity is at the **embedding** level, not the **store write** level. The most dangerous operation (reset) is not cancellation-aware.
182
+
183
+ ---
184
+
185
+ ### GAP-4: No Timeout on Gemini API Calls
186
+
187
+ **Location:** Step 7.2.1.
188
+
189
+ The embedder implements retry with backoff on 429/5xx, but specifies **no request timeout**. If the Gemini API hangs (TCP connection established, no response), the embedder will block indefinitely. The CLI becomes unresponsive. There is no `AbortController`, no socket timeout, no `Promise.race` with a deadline.
190
+
191
+ In a "3 AM" scenario: the on-call runs `arc index`, it hangs forever. No log output. No error. No timeout. They kill -9 it. See GAP-3.
192
+
193
+ ---
194
+
195
+ ### GAP-5: `arc search` Loads Full `project_map.json` On Every Query
196
+
197
+ **Location:** Step 7.5.2, Internal Design step 5.
198
+
199
+ Every `arc search` call loads and parses the full `project_map.json` for graph enrichment. For a large project, this file could be 5–50MB. The plan specifies AC-15 as "Search < 2s for 500 indexed files" — but if `project_map.json` is 20MB, just parsing it takes measurable time.
200
+
201
+ No caching, no lazy loading, no pre-computed graph metadata stored alongside the vector index.
202
+
203
+ ---
204
+
205
+ ## 5. MANDATORY MITIGATIONS
206
+
207
+ The following are **non-negotiable** requirements before this plan is approved for execution:
208
+
209
+ | # | Mitigation | Addresses |
210
+ |---|-----------|-----------|
211
+ | M-1 | Implement table-swap strategy for full re-index (write to temp table, atomic rename). Do not use `reset()` + `upsert()` as separate operations. | BLOCKER-1 |
212
+ | M-2 | Add `status` field to `IndexMetadata` (`in_progress` / `complete`). Write metadata at start and end of indexing. On startup with `in_progress`, force full re-index. | BLOCKER-2 |
213
+ | M-3 | Validate `embedding_model` and `vector_dimensions` in incremental index flow. Mismatch → automatic full re-index with warning log. | BLOCKER-3 |
214
+ | M-4 | Upsert records in batches immediately after embedding each batch. Do not accumulate all records in memory. | BLOCKER-4 |
215
+ | M-5 | Remove `max_concurrent_requests` config or implement it. Dead config is worse than no config — it implies a capability that doesn't exist. | TRAP-2 |
216
+ | M-6 | Add `failed_files: string[]` to `IndexMetadata`. On incremental index, re-index any file in `failed_files` regardless of content hash. | GAP-1 |
217
+ | M-7 | Add request-level timeout (30s default) to all Gemini API calls using `AbortController` or equivalent. | GAP-4 |
218
+ | M-8 | Wrap `lancedb.connect()` and table operations in try-catch with specific error messages. A corrupted index should produce a clear "run `arc index --force`" message, not an unhandled exception. | GAP-2 |
219
+ | M-9 | Pin `@lancedb/lancedb` to an exact version (`"x.y.z"`, not `"^x.y.z"`). Pre-1.0 packages have no semver stability guarantees. | GAP-2 |
220
+ | M-10 | Define deterministic de-duplication: if a symbol result and its parent file result are both present and within 0.05 similarity, **remove the file-level result** (keep only the more specific symbol result). Document this as a hard rule, not a vague "priority." | TRAP-3 |
221
+
222
+ ---
223
+
224
+ ## 6. SECONDARY CONCERNS (Non-Blocking)
225
+
226
+ | # | Concern | Note |
227
+ |---|---------|------|
228
+ | S-1 | Pre-flight check PF-5 (`src/search/` does not exist) prevents re-execution. If Phase 7 partially fails and is retried, this check blocks it. Idempotency violation at the plan level. | Change to: "If `src/search/` exists, verify it was created by Phase 7 (check for known files)." |
229
+ | S-2 | No `--dry-run` flag on `arc index`. For a command that makes external API calls (costs money) and writes to disk, dry-run should be mandatory for production systems. | Add `--dry-run` that extracts and counts chunks without embedding. |
230
+ | S-3 | Cosine distance range stated as `[0, 2]` (Step 7.1.1, point 5). This is correct for cosine distance but the plan conflates distance and similarity in multiple places. The threshold config is in similarity space (0.0–1.0), but LanceDB returns distance. Multiple conversion points = multiple bug opportunities. | Centralize the `1 - distance = similarity` conversion in exactly one place (`VectorStore.query()`). Assert in tests that returned similarity is in `[0, 1]`. |
231
+ | S-4 | Integration test (Step 7.7.1) requires `GEMINI_API_KEY` — skipped in CI. This means the most critical test (full pipeline) never runs in automated pipelines. The plan has no CI-compatible integration test strategy. | Add a mock-embedder integration test that runs in CI with deterministic fake vectors. |
232
+ | S-5 | `Float32Array` serialization to JSON (for `--json` output) will produce `{}` in most JS runtimes (`JSON.stringify(new Float32Array([1,2,3]))` → `{"0":1,"1":2,"2":3}`). The plan doesn't specify that vectors should be excluded from JSON search output. | Ensure `SearchResult` type does not include `vector` field. Verify JSON output does not leak raw vectors. |
233
+ | S-6 | The `content_hash` is computed from the composed text string, not the source file. If the text composition logic changes (e.g., different field ordering), all hashes change, forcing a full re-index. This couples hashing to presentation logic. | Hash the raw inputs (file path + semantic data + symbol signatures) separately from the composed text. Or accept the coupling and document it. |
234
+ | S-7 | Step 7.0.2 says "Append `--external:@lancedb/lancedb` to the build script." If the build script is already long and complex, appending may break argument ordering. The plan does not show the current build script. | Read the current build script first. Insert externals in the correct position relative to other esbuild flags. |
235
+ | S-8 | No rate limit backpressure signal to the user. When rate-limited, the CLI silently sleeps. For a large index (1000+ chunks, 20+ batches), the user sees no output for long periods and may assume it's hung. | Log rate limit delays: `"[nomos:search:warn] Rate limited. Waiting {N}ms before next batch..."` |
236
+
237
+ ---
238
+
239
+ ## 7. AUDIT SUMMARY
240
+
241
+ The plan is architecturally sound in its decomposition — the module boundaries, type definitions, and dependency graph are well-structured. The risk register shows awareness of real failure modes. The idempotency checks per-step are a notable positive.
242
+
243
+ However, the plan fails to account for the **composition** of its own components under failure. Individual modules are designed with care; the pipeline that connects them is not. The gap between `reset()` and `upsert()`, the gap between upsert and metadata write, the gap between embedding failure and incremental recovery — these interstitial failures are where production systems die.
244
+
245
+ The plan is one good afternoon of mitigations away from being production-ready. It is not there yet.
246
+
247
+ ---
248
+
249
+ *End of Adversarial Audit. All findings are technical in nature and assume worst-case operational conditions.*