fix(adaptive): reuse stable ACG scaffolds - #481
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughACG prompt IR now includes canonicalized structured output. Learning and profile keys incorporate scaffold and response-format fingerprints. Stability results persist dominant prefix fingerprints, and intent construction validates live fingerprints before reuse. Tests cover key bucketing, persistence, serialization, and mismatch rejection. ChangesACG scaffold fingerprinting
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant AnnotatedLlmRequest
participant build_prompt_ir
participant AcgLearner
participant RedisBackend
participant build_intent_bundle
AnnotatedLlmRequest->>build_prompt_ir: messages and response_format
build_prompt_ir-->>AcgLearner: PromptIR and structured_output_schema_id
AcgLearner->>AcgLearner: analyze stability and derive prefix fingerprint
AcgLearner->>RedisBackend: persist observations and stability
RedisBackend-->>build_intent_bundle: stored stability fingerprint
build_intent_bundle->>build_intent_bundle: compare live and stored fingerprints
build_intent_bundle-->>AnnotatedLlmRequest: intent bundle or skipped result
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/adaptive/src/acg_profile.rs`:
- Around line 101-110: In the response_format_hash construction within the
profile-building logic, remove the unreachable has_stable_scaffold conditional
and short_hash call. Map response_format_fingerprint directly to an owned string
so the full fingerprint is always preserved, while keeping the existing optional
behavior unchanged.
In `@crates/adaptive/src/acg/stability.rs`:
- Around line 165-178: Update the fingerprint construction around
request_fingerprint so a deeper prefix (prefix_length > scaffold_length) returns
None when observation.source_request_hash is absent, rather than falling back to
"stable-scaffold"; retain the stable fallback for non-deeper prefixes. Add a
regression test covering a deeper prefix without source_request_hash and
asserting no fingerprint is produced.
In `@crates/adaptive/tests/integration/redis_tests.rs`:
- Around line 531-543: Update the restart assertions in the Redis integration
test to derive the scaffold-specific learning key from the request used by
process_run, then pass that key to restarted.load_observations and
restarted.load_stability. Keep the existing count and fingerprint assertions,
ensuring they validate the scaffold profile record rather than the plain
agent_id aggregate.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: e2272280-9799-46b2-baf1-c68bd359d9c6
📒 Files selected for processing (23)
crates/adaptive/src/acg/ir_builder.rscrates/adaptive/src/acg/stability.rscrates/adaptive/src/acg_component.rscrates/adaptive/src/acg_learner.rscrates/adaptive/src/acg_profile.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/python/tests/coverage/py_storage_coverage_tests.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (15)
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node workWhen changing the core Rust runtime or Rust-facing API surface, format Rust code with
cargo fmt(rustfmt defaults), keepcargo clippy -- -D warningsclean, and satisfycargo deny checkperdeny.toml.
**/*.rs: If any Rust code changed, always runjust test-rust.
If any Rust code changed, also runcargo fmt --all.
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings.
For Rust changes headed for review, runcargo fmt --allandcargo clippy --workspace --all-targets -- -D warningseven if relying on pre-commit.
Files:
crates/adaptive/tests/unit/intercepts_tests.rscrates/python/tests/coverage/py_storage_coverage_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/src/acg/stability.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rs
{crates/core,crates/adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
Changes to
crates/coreorcrates/adaptivemust run the full language matrix
Files:
crates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/src/acg/stability.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rs
**/*.{rs,py}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions in Rust and Python: use
snake_case.
Files:
crates/adaptive/tests/unit/intercepts_tests.rscrates/python/tests/coverage/py_storage_coverage_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/src/acg/stability.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rs
**/*.{rs,py,js,mjs,cjs,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{rs,py,js,mjs,cjs,ts,tsx}: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths, and keep errors explicit and binding-appropriate at the wrapper layer.
Keep async behavior on the existing tokio-based model; bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
Files:
crates/adaptive/tests/unit/intercepts_tests.rscrates/python/tests/coverage/py_storage_coverage_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/src/acg/stability.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rs
**/*.{rs,py,go,js,ts,c,h}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Use language-appropriate naming conventions: Rust
snake_case, C FFI exports prefixednemo_relay_, GoPascalCase, Node.jscamelCase, and Pythonsnake_case.
Files:
crates/adaptive/tests/unit/intercepts_tests.rscrates/python/tests/coverage/py_storage_coverage_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/src/acg/stability.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rs
**/*.{rs,go,js,ts}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Add the SPDX license header to all Rust, Go, JavaScript, and TypeScript source files using the corresponding
//comment form.
Files:
crates/adaptive/tests/unit/intercepts_tests.rscrates/python/tests/coverage/py_storage_coverage_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/src/acg/stability.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rs
crates/adaptive/**
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Keep
crates/adaptivealigned with the canonical adaptive config schema, built-in section helpers, plugin lifecycle, and validation/report behavior.
Files:
crates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/src/acg/stability.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rs
**/*
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*: Format changed files with the language-native formatter before the final lint/test pass.
If dynamic plugin behavior changed, usemaintain-dynamic-pluginsand include the native SDK, worker protocol, Python SDK, docs, packaging, and Codecov surfaces in the validation plan.
If code changes alter APIs, bindings, commands, paths, packaging behavior, observability/adaptive semantics, or documented best practices, update any dependent maintainer or consumer skills in the same branch.
During iteration, preferuv run pre-commit run --files <changed files...>.
Before review or handoff, runuv run pre-commit run --all-files.
Files:
crates/adaptive/tests/unit/intercepts_tests.rscrates/python/tests/coverage/py_storage_coverage_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/src/acg/stability.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rs
crates/{core,adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/coreorcrates/adaptivechanged, run the full validation matrix across Rust, Python, Go, and Node.js.
Files:
crates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/src/acg/stability.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rs
**/*.{rs,py,go,js,ts}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If a language surface changed, always run that language's test target even when Rust core did not change.
Files:
crates/adaptive/tests/unit/intercepts_tests.rscrates/python/tests/coverage/py_storage_coverage_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/src/acg/stability.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rs
**/*.{rs,py,js,ts,tsx,go,java,kt,swift}
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
Add tests covering registration and duplicate names, deregistration and missing names, priority ordering, callback failure policy, scope-local inheritance and cleanup, event payload semantics, immutable mark and scope fields, and parity across affected bindings.
Files:
crates/adaptive/tests/unit/intercepts_tests.rscrates/python/tests/coverage/py_storage_coverage_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/src/acg/stability.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rs
crates/{core,adaptive}/**/*.rs
⚙️ CodeRabbit configuration file
crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.
Files:
crates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/src/acg/stability.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.
Files:
crates/adaptive/tests/unit/intercepts_tests.rscrates/python/tests/coverage/py_storage_coverage_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rs
crates/{python,ffi,node}/**/*
⚙️ CodeRabbit configuration file
crates/{python,ffi,node}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.
Files:
crates/python/tests/coverage/py_storage_coverage_tests.rs
{crates/**/src/**/*.rs,python/**/*.py}
📄 CodeRabbit inference engine (.agents/skills/maintain-dynamic-plugins/SKILL.md)
Do not add tests under
src; Rust tests belong in cratetests/trees, and Python SDK tests belong underpython/tests.
Files:
crates/adaptive/src/acg_learner.rscrates/adaptive/src/acg_component.rscrates/adaptive/src/acg/stability.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg/ir_builder.rs
🔇 Additional comments (22)
crates/adaptive/src/acg/ir_builder.rs (1)
35-83: LGTM!Also applies to: 263-284
crates/adaptive/src/acg_profile.rs (1)
33-46: LGTM!Also applies to: 71-100, 225-232
crates/adaptive/tests/unit/acg/ir_builder_tests.rs (1)
191-251: LGTM!crates/adaptive/tests/unit/acg_profile_tests.rs (1)
49-145: LGTM!crates/adaptive/tests/unit/runtime_tests.rs (1)
416-417: LGTM!Also applies to: 493-495
crates/adaptive/tests/unit/acg_learner_tests.rs (1)
231-267: LGTM!crates/adaptive/tests/unit/runtime_features_tests.rs (1)
90-97: LGTM!Also applies to: 123-127
crates/python/tests/coverage/py_storage_coverage_tests.rs (1)
143-143: LGTM!crates/adaptive/tests/unit/acg/economics_internal_tests.rs (1)
124-124: LGTM!crates/adaptive/tests/unit/acg_component_tests.rs (1)
50-50: LGTM!Also applies to: 235-235, 266-266, 291-311, 454-458, 534-538, 584-605, 646-646, 677-681, 737-737, 815-846, 945-950, 982-1131, 1185-1185, 1240-1240, 1287-1291, 1390-1390, 1431-1435, 1569-1573
crates/adaptive/src/acg_component.rs (1)
136-162: LGTM!crates/adaptive/tests/integration/runtime_integration_tests.rs (1)
516-517: LGTM!crates/adaptive/src/acg/stability.rs (1)
42-145: LGTM!crates/adaptive/src/acg_learner.rs (1)
108-114: 📐 Maintainability & Code QualityProvide the required validation evidence.
The supplied summary does not confirm
cargo fmt --all,just test-rust, or the required Rust/Python/Go/Node matrix for thiscrates/adaptivechange. Please run and attach results forcargo fmt --all,cargo clippy --workspace --all-targets -- -D warnings,just test-rust, and the repository’s full language matrix.As per coding guidelines, “Any Rust change must run
just test-rust,” “Any Rust change must runcargo fmt --all,” and “Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings.” As per path instructions, “Changes tocrates/coreorcrates/adaptivemust run the full language matrix.”Sources: Coding guidelines, Path instructions
crates/adaptive/tests/unit/acg/stability_internal_tests.rs (1)
81-121: LGTM!crates/adaptive/tests/unit/types_tests.rs (1)
44-44: LGTM!Also applies to: 200-208
crates/adaptive/tests/unit/acg/economics_policy_tests.rs (1)
87-87: LGTM!crates/adaptive/tests/unit/acg/multi_breakpoint_tests.rs (1)
84-84: LGTM!crates/adaptive/tests/unit/cache_diagnostics_tests.rs (1)
85-85: LGTM!crates/adaptive/tests/unit/intercepts_tests.rs (1)
53-53: LGTM!crates/adaptive/tests/unit/storage_memory_internal_tests.rs (1)
87-87: LGTM!crates/adaptive/tests/unit/storage_tests.rs (1)
92-92: LGTM!
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/adaptive/tests/integration/redis_tests.rs (1)
551-553: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick winAssert fingerprint equality across the restart.
is_some()would also pass for a stale or changed fingerprint, so this test does not prove that the serialized value survived backend recreation. Capture the pre-restart fingerprint forlearning_keyand compare it with the reloaded value.As per path instructions, “Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/adaptive/tests/integration/redis_tests.rs` around lines 551 - 553, Update the restart persistence test around the stability assertions to capture the pre-restart stable_prefix_fingerprint for learning_key before recreating the backend, then assert the reloaded fingerprint equals that captured value rather than only checking is_some(). Preserve the existing observation-count assertions.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@crates/adaptive/tests/integration/redis_tests.rs`:
- Around line 551-553: Update the restart persistence test around the stability
assertions to capture the pre-restart stable_prefix_fingerprint for learning_key
before recreating the backend, then assert the reloaded fingerprint equals that
captured value rather than only checking is_some(). Preserve the existing
observation-count assertions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: bd62dbe9-c14b-4043-8324-462a452bb69d
📒 Files selected for processing (4)
crates/adaptive/src/acg/stability.rscrates/adaptive/src/acg_profile.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (14)
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node workWhen changing the core Rust runtime or Rust-facing API surface, format Rust code with
cargo fmt(rustfmt defaults), keepcargo clippy -- -D warningsclean, and satisfycargo deny checkperdeny.toml.
**/*.rs: If any Rust code changed, always runjust test-rust.
If any Rust code changed, also runcargo fmt --all.
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings.
For Rust changes headed for review, runcargo fmt --allandcargo clippy --workspace --all-targets -- -D warningseven if relying on pre-commit.
Files:
crates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg/stability.rs
{crates/core,crates/adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
Changes to
crates/coreorcrates/adaptivemust run the full language matrix
Files:
crates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg/stability.rs
**/*.{rs,py}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions in Rust and Python: use
snake_case.
Files:
crates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg/stability.rs
**/*.{rs,py,js,mjs,cjs,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{rs,py,js,mjs,cjs,ts,tsx}: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths, and keep errors explicit and binding-appropriate at the wrapper layer.
Keep async behavior on the existing tokio-based model; bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
Files:
crates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg/stability.rs
**/*.{rs,py,go,js,ts,c,h}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Use language-appropriate naming conventions: Rust
snake_case, C FFI exports prefixednemo_relay_, GoPascalCase, Node.jscamelCase, and Pythonsnake_case.
Files:
crates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg/stability.rs
**/*.{rs,go,js,ts}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Add the SPDX license header to all Rust, Go, JavaScript, and TypeScript source files using the corresponding
//comment form.
Files:
crates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg/stability.rs
crates/adaptive/**
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Keep
crates/adaptivealigned with the canonical adaptive config schema, built-in section helpers, plugin lifecycle, and validation/report behavior.
Files:
crates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg/stability.rs
**/*
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*: Format changed files with the language-native formatter before the final lint/test pass.
If dynamic plugin behavior changed, usemaintain-dynamic-pluginsand include the native SDK, worker protocol, Python SDK, docs, packaging, and Codecov surfaces in the validation plan.
If code changes alter APIs, bindings, commands, paths, packaging behavior, observability/adaptive semantics, or documented best practices, update any dependent maintainer or consumer skills in the same branch.
During iteration, preferuv run pre-commit run --files <changed files...>.
Before review or handoff, runuv run pre-commit run --all-files.
Files:
crates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg/stability.rs
crates/{core,adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/coreorcrates/adaptivechanged, run the full validation matrix across Rust, Python, Go, and Node.js.
Files:
crates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg/stability.rs
**/*.{rs,py,go,js,ts}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If a language surface changed, always run that language's test target even when Rust core did not change.
Files:
crates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg/stability.rs
**/*.{rs,py,js,ts,tsx,go,java,kt,swift}
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
Add tests covering registration and duplicate names, deregistration and missing names, priority ordering, callback failure policy, scope-local inheritance and cleanup, event payload semantics, immutable mark and scope fields, and parity across affected bindings.
Files:
crates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg/stability.rs
crates/{core,adaptive}/**/*.rs
⚙️ CodeRabbit configuration file
crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.
Files:
crates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg/stability.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.
Files:
crates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rs
{crates/**/src/**/*.rs,python/**/*.py}
📄 CodeRabbit inference engine (.agents/skills/maintain-dynamic-plugins/SKILL.md)
Do not add tests under
src; Rust tests belong in cratetests/trees, and Python SDK tests belong underpython/tests.
Files:
crates/adaptive/src/acg_profile.rscrates/adaptive/src/acg/stability.rs
🔇 Additional comments (4)
crates/adaptive/src/acg_profile.rs (1)
18-19: LGTM!Also applies to: 33-46, 71-102, 216-224
crates/adaptive/src/acg/stability.rs (1)
42-46: LGTM!Also applies to: 77-77, 98-118, 121-200
crates/adaptive/tests/integration/redis_tests.rs (1)
518-546: LGTM!crates/adaptive/tests/unit/acg/stability_internal_tests.rs (1)
81-109: LGTM!Also applies to: 111-121, 123-135
Signed-off-by: teerthsharma <teerths57@Gmail.com>
Signed-off-by: teerthsharma <teerths57@Gmail.com>
Add an interleaving storage backend that yields between the learner's load and store halves, proving that concurrent runs never pair a stable-prefix fingerprint with a foreign observation window and that the agent-level seed adopts exactly one profile's fingerprint rather than blending profiles. Add coverage for two workflows that share a system prompt and anchor turn: they collapse into one learning key, and once the stable prefix extends past the leading scaffold the fingerprint binds to a single complete request so sibling workflows fail closed. Rename the learner's grouping variable to learning_key, which is what derive_acg_learning_key actually returns, to keep it distinct from the separate diagnostics profile key. Signed-off-by: teerthsharma <teerths57@Gmail.com>
Add doc comments for the functions this change introduces or reshapes: the prefix fingerprint helpers, the structured-output scaffold block, the response-format fingerprint, the key-parts derivation, and the intent bundle gate. Each records why the rule is conservative, in particular why a prefix that extends past the leading scaffold binds to the complete source request. Signed-off-by: teerthsharma <teerths57@Gmail.com>
The restart test read its learning key back out of the hot cache, so it passed for whichever key process_run happened to write. process_run also persists the selected profile under the plain agent id for rehydration, which meant a missing or mis-keyed scaffold record could still satisfy the assertions. Assert instead that the surviving key is not the bare agent id and carries the stable-scaffold seed marker, so the reload proves the scaffold-specific record survived the backend restart. Signed-off-by: teerthsharma <teerths57@Gmail.com>
bf70abf to
f5f43fe
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/adaptive/src/acg/ir_builder.rs (1)
203-224: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winImage parts collapse to empty content in the IR, which weakens the scaffold-only fingerprint.
extract_texthere mapsContentPart::ImageUrlandContentPart::ImagetoString::new(), and the empty strings are then filtered out. Two System or Developer messages that differ only in image content produce byte-identicalPromptBlock::content.profile_prefix_fingerprintbinds a prefix that stops inside the scaffold to the prefix content only, so such a request passes the reuse gate against a different learned scaffold.crates/adaptive/src/acg_profile.rsalready avoids this by emitting[image:{detail}:{sha256}]in its ownextract_text. Align the IR builder with that behavior.Note also that the two
extract_textfunctions now have the same name, the same input type, and different semantics. Consider sharing one implementation.🛠️ Proposed fix: keep an image discriminator in the IR text
.map(|part| match part { ContentPart::Text { text, .. } => text.clone(), ContentPart::Refusal { refusal, .. } => refusal.clone(), - ContentPart::ImageUrl { .. } | ContentPart::Image { .. } => String::new(), - ContentPart::Audio { .. } + ContentPart::ImageUrl { .. } + | ContentPart::Image { .. } + | ContentPart::Audio { .. } | ContentPart::File { .. } | ContentPart::ToolUse { .. } | ContentPart::ToolResult { .. } | ContentPart::ProviderNative { .. } => { serde_json::to_string(part).unwrap_or_default() } })🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/adaptive/src/acg/ir_builder.rs` around lines 203 - 224, Update the ir_builder extract_text function to preserve image content distinctions using the established [image:{detail}:{sha256}] representation from acg_profile’s extract_text, rather than returning empty strings for ImageUrl and Image parts. Prefer sharing the existing implementation or helper so both extract_text functions use identical image semantics and retain scaffold-only fingerprint differences.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/adaptive/src/acg_component.rs`:
- Around line 162-182: Update the three build_intent_bundle_skipped emissions
for missing, unavailable, and mismatched stable_prefix_fingerprint in the
surrounding function to include the same agent_id, provider, and
observation_count attribution as the other skip events, plus the learning key
and prefix length. Preserve each existing reason value.
In `@crates/adaptive/src/acg/stability.rs`:
- Around line 98-111: Extract the shared fold-and-max tie-break logic from
analyze_stability and dominant_profile_prefix_fingerprint into one dominant
helper accepting an Iterator<Item = String>. Update both callers to pass their
filtered fingerprints through it, preserving the existing deterministic count
and hash tie-break behavior; keep the distinct unbound and learning-key-bound
fingerprint value spaces unchanged.
In `@crates/adaptive/tests/integration/redis_tests.rs`:
- Around line 532-563: Capture the pre-restart stable prefix fingerprint from
guard.acg_profiles[&learning_key] before dropping the backend, then replace the
post-restart is_some assertion with an exact equality check against that
captured value. Keep the existing observation and stability-count assertions
unchanged.
In `@crates/adaptive/tests/unit/acg_component_tests.rs`:
- Around line 1030-1059: Update the second legacy_stability scenario before the
over-long stable_prefix_length assignment to restore stable_prefix_fingerprint
to Some using the appropriate existing fingerprint value, so build_intent_bundle
reaches the stable_prefix_fingerprint_unavailable branch instead of repeating
the missing-fingerprint case. Keep the first missing-fingerprint assertion
unchanged.
In `@crates/adaptive/tests/unit/acg_learner_tests.rs`:
- Around line 536-544: Update the observation-count assertion in the concurrent
process_run test to verify the safety bound rather than requiring exactly one
surviving observation for alpha_key. Preserve the existing load_observations
flow and fingerprint-reproducibility loop, which should remain the invariant for
deterministic behavior.
---
Outside diff comments:
In `@crates/adaptive/src/acg/ir_builder.rs`:
- Around line 203-224: Update the ir_builder extract_text function to preserve
image content distinctions using the established [image:{detail}:{sha256}]
representation from acg_profile’s extract_text, rather than returning empty
strings for ImageUrl and Image parts. Prefer sharing the existing implementation
or helper so both extract_text functions use identical image semantics and
retain scaffold-only fingerprint differences.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 1a637956-51dd-46d6-8422-b87bc8bb1ad0
📒 Files selected for processing (22)
crates/adaptive/src/acg/ir_builder.rscrates/adaptive/src/acg/stability.rscrates/adaptive/src/acg_component.rscrates/adaptive/src/acg_learner.rscrates/adaptive/src/acg_profile.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/types_tests.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (14)
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node workWhen changing the core Rust runtime or Rust-facing API surface, format Rust code with
cargo fmt(rustfmt defaults), keepcargo clippy -- -D warningsclean, and satisfycargo deny checkperdeny.toml.
**/*.rs: If any Rust code changed, always runjust test-rust.
If any Rust code changed, also runcargo fmt --all.
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings.
For Rust changes headed for review, runcargo fmt --allandcargo clippy --workspace --all-targets -- -D warningseven if relying on pre-commit.
Files:
crates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/src/acg/stability.rs
{crates/core,crates/adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
Changes to
crates/coreorcrates/adaptivemust run the full language matrix
Files:
crates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/src/acg/stability.rs
**/*.{rs,py}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions in Rust and Python: use
snake_case.
Files:
crates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/src/acg/stability.rs
**/*.{rs,py,js,mjs,cjs,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{rs,py,js,mjs,cjs,ts,tsx}: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths, and keep errors explicit and binding-appropriate at the wrapper layer.
Keep async behavior on the existing tokio-based model; bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
Files:
crates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/src/acg/stability.rs
**/*.{rs,py,go,js,ts,c,h}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Use language-appropriate naming conventions: Rust
snake_case, C FFI exports prefixednemo_relay_, GoPascalCase, Node.jscamelCase, and Pythonsnake_case.
Files:
crates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/src/acg/stability.rs
**/*.{rs,go,js,ts}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Add the SPDX license header to all Rust, Go, JavaScript, and TypeScript source files using the corresponding
//comment form.
Files:
crates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/src/acg/stability.rs
crates/adaptive/**
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Keep
crates/adaptivealigned with the canonical adaptive config schema, built-in section helpers, plugin lifecycle, and validation/report behavior.
Files:
crates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/src/acg/stability.rs
**/*
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*: Format changed files with the language-native formatter before the final lint/test pass.
If dynamic plugin behavior changed, usemaintain-dynamic-pluginsand include the native SDK, worker protocol, Python SDK, docs, packaging, and Codecov surfaces in the validation plan.
If code changes alter APIs, bindings, commands, paths, packaging behavior, observability/adaptive semantics, or documented best practices, update any dependent maintainer or consumer skills in the same branch.
During iteration, preferuv run pre-commit run --files <changed files...>.
Before review or handoff, runuv run pre-commit run --all-files.
Files:
crates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/src/acg/stability.rs
crates/{core,adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/coreorcrates/adaptivechanged, run the full validation matrix across Rust, Python, Go, and Node.js.
Files:
crates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/src/acg/stability.rs
**/*.{rs,py,go,js,ts}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If a language surface changed, always run that language's test target even when Rust core did not change.
**/*.{rs,py,go,js,ts}: When observability configuration or lifecycle is exposed, keep FFI and Python, Go, and Node.js binding-native config objects and subscriber/exporter methods aligned in logical knobs and semantics.
Require every OpenTelemetry endpoint to have a type and nonblank destination; resolveheader_envvalues at activation and reject missing, blank, or duplicate headers.
Concatenate layered ATOF sink, ATIF storage, and OpenTelemetry endpoint lists with higher-precedence entries first.
Preserve correct handling of mark events, start/end events, orphan cases, and span or trajectory fields derived from intended event data.
Run affected Rust tests andjust test-rustwhen event fields change; runjust test-python,just test-go, andjust test-nodewhen binding-native configuration or lifecycle changes.
Files:
crates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/src/acg/stability.rs
**/*.{rs,py,js,ts,tsx,go,java,kt,swift}
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
Add tests covering registration and duplicate names, deregistration and missing names, priority ordering, callback failure policy, scope-local inheritance and cleanup, event payload semantics, immutable mark and scope fields, and parity across affected bindings.
Files:
crates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/src/acg/stability.rs
crates/{core,adaptive}/**/*.rs
⚙️ CodeRabbit configuration file
crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.
Files:
crates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/src/acg_component.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg_learner.rscrates/adaptive/tests/unit/acg_component_tests.rscrates/adaptive/src/acg/stability.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.
Files:
crates/adaptive/tests/unit/storage_tests.rscrates/adaptive/tests/unit/runtime_features_tests.rscrates/adaptive/tests/unit/acg/multi_breakpoint_tests.rscrates/adaptive/tests/unit/cache_diagnostics_tests.rscrates/adaptive/tests/unit/acg/economics_internal_tests.rscrates/adaptive/tests/unit/intercepts_tests.rscrates/adaptive/tests/unit/acg_profile_tests.rscrates/adaptive/tests/unit/types_tests.rscrates/adaptive/tests/unit/acg/economics_policy_tests.rscrates/adaptive/tests/unit/runtime_tests.rscrates/adaptive/tests/integration/redis_tests.rscrates/adaptive/tests/unit/storage_memory_internal_tests.rscrates/adaptive/tests/unit/acg/ir_builder_tests.rscrates/adaptive/tests/integration/runtime_integration_tests.rscrates/adaptive/tests/unit/acg_learner_tests.rscrates/adaptive/tests/unit/acg/stability_internal_tests.rscrates/adaptive/tests/unit/acg_component_tests.rs
{crates/**/src/**/*.rs,python/**/*.py}
📄 CodeRabbit inference engine (.agents/skills/maintain-dynamic-plugins/SKILL.md)
Do not add tests under
src; Rust tests belong in cratetests/trees, and Python SDK tests belong underpython/tests.
Files:
crates/adaptive/src/acg_component.rscrates/adaptive/src/acg/ir_builder.rscrates/adaptive/src/acg_profile.rscrates/adaptive/src/acg_learner.rscrates/adaptive/src/acg/stability.rs
🔇 Additional comments (31)
crates/adaptive/src/acg/ir_builder.rs (2)
38-44: LGTM!Also applies to: 57-78, 91-91, 334-364
142-172: LGTM!Also applies to: 226-236, 400-405
crates/adaptive/src/acg_profile.rs (3)
18-19: LGTM!Also applies to: 33-46, 71-75, 91-117, 296-303
133-163: LGTM!Also applies to: 210-260, 305-330
262-265: 🗄️ Data Integrity & IntegrationResolve the
serde_jsonfeature set before relying on this fallback. The manifests contain no explicitpreserve_orderfeature, but a transitive dependency could still enable it. If the resolved feature set includespreserve_order, make the fallback fail closed.crates/adaptive/tests/unit/acg/ir_builder_tests.rs (1)
201-300: LGTM!Also applies to: 302-346
crates/adaptive/tests/unit/acg_profile_tests.rs (1)
40-78: LGTM!Also applies to: 80-149, 233-286, 437-596
crates/adaptive/src/acg/stability.rs (1)
42-46: LGTM!Also applies to: 133-157, 178-207
crates/adaptive/tests/unit/acg/stability_internal_tests.rs (1)
82-109: LGTM!Also applies to: 111-121, 123-135
crates/adaptive/tests/unit/acg_learner_tests.rs (2)
233-269: LGTM!Also applies to: 578-630
393-505: LGTM!crates/adaptive/tests/unit/runtime_features_tests.rs (1)
89-130: LGTM!Also applies to: 148-181, 980-1010
crates/adaptive/tests/unit/cache_diagnostics_tests.rs (1)
85-85: LGTM!Also applies to: 94-95
crates/adaptive/src/acg_component.rs (1)
110-129: LGTM!Also applies to: 633-659
crates/adaptive/tests/unit/acg_component_tests.rs (2)
50-50: LGTM!Also applies to: 237-237, 268-268, 293-313, 456-460, 536-540, 586-607, 648-648, 679-683, 739-739, 947-952, 1187-1187, 1242-1242, 1289-1293, 1392-1392, 1433-1437, 1571-1589
817-848: LGTM!Also applies to: 984-1028, 1062-1133
crates/adaptive/tests/unit/runtime_tests.rs (3)
34-113: LGTM!
394-558: LGTM!
582-637: LGTM!crates/adaptive/tests/integration/runtime_integration_tests.rs (3)
75-242: LGTM!
517-563: LGTM!
593-602: LGTM!Also applies to: 717-751, 814-822
crates/adaptive/src/acg_learner.rs (2)
91-120: LGTM!
139-141: LGTM!crates/adaptive/tests/unit/types_tests.rs (1)
34-47: LGTM!Also applies to: 176-209
crates/adaptive/tests/unit/acg/economics_internal_tests.rs (1)
118-126: LGTM!crates/adaptive/tests/unit/acg/economics_policy_tests.rs (1)
73-90: LGTM!crates/adaptive/tests/unit/acg/multi_breakpoint_tests.rs (1)
72-87: LGTM!crates/adaptive/tests/unit/intercepts_tests.rs (1)
39-58: LGTM!crates/adaptive/tests/unit/storage_memory_internal_tests.rs (1)
77-90: LGTM!crates/adaptive/tests/unit/storage_tests.rs (1)
82-95: LGTM!
| let Some(stored_fingerprint) = stability.stable_prefix_fingerprint.as_ref() else { | ||
| acg_debug::emit( | ||
| "build_intent_bundle_skipped", | ||
| json!({"reason": "stable_prefix_fingerprint_missing"}), | ||
| ); | ||
| return None; | ||
| }; | ||
| let Some(live_fingerprint) = live_fingerprint.as_ref() else { | ||
| acg_debug::emit( | ||
| "build_intent_bundle_skipped", | ||
| json!({"reason": "stable_prefix_fingerprint_unavailable"}), | ||
| ); | ||
| return None; | ||
| }; | ||
| if stored_fingerprint != live_fingerprint { | ||
| acg_debug::emit( | ||
| "build_intent_bundle_skipped", | ||
| json!({"reason": "stable_prefix_fingerprint_mismatch"}), | ||
| ); | ||
| return None; | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Add attribution to the three new skip events.
The other build_intent_bundle_skipped emissions in this function carry agent_id, provider, and observation_count. These three carry only reason. When reuse stops in production, an operator cannot tell which agent or profile was rejected, which is exactly the case these events exist to explain. Include the learning key and the prefix length as well.
🔍 Proposed event payloads
let Some(stored_fingerprint) = stability.stable_prefix_fingerprint.as_ref() else {
acg_debug::emit(
"build_intent_bundle_skipped",
- json!({"reason": "stable_prefix_fingerprint_missing"}),
+ json!({
+ "reason": "stable_prefix_fingerprint_missing",
+ "agent_id": agent_id,
+ "provider": provider,
+ "learning_key": learning_key,
+ "stable_prefix_length": stability.stable_prefix_length,
+ }),
);
return None;
};
let Some(live_fingerprint) = live_fingerprint.as_ref() else {
acg_debug::emit(
"build_intent_bundle_skipped",
- json!({"reason": "stable_prefix_fingerprint_unavailable"}),
+ json!({
+ "reason": "stable_prefix_fingerprint_unavailable",
+ "agent_id": agent_id,
+ "provider": provider,
+ "learning_key": learning_key,
+ "stable_prefix_length": stability.stable_prefix_length,
+ "prompt_block_count": prompt_ir.blocks.len(),
+ }),
);
return None;
};
if stored_fingerprint != live_fingerprint {
acg_debug::emit(
"build_intent_bundle_skipped",
- json!({"reason": "stable_prefix_fingerprint_mismatch"}),
+ json!({
+ "reason": "stable_prefix_fingerprint_mismatch",
+ "agent_id": agent_id,
+ "provider": provider,
+ "learning_key": learning_key,
+ "stable_prefix_length": stability.stable_prefix_length,
+ }),
);
return None;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let Some(stored_fingerprint) = stability.stable_prefix_fingerprint.as_ref() else { | |
| acg_debug::emit( | |
| "build_intent_bundle_skipped", | |
| json!({"reason": "stable_prefix_fingerprint_missing"}), | |
| ); | |
| return None; | |
| }; | |
| let Some(live_fingerprint) = live_fingerprint.as_ref() else { | |
| acg_debug::emit( | |
| "build_intent_bundle_skipped", | |
| json!({"reason": "stable_prefix_fingerprint_unavailable"}), | |
| ); | |
| return None; | |
| }; | |
| if stored_fingerprint != live_fingerprint { | |
| acg_debug::emit( | |
| "build_intent_bundle_skipped", | |
| json!({"reason": "stable_prefix_fingerprint_mismatch"}), | |
| ); | |
| return None; | |
| } | |
| let Some(stored_fingerprint) = stability.stable_prefix_fingerprint.as_ref() else { | |
| acg_debug::emit( | |
| "build_intent_bundle_skipped", | |
| json!({ | |
| "reason": "stable_prefix_fingerprint_missing", | |
| "agent_id": agent_id, | |
| "provider": provider, | |
| "learning_key": learning_key, | |
| "stable_prefix_length": stability.stable_prefix_length, | |
| }), | |
| ); | |
| return None; | |
| }; | |
| let Some(live_fingerprint) = live_fingerprint.as_ref() else { | |
| acg_debug::emit( | |
| "build_intent_bundle_skipped", | |
| json!({ | |
| "reason": "stable_prefix_fingerprint_unavailable", | |
| "agent_id": agent_id, | |
| "provider": provider, | |
| "learning_key": learning_key, | |
| "stable_prefix_length": stability.stable_prefix_length, | |
| "prompt_block_count": prompt_ir.blocks.len(), | |
| }), | |
| ); | |
| return None; | |
| }; | |
| if stored_fingerprint != live_fingerprint { | |
| acg_debug::emit( | |
| "build_intent_bundle_skipped", | |
| json!({ | |
| "reason": "stable_prefix_fingerprint_mismatch", | |
| "agent_id": agent_id, | |
| "provider": provider, | |
| "learning_key": learning_key, | |
| "stable_prefix_length": stability.stable_prefix_length, | |
| }), | |
| ); | |
| return None; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@crates/adaptive/src/acg_component.rs` around lines 162 - 182, Update the
three build_intent_bundle_skipped emissions for missing, unavailable, and
mismatched stable_prefix_fingerprint in the surrounding function to include the
same agent_id, provider, and observation_count attribution as the other skip
events, plus the learning key and prefix length. Preserve each existing reason
value.
| let learning_key = { | ||
| let guard = hot_cache.read().unwrap(); | ||
| assert_eq!(guard.acg_profiles.len(), 1); | ||
| guard.acg_profiles.keys().next().unwrap().clone() | ||
| }; | ||
| // Both requests carry the same scaffold and differ only in the first user | ||
| // task, so the surviving record must be the scaffold-keyed profile rather | ||
| // than the plain agent seed `process_run` also writes for rehydration. | ||
| assert_ne!(learning_key, agent_id); | ||
| assert!( | ||
| learning_key.contains("::seed=stable-scaffold::"), | ||
| "expected a scaffold-keyed profile, got {learning_key}" | ||
| ); | ||
| drop(backend); | ||
|
|
||
| let restarted = RedisBackend::new("redis://127.0.0.1/", prefix) | ||
| .await | ||
| .unwrap(); | ||
| let observations = restarted | ||
| .load_observations(&learning_key) | ||
| .await | ||
| .unwrap() | ||
| .unwrap(); | ||
| let stability = restarted | ||
| .load_stability(&learning_key) | ||
| .await | ||
| .unwrap() | ||
| .unwrap(); | ||
|
|
||
| assert_eq!(observations.len(), 2); | ||
| assert_eq!(stability.total_observations, 2); | ||
| assert!(stability.stable_prefix_fingerprint.is_some()); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Strengthen the restart fingerprint assertion to check exact value, not just presence.
Line 563 only asserts stability.stable_prefix_fingerprint.is_some() after the Redis restart. Capture the pre-restart fingerprint from guard.acg_profiles[&learning_key] before drop(backend), and assert exact equality after reload. This confirms the persisted fingerprint round-trips correctly, not just that some value survived.
As per path instructions, "Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests."
🔧 Proposed fix to assert exact fingerprint equality across restart
- let learning_key = {
- let guard = hot_cache.read().unwrap();
- assert_eq!(guard.acg_profiles.len(), 1);
- guard.acg_profiles.keys().next().unwrap().clone()
- };
+ let (learning_key, expected_fingerprint) = {
+ let guard = hot_cache.read().unwrap();
+ assert_eq!(guard.acg_profiles.len(), 1);
+ let key = guard.acg_profiles.keys().next().unwrap().clone();
+ let fingerprint = guard.acg_profiles[&key].stable_prefix_fingerprint.clone();
+ (key, fingerprint)
+ };
// Both requests carry the same scaffold and differ only in the first user
// task, so the surviving record must be the scaffold-keyed profile rather
// than the plain agent seed `process_run` also writes for rehydration.
assert_ne!(learning_key, agent_id);
assert!(
learning_key.contains("::seed=stable-scaffold::"),
"expected a scaffold-keyed profile, got {learning_key}"
);
drop(backend);
let restarted = RedisBackend::new("redis://127.0.0.1/", prefix)
.await
.unwrap();
let observations = restarted
.load_observations(&learning_key)
.await
.unwrap()
.unwrap();
let stability = restarted
.load_stability(&learning_key)
.await
.unwrap()
.unwrap();
assert_eq!(observations.len(), 2);
assert_eq!(stability.total_observations, 2);
- assert!(stability.stable_prefix_fingerprint.is_some());
+ assert!(expected_fingerprint.is_some());
+ assert_eq!(stability.stable_prefix_fingerprint, expected_fingerprint);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let learning_key = { | |
| let guard = hot_cache.read().unwrap(); | |
| assert_eq!(guard.acg_profiles.len(), 1); | |
| guard.acg_profiles.keys().next().unwrap().clone() | |
| }; | |
| // Both requests carry the same scaffold and differ only in the first user | |
| // task, so the surviving record must be the scaffold-keyed profile rather | |
| // than the plain agent seed `process_run` also writes for rehydration. | |
| assert_ne!(learning_key, agent_id); | |
| assert!( | |
| learning_key.contains("::seed=stable-scaffold::"), | |
| "expected a scaffold-keyed profile, got {learning_key}" | |
| ); | |
| drop(backend); | |
| let restarted = RedisBackend::new("redis://127.0.0.1/", prefix) | |
| .await | |
| .unwrap(); | |
| let observations = restarted | |
| .load_observations(&learning_key) | |
| .await | |
| .unwrap() | |
| .unwrap(); | |
| let stability = restarted | |
| .load_stability(&learning_key) | |
| .await | |
| .unwrap() | |
| .unwrap(); | |
| assert_eq!(observations.len(), 2); | |
| assert_eq!(stability.total_observations, 2); | |
| assert!(stability.stable_prefix_fingerprint.is_some()); | |
| let (learning_key, expected_fingerprint) = { | |
| let guard = hot_cache.read().unwrap(); | |
| assert_eq!(guard.acg_profiles.len(), 1); | |
| let key = guard.acg_profiles.keys().next().unwrap().clone(); | |
| let fingerprint = guard.acg_profiles[&key].stable_prefix_fingerprint.clone(); | |
| (key, fingerprint) | |
| }; | |
| // Both requests carry the same scaffold and differ only in the first user | |
| // task, so the surviving record must be the scaffold-keyed profile rather | |
| // than the plain agent seed `process_run` also writes for rehydration. | |
| assert_ne!(learning_key, agent_id); | |
| assert!( | |
| learning_key.contains("::seed=stable-scaffold::"), | |
| "expected a scaffold-keyed profile, got {learning_key}" | |
| ); | |
| drop(backend); | |
| let restarted = RedisBackend::new("redis://127.0.0.1/", prefix) | |
| .await | |
| .unwrap(); | |
| let observations = restarted | |
| .load_observations(&learning_key) | |
| .await | |
| .unwrap() | |
| .unwrap(); | |
| let stability = restarted | |
| .load_stability(&learning_key) | |
| .await | |
| .unwrap() | |
| .unwrap(); | |
| assert_eq!(observations.len(), 2); | |
| assert_eq!(stability.total_observations, 2); | |
| assert!(expected_fingerprint.is_some()); | |
| assert_eq!(stability.stable_prefix_fingerprint, expected_fingerprint); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@crates/adaptive/tests/integration/redis_tests.rs` around lines 532 - 563,
Capture the pre-restart stable prefix fingerprint from
guard.acg_profiles[&learning_key] before dropping the backend, then replace the
post-restart is_some assertion with an exact equality check against that
captured value. Keep the existing observation and stability-count assertions
unchanged.
Source: Path instructions
| let mut legacy_stability = stability; | ||
| legacy_stability.stable_prefix_fingerprint = None; | ||
| assert!( | ||
| build_intent_bundle( | ||
| "agent-openai", | ||
| "openai", | ||
| plugin.as_ref(), | ||
| RequestSurface::OpenAIChat, | ||
| &request, | ||
| &prompt_ir, | ||
| &legacy_stability, | ||
| MIN_ACG_OBSERVATIONS, | ||
| ) | ||
| .is_none() | ||
| ); | ||
|
|
||
| legacy_stability.stable_prefix_length = prompt_ir.blocks.len() + 1; | ||
| assert!( | ||
| build_intent_bundle( | ||
| "agent-openai", | ||
| "openai", | ||
| plugin.as_ref(), | ||
| RequestSurface::OpenAIChat, | ||
| &request, | ||
| &prompt_ir, | ||
| &legacy_stability, | ||
| MIN_ACG_OBSERVATIONS, | ||
| ) | ||
| .is_none() | ||
| ); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
The last assertion repeats the missing branch instead of covering unavailable.
Line 1031 sets stable_prefix_fingerprint = None, and line 1046 then sets an over-long stable_prefix_length. build_intent_bundle checks the stored fingerprint before the live one, so the final case exits through stable_prefix_fingerprint_missing, exactly like the case above it. The stable_prefix_fingerprint_unavailable path stays uncovered.
Restore a Some fingerprint before setting the over-long prefix length.
💚 Proposed fix
- legacy_stability.stable_prefix_length = prompt_ir.blocks.len() + 1;
+ // Restore the stored fingerprint so the over-long prefix exercises the
+ // "live fingerprint unavailable" branch rather than the "missing" branch.
+ legacy_stability.stable_prefix_fingerprint = Some("sha256:stored".to_string());
+ legacy_stability.stable_prefix_length = prompt_ir.blocks.len() + 1;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let mut legacy_stability = stability; | |
| legacy_stability.stable_prefix_fingerprint = None; | |
| assert!( | |
| build_intent_bundle( | |
| "agent-openai", | |
| "openai", | |
| plugin.as_ref(), | |
| RequestSurface::OpenAIChat, | |
| &request, | |
| &prompt_ir, | |
| &legacy_stability, | |
| MIN_ACG_OBSERVATIONS, | |
| ) | |
| .is_none() | |
| ); | |
| legacy_stability.stable_prefix_length = prompt_ir.blocks.len() + 1; | |
| assert!( | |
| build_intent_bundle( | |
| "agent-openai", | |
| "openai", | |
| plugin.as_ref(), | |
| RequestSurface::OpenAIChat, | |
| &request, | |
| &prompt_ir, | |
| &legacy_stability, | |
| MIN_ACG_OBSERVATIONS, | |
| ) | |
| .is_none() | |
| ); | |
| let mut legacy_stability = stability; | |
| legacy_stability.stable_prefix_fingerprint = None; | |
| assert!( | |
| build_intent_bundle( | |
| "agent-openai", | |
| "openai", | |
| plugin.as_ref(), | |
| RequestSurface::OpenAIChat, | |
| &request, | |
| &prompt_ir, | |
| &legacy_stability, | |
| MIN_ACG_OBSERVATIONS, | |
| ) | |
| .is_none() | |
| ); | |
| // Restore the stored fingerprint so the over-long prefix exercises | |
| // the "live fingerprint unavailable" branch rather than the "missing" branch. | |
| legacy_stability.stable_prefix_fingerprint = Some("sha256:stored".to_string()); | |
| legacy_stability.stable_prefix_length = prompt_ir.blocks.len() + 1; | |
| assert!( | |
| build_intent_bundle( | |
| "agent-openai", | |
| "openai", | |
| plugin.as_ref(), | |
| RequestSurface::OpenAIChat, | |
| &request, | |
| &prompt_ir, | |
| &legacy_stability, | |
| MIN_ACG_OBSERVATIONS, | |
| ) | |
| .is_none() | |
| ); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@crates/adaptive/tests/unit/acg_component_tests.rs` around lines 1030 - 1059,
Update the second legacy_stability scenario before the over-long
stable_prefix_length assignment to restore stable_prefix_fingerprint to Some
using the appropriate existing fingerprint value, so build_intent_bundle reaches
the stable_prefix_fingerprint_unavailable branch instead of repeating the
missing-fingerprint case. Keep the first missing-fingerprint assertion
unchanged.
| assert_eq!( | ||
| backend | ||
| .load_observations(&alpha_key) | ||
| .await | ||
| .unwrap() | ||
| .unwrap() | ||
| .len(), | ||
| 1, | ||
| ); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Assert the safety bound, not the exact interleaving outcome.
This asserts that exactly one observation survives for alpha_key after three concurrent process_run futures. That value depends on the current poll order of tokio::join! and on the exact placement of the yield_now calls in InterleavingBackend. Both are implementation details, not contract. The test can flake or fail on an unrelated refactor even though the property the comment describes still holds.
Assert the bound instead, and keep the fingerprint-reproducibility loop below as the real invariant.
💚 Proposed assertion change
- assert_eq!(
- backend
- .load_observations(&alpha_key)
- .await
- .unwrap()
- .unwrap()
- .len(),
- 1,
- );
+ let alpha_window = backend
+ .load_observations(&alpha_key)
+ .await
+ .unwrap()
+ .unwrap()
+ .len();
+ assert!(
+ (1..=2).contains(&alpha_window),
+ "interleaved runs may drop an observation, but never all of them: got {alpha_window}",
+ );📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| assert_eq!( | |
| backend | |
| .load_observations(&alpha_key) | |
| .await | |
| .unwrap() | |
| .unwrap() | |
| .len(), | |
| 1, | |
| ); | |
| let alpha_window = backend | |
| .load_observations(&alpha_key) | |
| .await | |
| .unwrap() | |
| .unwrap() | |
| .len(); | |
| assert!( | |
| (1..=2).contains(&alpha_window), | |
| "interleaved runs may drop an observation, but never all of them: got {alpha_window}", | |
| ); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@crates/adaptive/tests/unit/acg_learner_tests.rs` around lines 536 - 544,
Update the observation-count assertion in the concurrent process_run test to
verify the safety bound rather than requiring exactly one surviving observation
for alpha_key. Preserve the existing load_observations flow and
fingerprint-reproducibility loop, which should remain the invariant for
deterministic behavior.
The stable prefix is derived from span scores sorted on the first-seen sequence index alone. That key is not injective over the span set: span ids carry the role and the tool suffix, so assistant-1-search and assistant-1-fetch are distinct spans sharing index 1, and the index is a minimum across observations, which collides further. A stable sort on that key leaves tied spans in HashMap iteration order, which is seeded per process, so the stable prefix length and its fingerprint varied between runs on identical input. Over 20 processes with one contested turn position and four tool spans at one index, the unfixed comparator produced 20 distinct span orders, 2 distinct prefix lengths, and 2 distinct fingerprints. A profile learned in one process therefore failed the reuse gate in another. Sort by (sequence index, stability rank, span id) instead. Span ids are unique within an analysis, so the key is injective and a total order over a finite set admits exactly one sorted sequence. The same 20 processes now agree on all three. Ranking the least stable span first makes the prefix stop before a contested position rather than extend across it, which matches the fail-closed rule the reuse gate already applies. Fold the duplicated dominant-fingerprint tie-break into one helper so the rule that decides reuse determinism exists in a single place. Signed-off-by: teerthsharma <teerths57@Gmail.com>
The stable prefix was the leading run of per-span scores above the stable threshold. That reads a span-level statistic, presence rate times dominant content fraction, and then re-sequences those scores, so the answer depended on the order the span map was enumerated in and diverged from the exact prefix a provider cache actually keys on. Derive it from the observations instead: descend the prefix tree of block sequences while one child still holds the configured share of the window. Descent also requires a strict majority, and two disjoint children cannot both hold one, so the dominant child is unique wherever it exists and no tie-break is reachable. Where no child dominates, the prefix stops. The rule is the one the review asked for, the same exact prefix observed for N samples, and it recovers reuse the span rule discarded. On a 20-observation window whose first turn varies in 1 of 20 runs, the span rule reports a 1-block prefix while 19 of 20 observations share an exact 6-block prefix; the outlier still fails the fingerprint gate, so the wider prefix stays exactly validated. Across 20 processes the rule returns one length and one fingerprint. Remove find_stable_prefix_length, whose only caller this replaces and which nothing else in the workspace uses. Fold the block identity shared by the length rule and the fingerprint into one definition so the two cannot drift. Record that prefix economics, not the length rule, is what the stability rank in the score ordering protects. Signed-off-by: teerthsharma <teerths57@Gmail.com>
Record the quantity the ordering and prefix rules exist to hold at 1: over N processes producing outcomes with multiplicities c_i, the agreement rate A = sum c_i (c_i - 1) / (N (N - 1)) is the probability two independent processes agree, and so the probability that a profile persisted by one satisfies the reuse gate in another. Tighten the surrounding doc comments and drop the unreachable trailing expression from the descent loop. Signed-off-by: teerthsharma <teerths57@Gmail.com>
Overview
ACG includes the first non-system message in its learning key. A workflow whose
system prompt, tool schemas, and output contract never change is therefore split
into a separate profile for every distinct first user task, so observations never
accumulate and the stable scaffold is never recognized as a reusable prefix.
This change buckets learning by the stable system/tool/structured-output
scaffold, preserves the prior task seed for requests without one, and gates reuse
on a fingerprint bound to the exact scaffold key.
Scope is the three items assessed as meaningful in the #323 review:
scaffold-aware keying, a stable-prefix fingerprint guard, and the
structured-output contract in
PromptIR. No governor, drift detector,convergence machinery, topology state, configuration surface, or binding change.
Nothing is added to Python, Node, Go, WebAssembly, or C FFI.
Details
5 source files (+432/-51), 18 test files (+938/-35).
prompt, tool schemas, or a structured-output contract bucket under
seed=stable-scaffold; requests without one keep the prior task-seed behavior.structured_output_schema_idis populated and the canonicalizedresponse_formatbecomes a scaffold block ahead of the first non-systemmessage, so an unchanging output contract sits inside the stable prefix.
scaffold binds to that scaffold; one extending past it binds to the complete
source request, because the normalized IR retains no lossless provider-prefix
representation.
beyond-scaffold-without-a-source-request fingerprints.
find_stable_prefix_lengthis removed. This change replaces its only callerand nothing else in the workspace used it.
Learning-key fragmentation on
mainControl:
mainat2ab7a070, no source change. Two requests sharing a systemprompt and tool schema, differing only in the first user task, key as:
systemandtoolsare identical; onlyseeddiffers, so the two runs land inseparate profiles and neither accumulates enough observations to produce a
reusable prefix. On this head the pair produces one key with
seed=stable-scaffold.Reuse determinism
A profile persisted by one process is read back by another, so the analysis must
not depend on the per-process seed Rust draws for
HashMapiteration. OverNprocesses producing outcomes with multiplicities
c_1..c_k, the cross-processagreement rate is
the probability two independent processes agree, and equivalently the probability
that a persisted profile satisfies the reuse gate elsewhere.
A = 1exactly whenthe analysis is seed-independent.
Measured over
N = 20processes on one 20-observation window whose first turnvaries in 1 of 20 runs, with four tool spans sharing a sequence index:
AAAsequence_index(main)1×9,2×11(index, rank, span id)16mainderives the prefix as the leading run of per-span scores, thenre-sequences those scores by first-seen index. That index does not order the span
set: span ids carry the role and tool suffix, so
assistant-1-searchandassistant-1-fetchare distinct spans at index 1, and the index is a minimumacross observations. At
A = 0.479, better than half of cross-process profilereads miss.
Two changes follow. Score ordering extends to
(index, stability rank, span id),injective because span ids are unique within one analysis. Prefix economics walks
that vector and stops pricing at the first non-stable span, so ranking the least
stable first ends the priced prefix at a contested position instead of pricing
across it.
The prefix length no longer reads that vector. It descends the prefix tree of
block sequences while one child holds the configured share, which is the rule
named in the #323 review: the same exact prefix observed for N samples. Descent
also requires a strict majority, which two disjoint children cannot both hold, so
the dominant child is unique where it exists and no tie-break is reachable; where
none dominates, the prefix stops. Equivalently, under
d(x, y) = 2^-lcp(x, y)the window is ultrametric, and every point of a closed ball is a center, so the
ball is fixed by its members rather than by traversal order.
That also recovers reuse. On this window 19 of 20 observations share an exact
6-block prefix; the per-span rule reports 1 because the minority span at index 1
stops the run. The outlier still fails the fingerprint gate, so the wider prefix
stays exactly validated.
Test coverage
Variable first-user tasks under one scaffold; changed system prompts, tool
schemas, and output contracts; canonical structured output; whitespace changes
hidden by normalized IR; prefixes beyond the scaffold; legacy state with no
fingerprint; same-run aggregation; fresh-cache rehydration; Redis restart;
serialization compatibility.
Adversarial cases: an interleaving storage backend that yields between the
learner's load and store halves shows concurrent runs never pair a fingerprint
with a foreign observation window; two workflows sharing a system prompt and
anchor turn collapse to one key and then fail closed once the prefix extends past
the scaffold; every rotation of one span set produces a single canonical ordering
without depending on a hash seed.
The Redis restart test previously read its learning key out of the hot cache, so
it passed for whichever key
process_runwrote — andprocess_runalso persistsunder the plain agent id for rehydration, so a mis-keyed scaffold record could
have satisfied it. It now asserts the key is not the bare agent id and carries the
stable-scaffold marker before reloading.
Validation
PR head
25c771e7onmainat2ab7a070, Windows 11, rustc 1.97.1, go 1.26.1:cargo test -p nemo-relay-adaptiveNEMO_RELAY_RUN_REDIS_TESTS=1 … --features redis-backend --test redis_integration127.0.0.1:6379just test-pythonjust test-nodecargo clippy -p nemo-relay-adaptive -p nemo-relay-python --all-targets -- -D warningscargo fmt --all -- --checkThe 36 response-cache and 4 response-cache benchmark tests cover the opt-in
exact-match LLM response cache from #404 and pass unchanged on this head.
Limits
No provider-cache, cost, or latency improvement is claimed. The analysis-only
trace report, the three-arm interleaved experiment, and the provider
cache-read/cache-write, billed-cost, parity, and p50/p95/p99 evidence requested in
points 1 through 3 of the #323 review are not supplied here; this diff is the
internal keying and validation change those points would measure. An earlier
interleaved run showed the fragmentation directly (144 keys and 0 hints versus 1
key and 120 hints) but used an older
mainand a benchmark overlay, so it is notoffered as evidence for this diff.
The exact-prefix-mass rule widens prefixes relative to
main, which is abehavior change and not only a determinism fix; reuse remains gated on the exact
fingerprint.
Two suites did not run on this host:
just test-gorequiresclang/lld, andfull-workspace
just test-rustreaches unrelated CLI filesystem failures onWindows. CI provides the authoritative Linux matrix.
Persisted JSON stays backward-compatible through an optional fingerprint field,
which is source-visible to downstream Rust constructing
StabilityAnalysisResultwith a struct literal.
Where should the reviewer start?
crates/adaptive/src/acg_profile.rsfor the learning-key boundary, thencrates/adaptive/src/acg/stability.rsfor the prefix and ordering rules andcrates/adaptive/src/acg_component.rsfor the gate. Focused tests are incrates/adaptive/tests/unit/acg_profile_tests.rs,crates/adaptive/tests/unit/acg/stability_internal_tests.rs, andcrates/adaptive/tests/unit/acg_component_tests.rs.Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)
convergence, governor, drift, and binding scope rejected there is absent.