feat(semantic): [merge candidate build] FTS5 index and search tools, provider-aware typed embeddings, reranking, diagnostics, and eval harness#87
Conversation
…iority ordering, backoff - CancellationToken (Arc<AtomicU64> generation counter) for cooperative build cancellation on reconfigure - Cancel old semantic index builds instead of detaching when config changes - Priority file ordering: README/docs first, then core source, then tests, then rest - Embedding backoff: exponential retry with jitter for remote provider rate limits - SemanticIndexStatus::Partial variant with completeness percentage for partial builds - Search reports partial index state during cold start - Phase-boundary cancellation checks between model init, disk read, incremental refresh, and full rebuild
Add Perplexity backend with InputMode::DocumentChunks support for contextualized embedding where chunks carry document-level context. - SemanticBackend::Perplexity variant with config, profile, engine - DocumentChunks/PerDocumentChunks/DocumentEmbeddings structs - embed_document_chunks() routes Perplexity to grouped embedding API - build_with_progress_contextualized() groups chunks by document - Wire configure.rs to branch on input_mode: DocumentChunks - SemanticEmbeddingModel::input_mode() public accessor - EmbeddingModelProfile with contextualized_supported guard - Response validation: index continuity, missing documents, dimension
…to trait-backed module Bead: aft-t6p.12 Extracts Vec<EmbeddingEntry> storage and search from SemanticIndexSnapshot into a VectorStore trait with FlatF32VectorStore implementation. This decouples the storage layer from the lifecycle logic and prepares for alternative backends (binary Hamming, approximate ANN). Key changes: - vector_store.rs: VectorStore trait + ScoredChunk/PruneStats types - FlatF32VectorStore: flat scan with cosine similarity (preserves existing behaviour exactly) - FlatBinaryHammingVectorStore: forward-looking Hamming-search impl - SemanticIndexSnapshot delegates search/len/prune/entries to store - Fixed dimension-sync bug where set_dimension updated the snapshot dimension but not the store dimension, causing search to return 0 - EmbeddingEntry and IndexedFileMetadata made pub for trait compatibility
On Windows, use copyFileSync for the binary replacement (which overwrites the target — renameSync fails with EEXIST). If it fails, the original binary at binaryPath is preserved. The temp file cleanup is now wrapped in its own try/catch so a cleanup failure does NOT propagate as a download failure — the binary was already successfully placed at binaryPath. Addresses PR cortexkit#69 cubic review finding P2.
Implement bead aft-t6p.24: file identity manifest + vector ownership records. Changes: - **FileRecord struct**: identity record with content_hash, size_bytes, mtime, language, document_kind, inclusion_policy_hash, indexed_at - **file_manifest on SemanticIndexSnapshot**: HashMap<PathBuf, FileRecord> tracking which files produced which vectors, enabling precise stale-vector pruning when files are edited, deleted, or excluded - **V8 serialization format**: extends V7 with per-entry chunk_hash (after each vector) and file manifest block (after all entry vectors). Full backward compatibility with V1-V7 reads. - **chunk_hash on EmbeddingEntry**: deterministic hash of chunk content fields for tracing which version of a chunk produced a stored vector - **compute_chunk_hash**: blake3-based deterministic hash - **build_manifest_from_store helper**: populates file_manifest from store's file_metadata, called in all builder functions (build_from_chunks, build_with_progress_contextualized, refresh_stale_files) and from_bytes for V1-V7 cache migration - **next_chunk_id, fingerprint_string**: forward-looking fields on snapshot for future unique ID assignment and fingerprint tracking
…rmalization, and model profiles Adds aft-t6p.20 (Typed embedding vector representation + storage-strategy resolution): - TypedVector (source-side) and StoredVector (persisted) enums with DenseF32, DenseInt8, BinaryPacked, and Quantized variants - StorageStrategy (NativeF32, DecodeNormalizeF32, BinaryPacked) - VectorKind enum for runtime type tagging - DistanceMetric (Cosine, DotProduct, Euclidean, Hamming) - NormalizationPolicy (AlreadyNormalized, NormalizeOnInsertQuery, NotApplicable) - EmbeddingModelProfile fields: source_vector_kind, stored_vector_kind, metric, normalization - convert_vector() / validate_compatible() on EmbeddingModelProfile - blake3 dependency for chunk hashing
… + dummy base_url for Perplexity profile test Two fixes for `fingerprint_invalidation_tests`: - Mock HTTP server now lowercases header names before matching Content-Length (reqwest/hyper sends lowercase `content-length:`). - `base64_int8_profile_from_config_selects_correctly` test provides a dummy `base_url` for the Perplexity backend (required by `from_config`). Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
- Add StorageStrategy::BinaryPacked variant for packed-bit vector storage - Add EmbeddingModelProfile::perplexity_binary() with BinaryPacked → Hamming path - Wire from_config to select perplexity_binary profile when Base64Binary encoding - Implement parse_embedding_value for Base64Binary (decode → 0.0/1.0 f32 vec) - Implement into_stored for TypedVector::BinaryPacked (requires BinaryPacked strategy) - Update validate_config and validate_compatible to accept Base64Binary+BinaryPacked - Replace old "not yet supported" test with parse_embedding_value_base64_binary_succeeds - 886/893 tests pass (7 pre-existing Docker failures) Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Add semantic_diagnostics module with SearchDiagnostics, SearchPipelineType, SearchWarning, SearchMetricsCollector, PhaseTimer, score_statistics, top1_margin. Instrument handle_semantic_search with per-phase timing and warning collection. Wire SearchMetricsCollector into AppContext. 17 new tests, 902/910 lib tests pass (8 pre-existing Docker failures). Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
- Add SemanticDiagnosticsLogger with file append, rotation (50 MB), and retention cleanup (file-deletion based on mtime) - Add SearchDiagnosticsEvent struct for JSONL serialization with raw_query redaction (opt-in via include_raw_queries) and snippet placeholder (include_snippets) - Add config fields: jsonl_logging, jsonl_path, include_raw_queries, include_snippets, retention_days to SemanticBackendConfig - Add lazy-init diagnostics_logger on AppContext with resolve_diagnostics_log_path helper (env var → project root → ~/.cache) - Wire JSONL record into handle_semantic_search diagnostics block - 4 new tests: raw query redaction, raw query inclusion, disk write verification, missing-file recovery - 907/914 lib tests pass (7 pre-existing Docker failures) Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
…rch output Add DiagnosticsOutputMode enum (Off/Minimal/Verbose) and output_mode field to SemanticBackendConfig. Implement format_diagnostics_prefix() for Minimal (warnings only) and Verbose (scores + latency + warnings) output modes. Wire into handle_semantic_search response text. 4 new tests, 25 diagnostics tests total. 910/918 lib tests pass (8 pre-existing Docker failures). Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Add optional reranking via OpenAI-compatible chat endpoint. When enabled, aft_search overfetches candidates, sends them to a reranker model, and re-sorts by relevance. Falls back gracefully on any error. - Add RerankConfig fields to SemanticBackendConfig (rerank_enabled, rerank_model, rerank_base_url, rerank_api_key_env, rerank_timeout_ms, rerank_max_candidates) - Create semantic_rerank.rs with RerankerClient, RerankOutcome enum, and rerank_candidates function - Add RerankerFailure warning variant to SearchWarning - Wire reranking into handle_semantic_search (overfetch → rerank → re-sort) - Add rerank_latency_ms to SearchDiagnostics and SearchDiagnosticsEvent - Include rerank latency in verbose diagnostics output - 6 unit tests for reranker parsing, skip conditions, and failure handling All 25 diagnostics + 6 reranker tests pass. 917/924 total tests pass (7 pre-existing Docker infrastructure failures).
Add 40+ unit tests to fingerprint_invalidation_tests covering: - SemanticBackendConfig deserialization (minimal, all-fields, defaults) - EmbeddingModelProfile validation for all encoding types - TypedVector conversion and StoredVector roundtrip - convert_vector and validate_compatible rejection paths - Distance metric auto-resolution for f32/int8/binary - base64_int8 signed int8 decode correctness - Template hashing, enum roundtrips, resolve helpers Minor: add #[derive(Debug)] to StoredVector for test ergonomics. Closes aft-t6p.6.1
Add 6 new tests to fingerprint_invalidation_tests covering: - file_policy_hash mismatch triggers rebuild - docs_chunker_version mismatch triggers rebuild - multi-field changes still trigger rebuild - rebuild+query_prompt: rebuild wins - only query_prompt change: ClearQueryCache - non-fingerprint field changes: NoChange Total: 22 fingerprint tests. Closes aft-t6p.6.2
Add 29 tests covering: - is_generated_file: protobuf, minified, dist, build, generated, dart - is_doc_extension and is_config_extension validation - classify_semantic_file for code/doc/config - collect_docs_chunks markdown heading splitting - SemanticFilePolicy defaults and builtin globs - FileRecord field population - build_manifest_from_store construction and cleanup Closes aft-t6p.6.3
… tests Add 23 tests covering: - FlatF32VectorStore: search, empty, dimension mismatch, CRUD, prune, stats - FlatBinaryHammingVectorStore: search, ranking, prune, delete, stats - hamming_distance and popcount64 correctness - Binary decode: byte-aligned, non-byte-aligned, padding, error Closes aft-t6p.6.4
Add 8 tests covering: - SemanticIndexLifecycle: cold start, set/get, failed+error, all variants - SemanticIndexSnapshot: search ranking, immutability after clone - VectorStore: prune_stale_vectors, prune_orphans Closes aft-t6p.6.5
Add 10 tests covering: - HybridRerank pipeline type display - Metrics collector: window size 1, cache hit rate, zero result rate, low confidence rate, latency percentiles - Diagnostics output mode defaults - Warning formatting: minimal (all variants, verifies suppressed), verbose (all 9 variants) - SearchWarning serde roundtrip for all 8 variants Closes aft-t6p.6.6
Add 4 tests covering: - Concurrent snapshot clones produce independent results - Concurrent read threads see identical data via Arc - Mutex contention across 10 threads does not deadlock - Arc strong_count tracks clone/drop correctly Closes aft-t6p.6.7
Add 6 tests covering: - Trust file atomic write (no tmp files left behind) - Multiple projects trusted independently - Untrust is idempotent - Trust state survives reload (serde roundtrip) - Nonexistent project path is untrusted (fail-closed) Closes aft-t6p.6.8
The validate_compatible_rejects_binary_stored_with_cosine_metric test was missing source_vector_kind: BinaryPacked, causing the first match block to fail with 'unsupported source→stored vector conversion' instead of reaching the metric compatibility check.
Add local retrieval evaluation harness for measuring semantic search quality. New files: - crates/aft/src/semantic_eval.rs — pure-logic module with: - EvalCase, EvalResult, EvalSummary structs - JSONL parser (tolerates blank lines and comments) - path_matches() — cross-platform suffix matching - symbol_matches() — Rust/other-language symbol normalization - score_case() — per-case recall@k and MRR scoring - score_suite() — aggregate metrics across a suite - crates/aft/src/commands/semantic_eval.rs — handler wiring: - Reads .aft/semantic-eval.jsonl, returns EvalSummary as JSON - Supports top_k override and include_per_case toggle - Returns tri-state response per AFT honest reporting convention Wiring: - crates/aft/src/lib.rs: pub mod semantic_eval - crates/aft/src/commands/mod.rs: pub mod semantic_eval - crates/aft/src/main.rs: dispatch semantic_eval command Tests: 44 tests passing (parser, matcher, scorer, handler)
Add semantic_doctor command that produces a SemanticHealthReport gathering: - Config summary (backend, model, dimensions, metric, prompts, rerank) - Index state (lifecycle, entry count, dimension, fingerprint freshness) - Search quality metrics (p50/p95 latency, zero-result/low-confidence rates) - Provider connectivity (optional probe) - Active warnings and actionable suggestions New files: - crates/aft/src/semantic_doctor.rs — HealthStatus, ConfigSummary, IndexSummary, MetricsSummary, ProviderSummary, Suggestion, SemanticHealthReport structs with Serialize and Display impls - crates/aft/src/commands/semantic_doctor.rs — command handler with optional probe_provider param, suggestion generation for disabled/ building/failed/ready states, 7 handler tests + 6 model tests Wiring: - crates/aft/src/lib.rs: pub mod semantic_doctor - crates/aft/src/commands/mod.rs: pub mod semantic_doctor - crates/aft/src/main.rs: dispatch "semantic_doctor" command Also: fix semantic_eval temp directory race condition (atomic counter). Tests: 14 semantic_doctor + 44 semantic_eval passing, check+clippy+fmt clean.
Extend the semantic_index_info section of the status command to include: - Search quality metrics (total_queries, p50/p95 latency, zero_result_rate, low_confidence_rate, embedding_failure_rate, lexical_failure_rate) - Rerank status (rerank_enabled, rerank_model) - Diagnostics state (diagnostics_enabled, prompt_active) The TUI/status surfaces can now show pipeline health without a separate semantic_doctor call. Metrics are zero when no queries have been recorded. Tests: status + semantic_doctor tests passing, check+clippy+fmt clean.
- Add 3 new tests: markdown-fence parsing, snippet truncation, max_candidates limit - Fix missing-ID append: semantic_search now appends missing indices in original order - Add max_candidate_chars config field (default 2500) to SemanticBackendConfig - Use config.rerank_max_candidate_chars instead of hardcoded 200 in reranker - Update all test configs with new field Bead: aft-t6p.2.1
There was a problem hiding this comment.
4 issues found across 107 files
Note: This PR contains a large number of files. cubic only reviews up to 100 files per PR, so some files may not have been reviewed. cubic prioritizes the most important files to review.
On a pro plan you can use ultrareview for larger PRs.
Re-trigger cubic
Remove .beads/, .qartez/, .claude/, .omo/, .kiro/, .lean-ctx/ from the branch. These are local agent working directories that should not be distributed. Add them to .gitignore to prevent future accidents. Addresses cubic review comments on PR cortexkit#87.
There was a problem hiding this comment.
1 issue found across 69 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".gitignore">
<violation number="1" location=".gitignore:95">
P2: Inconsistent .gitignore pattern: `omo/` should likely be `.omo/` to match the hidden tooling directory convention used by all other entries in this block.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
Too many files changed for review. ( Bypass the limit by tagging |
… read_searchable_text to avoid reading multi-GB binary files
…ment Resolved 25 conflicting files across a 239/718 commit divergence: Mechanical (unioned both sides): - .gitattributes, .gitignore, release.yml - lib.rs (4 hunks: 20 modules), cli/mod.rs, compress/mod.rs, commands/mod.rs - tests/integration/main.rs (additive module declarations) Config schemas (kept both features): - config.rs: fts5 + backup config fields, max_callgraph_files, tests - opencode-plugin/config.ts: UP z.preprocess + fork fts5 block + safe fields - pi-plugin/config.ts: fts5 + callgraph_store types Architectural (took UP base, fork features to be re-applied): - context.rs: UP App/AppContext refactor (parking_lot/RwLock concurrency) - semantic_index.rs: UP concurrency-modernized skeleton - semantic_search.rs: UP tool_call dispatch - db/mod.rs: UP v4 schema (fork RIL migration to be re-added as v5) - configure.rs: UP callgraph store rewrite (fork fts5 config to be re-added) - grep.rs, glob.rs, status.rs: UP response infrastructure - test files: UP test harness Also fixed: duplicate base64 dependency in Cargo.toml (merge artifact) Known-missing fork features (re-application in progress): - PR cortexkit#87 provider-aware vectors (VectorKind, TypedVector, model2vec) - RI v3.1 commands (aft_orient, aft_impact_delta, aft_context_pack) - FTS5 config parsing in configure.rs - Semantic fields in AppContext (semantic_index, inspect_manager) - RIL schema migration (v5)
…anup - Added max_body_chars, max_body_lines, raw_fts_debug to opencode-plugin fts5 schema - Added same fields to pi-plugin fts5 type definition - Updated dangling spike-output.json references in REPORT.md and spike.ts
- Fixed opencode-plugin config.ts formatting where schema was collapsed onto the line. - Added to in both plugins so project-level config is honored during user/project merge. - Wired through (opencode-plugin) and the configure-time allowlist (pi-plugin/index.ts) so the Rust backend receives the settings. - Added the missing Zod schema to pi-plugin's AftConfigSchema, matching the existing interface and opencode-plugin schema. - Added project-override tests for both plugins.
returns success for zombie entries, so in Docker
containers where PID 1 does not reap orphaned children, callers could wait
forever. Add a /proc/{pid}/stat state check: if the process is a zombie
('Z'), report it as not alive. This fixes the failing nextest
terminate_pgid_kills_term_ignoring_descendant_after_leader_exits test in
the Dockerized check environment.
- Use strict freshness verification in is_file_stale and refresh_stale_files so same-mtime/same-size content edits are detected. - Reuse unchanged chunk vectors during refresh_stale_files to avoid re-embedding line-shifted or partially-edited files. - Handle alias/canonical paths in invalidate_file so deleting a symlink or alias invalidates the underlying semantic entries. - Add Pascal/Delphi extensions (pas, pp, dpr, dpk, lpr) to the semantic indexing policy. - Expose canonicalize_existing_or_deleted_path as pub(crate) so the semantic index can resolve deleted-file aliases consistently.
Gate the per-entry fs::canonicalize fallback in SemanticIndex:: invalidate_file by file name. Stored paths are canonical in practice, so most entries are handled by direct comparison. When an entry might be an alias, we only pay for canonicalization if the base name matches the supplied or canonical target, avoiding O(N) filesystem calls on large indices.
On slow CI (Docker, shared runners), spawning AftProcess + configure + replay can exceed 1 second, causing sleep 1 to finish before the rehydration status check asserts "running". Bump to sleep 10 (10x the original) which keeps the test fast while providing ample CI headroom.
- Add model_cache CLI commands (list/remove/info/check-update) with plugin tools for opencode-plugin and pi-plugin - Add shared repo_id module with path-safety validation (rejects empty components, dot segments, path separators, embedded NUL) - Upgrade hf-hub to 1.0 with unified download_file API - Extract shared HuggingFace repo ID parsing helper - Fix semantic refresh breaker race: remove premature probe consumption from post-event-processing drain path - Fix flaky spawn_detached_survives_parent_restart: sleep 1 -> sleep 10 - Fix semantic index integration tests: canonicalize chunk paths - Fix callgraph_store coverage test flakiness (wall-clock assertions) - Fix lint_tool_schemas doctest (unresolved import, missing Severity) - Apply cargo update to resolve RUSTSEC audit findings - Add AFT storage dirs to degraded grep skip list - Optimize read_searchable_text with size-limit + preview binary check - Update CI validation scripts and zir-aft-check.sh
…idge Extract ~600 lines of duplicated config logic (bash resolver, config migration engine, merge helpers, bridge defaults) from opencode-plugin and pi-plugin into a single shared module in @cortexkit/aft-bridge. - New: packages/aft-bridge/src/config-resolver.ts (759 lines) - Both plugin configs now import shared functions + re-export for BC - Pi-plugin switches from separate TS interfaces to z.infer<> (eliminates interface/schema drift risk) - Added ConfigLogger interface to avoid requiring error method - Add comment-json dependency to aft-bridge - Net reduction: ~1600 lines deleted across both plugins Also: docs/reports/code-review-session-20250725.md — comprehensive review of all changes from the merge session.
list_cached_models() reverse-constructs repo IDs from directory names by replacing -- with /. A manually-created or stale cache directory like "evil" (no slash) would produce a malformed repo_id that passes the cache check but confuses downstream commands that expect valid owner/name format. Add a split_hf_repo_id validation guard inside the loop so entries that don t round-trip through validation are silently skipped.
- Document hardcoded directory filter limitations in degraded grep, pointing users to .gitignore/.aftignore for custom binary directories - Replace #[ignore] with AFT_TEST_ONLINE env-var gate for online model test, keeping it compiled to prevent bit-rot while still skipping by default - Use concrete () => void type for LoggerMockFn to avoid portability hazard with Bun\'s Mock<F> return type across versions
There was a problem hiding this comment.
5 issues found across 10 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="crates/aft/src/local_embed.rs">
<violation number="1">
P2: Test `resolve_model_files_downloads_and_reuses_cache` now silently passes as `ok` without doing any real work when `AFT_TEST_ONLINE` is not set. Previously `#[ignore]` made it explicitly visible as 'ignored' in test output. The `eprintln` skip message is captured by the test framework and invisible without `--nocapture`, so developers running `cargo test` see a passing test that exercised nothing — which is misleading and inflates coverage signal.
Suggestion: keep `#[ignore]` to preserve explicit 'ignored' status, and add the env-var gate as a secondary runtime check for those who use `--ignored` but need to avoid network.</violation>
</file>
<file name="packages/pi-plugin/src/config.ts">
<violation number="1" location="packages/pi-plugin/src/config.ts:379">
P1: A user-level `bash: false` is no longer able to disable the AFT bash surface when a project config is present: the shared merge expands the boolean into an object, and `resolveBashConfig` treats that object as enabled. Preserving an explicit boolean when only one side is configured (especially `false`) would retain the documented disable behavior.</violation>
</file>
<file name="crates/aft/src/model2vec_download.rs">
<violation number="1">
P2: Cache entries containing `--` in a repo component can pass this validation but be listed under a different `repo_id`, making cache output misleading and leaving the encoding ambiguous. An unambiguous cache-key encoding (or an explicit rejection of ambiguous names) would make the round-trip guarantee in this function true.</violation>
</file>
<file name="packages/opencode-plugin/src/config.ts">
<violation number="1" location="packages/opencode-plugin/src/config.ts:22">
P2: OpenCode subagents can no longer opt into background bash: the imported shared resolver defaults to `subagentAware: false`, so `subagent_background` is always undefined and `bash.ts` forces the synchronous path. OpenCode should use a subagent-aware wrapper/call (`resolveBashConfig(config, { subagentAware: true })`) while keeping the Pi resolver default false.</violation>
</file>
<file name="packages/aft-bridge/src/config-resolver.ts">
<violation number="1" location="packages/aft-bridge/src/config-resolver.ts:512">
P2: Configs that already have top-level `bash` lose supported `experimental.bash.long_running_reminder_*` settings during migration. The conflict path could merge those reminder fields into top-level `bash` before deleting the legacy block, matching `resolveBashConfig`'s pre-migration fallback behavior.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| base.experimental, | ||
| override.experimental, | ||
| ) as AftConfig["experimental"]; | ||
| const bash = mergeBashConfig(base.bash, override.bash) as AftConfig["bash"]; |
There was a problem hiding this comment.
P1: A user-level bash: false is no longer able to disable the AFT bash surface when a project config is present: the shared merge expands the boolean into an object, and resolveBashConfig treats that object as enabled. Preserving an explicit boolean when only one side is configured (especially false) would retain the documented disable behavior.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/pi-plugin/src/config.ts, line 379:
<comment>A user-level `bash: false` is no longer able to disable the AFT bash surface when a project config is present: the shared merge expands the boolean into an object, and `resolveBashConfig` treats that object as enabled. Preserving an explicit boolean when only one side is configured (especially `false`) would retain the documented disable behavior.</comment>
<file context>
@@ -1179,22 +370,18 @@ function mergeConfigs(base: AftConfig, override: AftConfig): AftConfig {
+ base.experimental,
+ override.experimental,
+ ) as AftConfig["experimental"];
+ const bash = mergeBashConfig(base.bash, override.bash) as AftConfig["bash"];
+ const inspect = mergeInspectConfig(base.inspect, override.inspect) as AftConfig["inspect"];
const bridge = base.bridge;
</file context>
| @@ -0,0 +1,677 @@ | |||
| //! Model2Vec model download and cache management. | |||
There was a problem hiding this comment.
P2: Cache entries containing -- in a repo component can pass this validation but be listed under a different repo_id, making cache output misleading and leaving the encoding ambiguous. An unambiguous cache-key encoding (or an explicit rejection of ambiguous names) would make the round-trip guarantee in this function true.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/aft/src/model2vec_download.rs, line 265:
<comment>Cache entries containing `--` in a repo component can pass this validation but be listed under a different `repo_id`, making cache output misleading and leaving the encoding ambiguous. An unambiguous cache-key encoding (or an explicit rejection of ambiguous names) would make the round-trip guarantee in this function true.</comment>
<file context>
@@ -253,6 +258,13 @@ pub fn list_cached_models() -> Vec<(String, PathBuf, u64)> {
+ // validation. A manually-created directory like "evil"
+ // (no slash) would pass the cache check but then confuse
+ // downstream commands that expect a valid repo_id.
+ if crate::repo_id::split_hf_repo_id(&name).is_err() {
+ continue;
+ }
</file context>
| migrateAftConfigFile, | ||
| migrateRawConfig, | ||
| type ResolvedBashConfig, | ||
| resolveBashConfig, |
There was a problem hiding this comment.
P2: OpenCode subagents can no longer opt into background bash: the imported shared resolver defaults to subagentAware: false, so subagent_background is always undefined and bash.ts forces the synchronous path. OpenCode should use a subagent-aware wrapper/call (resolveBashConfig(config, { subagentAware: true })) while keeping the Pi resolver default false.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/opencode-plugin/src/config.ts, line 22:
<comment>OpenCode subagents can no longer opt into background bash: the imported shared resolver defaults to `subagentAware: false`, so `subagent_background` is always undefined and `bash.ts` forces the synchronous path. OpenCode should use a subagent-aware wrapper/call (`resolveBashConfig(config, { subagentAware: true })`) while keeping the Pi resolver default false.</comment>
<file context>
@@ -1,11 +1,48 @@
+ migrateAftConfigFile,
+ migrateRawConfig,
+ type ResolvedBashConfig,
+ resolveBashConfig,
+ resolveExperimentalConfigForConfigure,
+ resolveLspConfigForConfigure,
</file context>
|
|
||
| if (Object.hasOwn(rawConfig, "bash")) { | ||
| logger?.warn( | ||
| `Config migration conflict at ${configPath}: experimental.bash dropped because top-level "bash" is already set`, |
There was a problem hiding this comment.
P2: Configs that already have top-level bash lose supported experimental.bash.long_running_reminder_* settings during migration. The conflict path could merge those reminder fields into top-level bash before deleting the legacy block, matching resolveBashConfig's pre-migration fallback behavior.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/aft-bridge/src/config-resolver.ts, line 512:
<comment>Configs that already have top-level `bash` lose supported `experimental.bash.long_running_reminder_*` settings during migration. The conflict path could merge those reminder fields into top-level `bash` before deleting the legacy block, matching `resolveBashConfig`'s pre-migration fallback behavior.</comment>
<file context>
@@ -0,0 +1,764 @@
+
+ if (Object.hasOwn(rawConfig, "bash")) {
+ logger?.warn(
+ `Config migration conflict at ${configPath}: experimental.bash dropped because top-level "bash" is already set`,
+ );
+ } else {
</file context>
- Deduplicate reranker output indices at all 5 return sites using HashSet to prevent duplicate search results from LLM cross-encoder rerankers - Validate --features argument against shell-safe regex to prevent command injection via cargo_features_flag() in zir-aft-check.sh - Save/restore core.autocrlf in zir-aft-check.sh via chained EXIT trap instead of silently mutating the user's repo git config
- Increment suppressed_count in WarningDedup on each suppressed occurrence instead of discarding it, making the field non-dead - Document fork()+setsid() safety assumption in child_registry killpg test, noting single-threaded cargo test guarantee and nextest/multi-threaded runner caveat
…lity Bun's default per-test timeout is 5000ms. In Docker containers, the aft binary cold-start exceeds 5s, causing 78 test timeouts. A root-level bunfig.toml was ineffective because Bun doesn't walk up from subdirectory package dirs to find it. Passing --timeout=30000 directly in each package's test:unit script is the reliable fix.
Review Comment Resolution — 2026-07-25
All 26 outstanding review comments from PR #87 have been addressed. See replies on each thread for details.
Code fixes committed
Already addressed in codebase (no change needed)
Design intent / not actionable
Docker validation