Skip to content

feat(semantic): [merge candidate build] FTS5 index and search tools, provider-aware typed embeddings, reranking, diagnostics, and eval harness#87

Open
Zireael wants to merge 258 commits into
cortexkit:mainfrom
Zireael:semantic-search-enhancement
Open

Conversation

@Zireael

@Zireael Zireael commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

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

Commit Scope
53137af Fork-specific housekeeping (degraded-grep docs, test env gate, LoggerMockFn type fix)
13d1309 P1: Reranker index dedup at 5 return sites, shell injection prevention in zir-aft-check.sh, autocrlf save/restore with chained trap
ad55bcf P2: Increment suppressed_count in WarningDedup, fork safety comment in child_registry test
345498b Fix missing mut on indices declaration
4bf6701 Remove unused stripJsoncSymbols import

Already addressed in codebase (no change needed)

ID File Issue Resolution
3343597517 .gitignore Inconsistent omo/ pattern Already .omo/
3343613914 semantic_rerank.rs Markdown fence stripping strip_markdown_fences called in production
3343666968 config.ts Missing rerank fields All fields declared in schema
3343909788 config.ts Enum backwards compat Current values correct
3357767727 configure.rs SSRF on rerank_base_url validate_base_url_no_ssrf called
3359137353 configure.rs jsonl_path validation normalize_absolute_path + ParentDir check
3359137362 configure.rs u64→u32 lossy cast Uses u32::try_from
3370722719 paths.ts Migration drops state repairRootScopedStorageFile handles it
3370722720 child_registry.rs /proc/stat parsing Uses ps, not /proc
3378028776 semantic_eval.rs Per-case top_k ignored case.top_k.unwrap_or(params.top_k) used

Design intent / not actionable

ID File Issue Rationale
3343667094 semantic_search.rs Index status overwrite status vs semantic_status intentionally separate
3370722725 semantic_search.rs Lexical ordering Design-intent clamped scores
3370733787 semantic_search.rs Reranker warning gating diagnostics_enabled vs output_mode serve different purposes
3370722736 helpers.rs panic! in tests No skip-mechanism panic found
3378028773 configure.rs Sensitive logging Only logs placeholder name, never template content

Docker validation

  • cargo fmt ✅ | cargo check ✅ | cargo clippy ✅ | cargo nextest ✅

Zireael and others added 26 commits May 25, 2026 23:27
…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

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread .beads/README.md Outdated
Comment thread .beads/config.yaml Outdated
Comment thread .claude/settings.json Outdated
Comment thread .qartez/acks/5813b13fa433d553 Outdated
@Zireael Zireael changed the title feat(semantic): provider-aware typed embeddings, reranking, diagnostics, and eval harness feat(semantic): [alpha build] provider-aware typed embeddings, reranking, diagnostics, and eval harness Jun 2, 2026
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.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread .gitignore Outdated
@greptile-apps

greptile-apps Bot commented Jun 21, 2026

Copy link
Copy Markdown

Too many files changed for review. (286 files found, 100 file limit)

Bypass the limit by tagging @greptile-apps to review.

Zireael and others added 18 commits June 22, 2026 19:34
… 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

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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"];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>

S added 6 commits July 25, 2026 11:05
- 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant