Skip to content

feat(domain): add F3 episodic semantic-memory contract - #216

Merged
KooshaPari merged 2 commits into
mainfrom
feat/forge-f3-semantic-memory-20260830
Aug 31, 2026
Merged

feat(domain): add F3 episodic semantic-memory contract#216
KooshaPari merged 2 commits into
mainfrom
feat/forge-f3-semantic-memory-20260830

Conversation

@KooshaPari

@KooshaPari KooshaPari commented Aug 30, 2026

Copy link
Copy Markdown
Owner

User description

Summary

F3 previously had a research and ADR surface but no provider-agnostic domain contract for semantic memory. This slice adds the deliberately narrow Episodic-only boundary required before any provider, database, network, or prompt integration can be introduced.

It exports validated query and hard-budget types, provenance-bearing records with deterministic ranking, a provider-agnostic SemanticMemoryPort, and an error taxonomy that permits FTS fallback only for provider unavailability. Identity and project-knowledge scopes are explicitly rejected in this slice.

Cargo.lock is included as a pre-existing workspace consistency repair discovered by Cargo: the lockfile lacked the already-declared forge_e2e, forge_sandbox, and helios-bot members and the existing forge_app -> forge_sandbox edge. No F3 dependency was added.

Validation

  • cargo test -p forge_domain semantic_memory --lib --locked (5 passed)
  • cargo test -p forge_domain --lib --locked --quiet (679 passed)
  • cargo clippy -p forge_domain --all-targets --locked -- -D warnings
  • cargo fmt --all -- --check
  • git diff --check

Scope

This is only the domain contract. It intentionally does not add Thegent imports, remote calls, embedding providers, storage/migrations, configuration, or orchestration prompt injection.


CodeAnt-AI Description

Add a workspace-scoped contract for episodic semantic-memory recall

What Changed

  • Adds a provider-independent interface for storing, recalling, and forgetting episodic conversation memories
  • Rejects unsupported identity and project-knowledge memory scopes
  • Keeps memories isolated to their workspace and preserves conversation source details with every result
  • Validates query text, result limits, relevance scores, and recall content budgets before processing
  • Orders recalled memories by relevance with stable tie-breaking
  • Allows FTS fallback only when the semantic-memory provider is unavailable
  • Adds coverage for scope handling, validation, workspace isolation, ranking, provenance, deletion, and fallback errors

Impact

✅ Workspace-isolated memory recall
✅ Bounded prompt context from recalled memories
✅ Stable, provenance-aware search results

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Copilot AI lite review requested due to automatic review settings August 30, 2026 22:23
@codeant-ai

codeant-ai Bot commented Aug 30, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Incremental review completed a9929f2 Aug 31, 2026 · 07:40 07:40
✅ Reviewed your PR c4c7b5c Aug 30, 2026 · 22:23 22:25

@codeant-ai

codeant-ai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@codeant-ai codeant-ai Bot added the size:L label Aug 30, 2026
@mergify mergify Bot added rust labels Aug 30, 2026
@mergify

mergify Bot commented Aug 30, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

Comment on lines +350 to +354
async fn recall(
&self,
query: SemanticMemoryQuery,
budget: SemanticMemoryBudget,
) -> Result<Vec<SemanticMemoryRecord>, SemanticMemoryError>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The validated budget is never applied to returned records, so recall can exceed the documented hard content cap before prompt construction. [incomplete implementation]

Assessment: 🟠 Major · 🔁 Occurrence: Sometimes

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** crates/forge_domain/src/semantic_memory.rs
**Line:** 350:354
**Comment:**
	*Incomplete Implementation: The validated budget is never applied to returned records, so recall can exceed the documented hard content cap before prompt construction.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@codeant-ai

codeant-ai Bot commented Aug 30, 2026

Copy link
Copy Markdown

CodeAnt Nitpicks

1 code suggestion

1. A zero limit is reported as QueryLimitExceeded, whose message says the limit exceeds the maximum, misclassifying this lower-bound input.

Incorrect condition logic · crates/forge_domain/src/semantic_memory.rs:208-212

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c4c7b5c595

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +350 to +354
async fn recall(
&self,
query: SemanticMemoryQuery,
budget: SemanticMemoryBudget,
) -> Result<Vec<SemanticMemoryRecord>, SemanticMemoryError>;

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 Badge Add workspace scope to recall requests

When one semantic-memory backend serves multiple workspaces, this request contains no workspace or conversation filter, so an adapter cannot constrain the provider query before records are retrieved; it must either search globally—risking cross-workspace conversation disclosure—or rely on an undocumented per-workspace port instance. Include the owning WorkspaceId (and any intended conversation boundary) in the recall request so tenant isolation is enforceable.

Useful? React with 👍 / 👎.

#[async_trait]
pub trait SemanticMemoryPort: Send + Sync {
/// Stores one Episodic memory and returns its provider-assigned identifier.
async fn store(&self, record: SemanticMemoryRecord) -> Result<String, SemanticMemoryError>;

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 Badge Separate store inputs from recalled records

When callers store a new episodic memory, they must construct a SemanticMemoryRecord, even though that type requires an adapter-provided relevance score and represents a recalled result; no meaningful score exists before a query, so every caller must fabricate one and may accidentally persist query-specific metadata. Accept a score-free write type here and reserve SemanticMemoryRecord for recall output.

Useful? React with 👍 / 👎.


impl SemanticMemoryProvenance {
/// Creates provenance for a record derived from one conversation.
pub fn new(

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 Badge Document every parameterized public API

This public constructor takes three parameters but omits the required # Arguments section, and the same omission recurs on the other new constructors and port methods. Add parameter documentation to each parameterized public API so the domain contract follows the repository's LLM-oriented documentation requirements.

AGENTS.md reference: AGENTS.md:L113-L117

Useful? React with 👍 / 👎.

Comment on lines +148 to +149
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SemanticMemoryProvenance {

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 Badge Derive configured setters for the new domain structs

The newly introduced domain structs, beginning with SemanticMemoryProvenance, omit derive_setters::Setters and the required into/strip_option configuration. Add the repository-standard setter derivation to the new domain types while preserving constructor validation for constrained fields.

AGENTS.md reference: AGENTS.md:L109-L111

Useful? React with 👍 / 👎.

Comment on lines +23 to +27
let actual = SemanticMemoryScope::try_from(MemoryScope::Identity);
assert_eq!(
actual,
Err(SemanticMemoryError::UnsupportedScope(MemoryScope::Identity))
);

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 Badge Restructure tests into the required three steps

After the first case, this test directly embeds the expected error in the assertion instead of keeping discrete fixture/setup, actual, and handwritten expected steps; similar patterns occur throughout the new test module. Restructure each case using the mandated three-step form so failures and intended outputs remain explicit.

AGENTS.md reference: AGENTS.md:L13-L23

Useful? React with 👍 / 👎.

@@ -0,0 +1,400 @@
#[cfg(test)]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: #[cfg(test)] mod tests is declared before every production item in the file

Every other module in forge_domain puts the test module last (e.g. conversation.rs:310). Here all use declarations, types, the trait and the error enum come after a #[cfg(test)] module, which is exactly the shape clippy's warn-by-default clippy::items_after_test_module lint targets. When the lib is linted as a test target (cargo clippy --workspace --all-targets -- -D warnings) that turns into a hard CI failure, so please confirm CI runs --all-targets and move the module to the bottom of the file, after SemanticMemoryError.

Related nit: use crate::{ConversationId, MemoryScope, WorkspaceId}; (line 5) is redundant — use super::*; (line 7) already pulls those names in from the parent module, so the explicit import only shadows the glob.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

}

#[test]
fn query_rejects_empty_text_excessive_limit_and_non_finite_min_score() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

SUGGESTION: Validation tests miss the boundary cases most likely to regress

Currently uncovered branches: limit == 0 (line 208), whitespace-only query text (" ", the trim() branch), Some(f32::INFINITY)/NEG_INFINITY (only NAN is exercised), SemanticMemoryRecord::try_new rejecting a non-finite score, exact-boundary acceptance for MAX_LIMIT and MAX_BYTES, and the third ranked tiebreaker on provenance.source_key (line 312) which no fixture currently varies. Each is a one-line addition and each maps to a branch that is unverified today.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

fn try_from(scope: MemoryScope) -> Result<Self, Self::Error> {
match scope {
MemoryScope::Episodic => Ok(Self::Episodic),
scope => Err(SemanticMemoryError::UnsupportedScope(scope)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

SUGGESTION: Wildcard arm silently absorbs future MemoryScope variants

MemoryScope is a local enum without #[non_exhaustive], so listing each variant explicitly would make the compiler flag this conversion the moment a scope is added. With the catch-all, a newly added scope silently becomes a runtime UnsupportedScope error instead of a compile-time reminder to revisit the deliberately narrow F3 boundary — the opposite of what an intentionally bounded slice wants.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.


impl SemanticMemoryQuery {
/// Default number of records requested when callers do not need a wider recall.
pub const DEFAULT_LIMIT: usize = 10;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

SUGGESTION: DEFAULT_LIMIT and DEFAULT_BYTES (line 242) are exported but unreachable through any constructor

Nothing uses them and neither type offers a default constructor, so callers are pushed into SemanticMemoryQuery::new(text, SemanticMemoryQuery::DEFAULT_LIMIT, None).unwrap() — an unwrap() on a path that is statically infallible. Consider SemanticMemoryQuery::with_defaults(text) and an infallible impl Default for SemanticMemoryBudget (both constants are in range by construction) so the default path cannot return an error at all.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

if text.trim().is_empty() {
return Err(SemanticMemoryError::EmptyQuery);
}
if limit == 0 || limit > Self::MAX_LIMIT {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: limit == 0 reports QueryLimitExceeded, producing a factually wrong error message

SemanticMemoryQuery::new(text, 0, None) returns QueryLimitExceeded { requested: 0, maximum: 100 }, which renders as semantic-memory query limit 0 exceeds maximum 100. That statement is untrue and will mislead whoever debugs the caller or parses the error. SemanticMemoryBudget already models this correctly with a separate InvalidBudget for zero — mirror it with an InvalidLimit variant and keep QueryLimitExceeded for limit > MAX_LIMIT only. Note no test covers limit == 0 today, so the wrong message is invisible.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

score: f32,
provenance: SemanticMemoryProvenance,
) -> Result<Self, SemanticMemoryError> {
if !score.is_finite() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: try_new validates score finiteness only — key, content size and score magnitude are unchecked

Three gaps in a constructor whose stated job is to be the safe conversion point for untrusted provider responses:

  1. An empty or whitespace key is accepted and then flows into SemanticMemoryPort::forget(&str) and provider identity, while SemanticMemoryQuery rejects blank text for the same reason.
  2. content has no ceiling, so a single record can exceed SemanticMemoryBudget::MAX_BYTES on its own — the budget type exists specifically to bound this.
  3. A "finite" score of 1e30/-1e30 passes and then breaks every min_score comparison and score-based ranking downstream.

Reject blank keys and out-of-range scores here so no adapter has to re-derive the rules.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

async fn store(&self, record: SemanticMemoryRecord) -> Result<String, SemanticMemoryError>;

/// Recalls records matching a validated query.
async fn recall(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: The port contract never states (or enforces) what limit, min_score and budget obligate an implementation to do

recall takes a validated query and a hard budget, yet nothing in the domain truncates to query.limit(), filters by query.min_score(), applies budget.bytes(), or requires the returned Vec to be ranked — SemanticMemoryRecord::ranked is a free-standing helper an adapter can simply forget to call, and the trait docs do not mention it. Every future provider plus the FTS fallback will therefore re-implement these three rules slightly differently, and a single missed budget check means unbounded recalled content entering prompt context, which is the exact failure this budget type was introduced to prevent.

Add a domain-side enforcement helper (e.g. SemanticMemoryBudget::apply(records) that ranks, filters by score, truncates to the limit and cuts content past the byte budget) and state in the trait docs that implementations must return its output.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.


/// Errors produced at the provider-agnostic semantic-memory boundary.
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum SemanticMemoryError {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

SUGGESTION: Consider #[non_exhaustive] on this public error enum

The PR description commits to follow-up slices for providers, transport, storage and configuration, each of which will add variants. Without #[non_exhaustive], any downstream match on SemanticMemoryError in other crates compiles today and breaks on the next variant, turning a purely additive change into a breaking one. Adding it now costs nothing because no external matcher exists yet.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

Unavailable(String),
/// The provider returned a non-success status and body.
#[error("semantic-memory backend returned status {status}: {body}")]
Backend { status: u16, body: String },

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: Raw provider response body is embedded verbatim into a Display error

Backend { status, body } renders the whole provider body into logs and user-facing error chains. Provider error bodies routinely echo request metadata and headers, and for a memory provider the body can also contain the recalled conversation text (user PII) or an echoed auth header. Bound and sanitize before constructing this variant — e.g. store a truncated prefix and document on the variant that adapters must redact credentials — otherwise the first HTTP adapter will pipe upstream payloads straight into tracing output.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

impl SemanticMemoryError {
/// Returns whether this error is eligible for a semantic-to-FTS fallback.
pub fn allows_fts_fallback(&self) -> bool {
matches!(self, Self::Unavailable(_))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: Transient provider failures classified as Backend are not fallback-eligible

allows_fts_fallback matches Unavailable only, but the natural mapping in an HTTP adapter puts 429, 500, 502, 503, 504 and timeouts into Backend { status, .. }. Those are precisely the "provider temporarily unavailable" conditions the FTS fallback exists for, so a 503 will hard-fail recall instead of degrading gracefully — while a permanent 401 and a transient 503 are treated identically. Either classify transient statuses here (e.g. Backend { status, .. } if *status == 429 || *status >= 500) or document on Unavailable/Backend that adapters must map transport errors and 5xx/429 to Unavailable. Nothing in the contract says that today, and the test at line 116 pins only the current stricter behaviour.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Aug 30, 2026

Copy link
Copy Markdown

Code Review Summary

Status: 12 Issues Found | Recommendation: Address before merge — Request Changes

Overview

Severity Count
CRITICAL 0
WARNING 7
SUGGESTION 5

What this PR does

Adds crates/forge_domain/src/semantic_memory.rs (400 lines, under the 500-line cap): an Episodic-only semantic-memory domain contract — SemanticMemoryScope, validated SemanticMemoryQuery, SemanticMemoryBudget, provenance-bearing SemanticMemoryRecord with deterministic ranking, the SemanticMemoryPort trait, and a thiserror error taxonomy with FTS-fallback classification. Wired into the crate via mod/pub use in lib.rs. Cargo.lock gains only workspace path members (forge_e2e, forge_sandbox, helios-bot) and the existing forge_app -> forge_sandbox edge — verified against Cargo.toml members, workspace version 2.13.21, and crates/forge_app/Cargo.toml; no new third-party dependency and no hardcoded secrets.

The design intent is good and the scope discipline is real. The blocking concerns are that the file's organization risks a -D warnings clippy failure, and that the types marketed as the validated boundary leave several validation and enforcement responsibilities to future adapters.

Issue Details (click to expand)

WARNING

File Line Issue
crates/forge_domain/src/semantic_memory.rs 1 #[cfg(test)] mod tests precedes all production items — risks warn-by-default clippy::items_after_test_module failing --all-targets -- -D warnings; inconsistent with every sibling module. Redundant use crate::{...} shadowing use super::*
crates/forge_domain/src/semantic_memory.rs 208 limit == 0 returns QueryLimitExceeded { requested: 0, maximum: 100 } → factually wrong message limit 0 exceeds maximum 100; needs its own variant (budget type already does this)
crates/forge_domain/src/semantic_memory.rs 214 min_score checked for finiteness only; -5.0 / 1e30 accepted, so the threshold silently means "all" or "nothing" at adapter level
crates/forge_domain/src/semantic_memory.rs 291 try_new accepts blank key, unbounded content (can exceed MAX_BYTES alone), and extreme finite scores that break min_score/ranking
crates/forge_domain/src/semantic_memory.rs 350 Port contract never states or enforces limit, min_score, budget or ranking; ranked is opt-in, so a missed budget check silently lets unbounded content into prompt context
crates/forge_domain/src/semantic_memory.rs 389 Backend { status, body } embeds the raw provider body in Display → credential/PII (recalled conversation text) leakage into logs and error chains
crates/forge_domain/src/semantic_memory.rs 398 Only Unavailable is FTS-fallback eligible; 429/5xx/timeouts naturally map to Backend, so a transient 503 hard-fails recall and is treated like a permanent 401

SUGGESTION

File Line Issue
crates/forge_domain/src/semantic_memory.rs 39 Untested branches: limit == 0, whitespace-only text, ±INFINITY, non-finite record score, exact MAX_LIMIT/MAX_BYTES boundaries, source_key tiebreaker
crates/forge_domain/src/semantic_memory.rs 142 Wildcard TryFrom arm hides future MemoryScope variants instead of failing at compile time
crates/forge_domain/src/semantic_memory.rs 191 DEFAULT_LIMIT / DEFAULT_BYTES (242) unreachable through any constructor; forces unwrap() on a statically infallible path
crates/forge_domain/src/semantic_memory.rs 270 No Serialize/Deserialize on record/provenance although nearly all sibling domain types derive serde and the next slice crosses a wire
crates/forge_domain/src/semantic_memory.rs 365 Public error enum lacks #[non_exhaustive]; planned provider/transport/storage variants would be breaking changes
Constraint checklist
  • File size ≤ 500 lines — pass (400)
  • thiserror domain errors, no From impls (per AGENTS.md) — pass
  • Public types implement Debug + Clonepass
  • Rustdoc on all public items — pass
  • No new inter-crate dependency, no new external crate, no secrets — pass
  • Tests co-located with source (AGENTS.md), pretty_assertions, fixture/actual/expected naming — pass (placement at top of file flagged above)
  • derive_setters convention for domain types — not followed, though validated private fields are a defensible deviation here
  • Backwards compatibility — additive only; pub use semantic_memory::* introduces no name collisions
  • cargo clippy --all-targets -- -D warnings, cargo fmt --check, cargo testnot executed (read-only review); the line-1 finding is the specific clippy risk to verify in CI
Files Reviewed (3 files)
  • crates/forge_domain/src/semantic_memory.rs - 12 issues
  • crates/forge_domain/src/lib.rs - 0 issues
  • Cargo.lock - 0 issues (generated; verified as members-only sync, no new third-party dependency)

Recommendation

Request Changes. None of the findings are compilation-breaking, but the line-1 organization issue can fail the zero-warnings gate, and the boundary types should not ship advertising validation guarantees they do not enforce (lines 208, 214, 291, 350) before the first provider adapter is written against them.

Auto-fix: reply @kilocode-bot fix it on any inline comment, or @cursor fix to have Cursor take a pass.

Fix these issues in Kilo Cloud

Previous Review Summaries (2 snapshots, latest commit a9929f2)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit a9929f2)

Status: 12 Issues Found | Recommendation: Address before merge — Request Changes

Overview

Severity Count
CRITICAL 0
WARNING 7
SUGGESTION 5

What this PR does

Adds crates/forge_domain/src/semantic_memory.rs (400 lines, under the 500-line cap): an Episodic-only semantic-memory domain contract — SemanticMemoryScope, validated SemanticMemoryQuery, SemanticMemoryBudget, provenance-bearing SemanticMemoryRecord with deterministic ranking, the SemanticMemoryPort trait, and a thiserror error taxonomy with FTS-fallback classification. Wired into the crate via mod/pub use in lib.rs. Cargo.lock gains only workspace path members (forge_e2e, forge_sandbox, helios-bot) and the existing forge_app -> forge_sandbox edge — verified against Cargo.toml members, workspace version 2.13.21, and crates/forge_app/Cargo.toml; no new third-party dependency and no hardcoded secrets.

The design intent is good and the scope discipline is real. The blocking concerns are that the file's organization risks a -D warnings clippy failure, and that the types marketed as the validated boundary leave several validation and enforcement responsibilities to future adapters.

Issue Details (click to expand)

WARNING

File Line Issue
crates/forge_domain/src/semantic_memory.rs 1 #[cfg(test)] mod tests precedes all production items — risks warn-by-default clippy::items_after_test_module failing --all-targets -- -D warnings; inconsistent with every sibling module. Redundant use crate::{...} shadowing use super::*
crates/forge_domain/src/semantic_memory.rs 208 limit == 0 returns QueryLimitExceeded { requested: 0, maximum: 100 } → factually wrong message limit 0 exceeds maximum 100; needs its own variant (budget type already does this)
crates/forge_domain/src/semantic_memory.rs 214 min_score checked for finiteness only; -5.0 / 1e30 accepted, so the threshold silently means "all" or "nothing" at adapter level
crates/forge_domain/src/semantic_memory.rs 291 try_new accepts blank key, unbounded content (can exceed MAX_BYTES alone), and extreme finite scores that break min_score/ranking
crates/forge_domain/src/semantic_memory.rs 350 Port contract never states or enforces limit, min_score, budget or ranking; ranked is opt-in, so a missed budget check silently lets unbounded content into prompt context
crates/forge_domain/src/semantic_memory.rs 389 Backend { status, body } embeds the raw provider body in Display → credential/PII (recalled conversation text) leakage into logs and error chains
crates/forge_domain/src/semantic_memory.rs 398 Only Unavailable is FTS-fallback eligible; 429/5xx/timeouts naturally map to Backend, so a transient 503 hard-fails recall and is treated like a permanent 401

SUGGESTION

File Line Issue
crates/forge_domain/src/semantic_memory.rs 39 Untested branches: limit == 0, whitespace-only text, ±INFINITY, non-finite record score, exact MAX_LIMIT/MAX_BYTES boundaries, source_key tiebreaker
crates/forge_domain/src/semantic_memory.rs 142 Wildcard TryFrom arm hides future MemoryScope variants instead of failing at compile time
crates/forge_domain/src/semantic_memory.rs 191 DEFAULT_LIMIT / DEFAULT_BYTES (242) unreachable through any constructor; forces unwrap() on a statically infallible path
crates/forge_domain/src/semantic_memory.rs 270 No Serialize/Deserialize on record/provenance although nearly all sibling domain types derive serde and the next slice crosses a wire
crates/forge_domain/src/semantic_memory.rs 365 Public error enum lacks #[non_exhaustive]; planned provider/transport/storage variants would be breaking changes
Constraint checklist
  • File size ≤ 500 lines — pass (400)
  • thiserror domain errors, no From impls (per AGENTS.md) — pass
  • Public types implement Debug + Clonepass
  • Rustdoc on all public items — pass
  • No new inter-crate dependency, no new external crate, no secrets — pass
  • Tests co-located with source (AGENTS.md), pretty_assertions, fixture/actual/expected naming — pass (placement at top of file flagged above)
  • derive_setters convention for domain types — not followed, though validated private fields are a defensible deviation here
  • Backwards compatibility — additive only; pub use semantic_memory::* introduces no name collisions
  • cargo clippy --all-targets -- -D warnings, cargo fmt --check, cargo testnot executed (read-only review); the line-1 finding is the specific clippy risk to verify in CI
Files Reviewed (3 files)
  • crates/forge_domain/src/semantic_memory.rs - 12 issues
  • crates/forge_domain/src/lib.rs - 0 issues
  • Cargo.lock - 0 issues (generated; verified as members-only sync, no new third-party dependency)

Recommendation

Request Changes. None of the findings are compilation-breaking, but the line-1 organization issue can fail the zero-warnings gate, and the boundary types should not ship advertising validation guarantees they do not enforce (lines 208, 214, 291, 350) before the first provider adapter is written against them.

Auto-fix: reply @kilocode-bot fix it on any inline comment, or @cursor fix to have Cursor take a pass.

Fix these issues in Kilo Cloud

Previous review (commit c4c7b5c)

Status: 12 Issues Found | Recommendation: Address before merge — Request Changes

Overview

Severity Count
CRITICAL 0
WARNING 7
SUGGESTION 5

What this PR does

Adds crates/forge_domain/src/semantic_memory.rs (400 lines, under the 500-line cap): an Episodic-only semantic-memory domain contract — SemanticMemoryScope, validated SemanticMemoryQuery, SemanticMemoryBudget, provenance-bearing SemanticMemoryRecord with deterministic ranking, the SemanticMemoryPort trait, and a thiserror error taxonomy with FTS-fallback classification. Wired into the crate via mod/pub use in lib.rs. Cargo.lock gains only workspace path members (forge_e2e, forge_sandbox, helios-bot) and the existing forge_app -> forge_sandbox edge — verified against Cargo.toml members, workspace version 2.13.21, and crates/forge_app/Cargo.toml; no new third-party dependency and no hardcoded secrets.

The design intent is good and the scope discipline is real. The blocking concerns are that the file's organization risks a -D warnings clippy failure, and that the types marketed as the validated boundary leave several validation and enforcement responsibilities to future adapters.

Issue Details (click to expand)

WARNING

File Line Issue
crates/forge_domain/src/semantic_memory.rs 1 #[cfg(test)] mod tests precedes all production items — risks warn-by-default clippy::items_after_test_module failing --all-targets -- -D warnings; inconsistent with every sibling module. Redundant use crate::{...} shadowing use super::*
crates/forge_domain/src/semantic_memory.rs 208 limit == 0 returns QueryLimitExceeded { requested: 0, maximum: 100 } → factually wrong message limit 0 exceeds maximum 100; needs its own variant (budget type already does this)
crates/forge_domain/src/semantic_memory.rs 214 min_score checked for finiteness only; -5.0 / 1e30 accepted, so the threshold silently means "all" or "nothing" at adapter level
crates/forge_domain/src/semantic_memory.rs 291 try_new accepts blank key, unbounded content (can exceed MAX_BYTES alone), and extreme finite scores that break min_score/ranking
crates/forge_domain/src/semantic_memory.rs 350 Port contract never states or enforces limit, min_score, budget or ranking; ranked is opt-in, so a missed budget check silently lets unbounded content into prompt context
crates/forge_domain/src/semantic_memory.rs 389 Backend { status, body } embeds the raw provider body in Display → credential/PII (recalled conversation text) leakage into logs and error chains
crates/forge_domain/src/semantic_memory.rs 398 Only Unavailable is FTS-fallback eligible; 429/5xx/timeouts naturally map to Backend, so a transient 503 hard-fails recall and is treated like a permanent 401

SUGGESTION

File Line Issue
crates/forge_domain/src/semantic_memory.rs 39 Untested branches: limit == 0, whitespace-only text, ±INFINITY, non-finite record score, exact MAX_LIMIT/MAX_BYTES boundaries, source_key tiebreaker
crates/forge_domain/src/semantic_memory.rs 142 Wildcard TryFrom arm hides future MemoryScope variants instead of failing at compile time
crates/forge_domain/src/semantic_memory.rs 191 DEFAULT_LIMIT / DEFAULT_BYTES (242) unreachable through any constructor; forces unwrap() on a statically infallible path
crates/forge_domain/src/semantic_memory.rs 270 No Serialize/Deserialize on record/provenance although nearly all sibling domain types derive serde and the next slice crosses a wire
crates/forge_domain/src/semantic_memory.rs 365 Public error enum lacks #[non_exhaustive]; planned provider/transport/storage variants would be breaking changes
Constraint checklist
  • File size ≤ 500 lines — pass (400)
  • thiserror domain errors, no From impls (per AGENTS.md) — pass
  • Public types implement Debug + Clonepass
  • Rustdoc on all public items — pass
  • No new inter-crate dependency, no new external crate, no secrets — pass
  • Tests co-located with source (AGENTS.md), pretty_assertions, fixture/actual/expected naming — pass (placement at top of file flagged above)
  • derive_setters convention for domain types — not followed, though validated private fields are a defensible deviation here
  • Backwards compatibility — additive only; pub use semantic_memory::* introduces no name collisions
  • cargo clippy --all-targets -- -D warnings, cargo fmt --check, cargo testnot executed (read-only review); the line-1 finding is the specific clippy risk to verify in CI
Files Reviewed (3 files)
  • crates/forge_domain/src/semantic_memory.rs - 12 issues
  • crates/forge_domain/src/lib.rs - 0 issues
  • Cargo.lock - 0 issues (generated; verified as members-only sync, no new third-party dependency)

Recommendation

Request Changes. None of the findings are compilation-breaking, but the line-1 organization issue can fail the zero-warnings gate, and the boundary types should not ship advertising validation guarantees they do not enforce (lines 208, 214, 291, 350) before the first provider adapter is written against them.

Auto-fix: reply @kilocode-bot fix it on any inline comment, or @cursor fix to have Cursor take a pass.

Fix these issues in Kilo Cloud


Reviewed by free · Input: 40.7K · Output: 11.3K · Cached: 123K

@socket-security

socket-security Bot commented Aug 30, 2026

Copy link
Copy Markdown

Dependency limit exceeded — report not shown.

This pull request scan exceeded the 10,000-dependency limit applied to this scan, so the results are incomplete and may be inaccurate. To avoid reporting false positives, Socket has not posted a report.

Upgrade your plan to raise the dependency limit and get complete reports, or view the partial scan in the dashboard.

Socket is always free for open source. If this is a non-commercial open source project, contact us to request a free Team account.

@github-actions github-actions Bot removed go labels Aug 31, 2026
@mergify mergify Bot added rust labels Aug 31, 2026
@codeant-ai codeant-ai Bot added the size:XL label Aug 31, 2026
KooshaPari and others added 2 commits August 31, 2026 01:30
Co-Authored-By: ForgeCode <noreply@forgecode.dev>
Co-Authored-By: ForgeCode <noreply@forgecode.dev>
@KooshaPari
KooshaPari force-pushed the feat/forge-f3-semantic-memory-20260830 branch from a9929f2 to a513985 Compare August 31, 2026 08:31
@mergify mergify Bot added rust labels Aug 31, 2026
@KooshaPari
KooshaPari merged commit c38aa73 into main Aug 31, 2026
32 of 33 checks passed
@KooshaPari
KooshaPari deleted the feat/forge-f3-semantic-memory-20260830 branch August 31, 2026 09:03
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.

2 participants