Repository navigation
auto-recover: orphaned worker branch for #2321 - #2324
superdav42 wants to merge 2 commits into
Conversation
|
Warning Review limit reached
Next review available in: 41 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds versioned managed customer-agent profiles with ownership controls, schema persistence, constrained prompt composition, explicit anonymous deny-all policies, locked runtime execution, trusted request context, and structured handoff responses. ChangesManaged customer-agent runtime
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Consumer
participant CustomerAgentRuntimeService
participant AgentLoop
participant ResponseNormalizer
Consumer->>CustomerAgentRuntimeService: enqueue_turn(message, request_context)
CustomerAgentRuntimeService->>CustomerAgentRuntimeService: persist constrained profile snapshot
CustomerAgentRuntimeService->>AgentLoop: execute customer-agent turn
AgentLoop-->>CustomerAgentRuntimeService: model response
CustomerAgentRuntimeService->>ResponseNormalizer: normalize reply and handoff
ResponseNormalizer-->>Consumer: structured response
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
includes/REST/SessionController.php (1)
1546-1572: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winRemoving the empty-abilities fallback makes a prompt/allowlist mismatch reachable.
This change correctly lets an admin configure an explicit deny-all
public_chat_allowed_abilities(previously it was silently forced back toknowledge-search). Butbuild_public_chat_system_instruction()unconditionally tells the model "Your only public tool is knowledge-search" regardless of the resolved list. With an empty allowlist now honored end-to-end, the model is instructed to call a tool thatToolDiscovery's deny-all gate will reject every time, producing confusing behavior instead of a clean deny-all experience.🤖 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 `@includes/REST/SessionController.php` around lines 1546 - 1572, The public chat prompt must reflect an explicitly empty abilities allowlist instead of always advertising knowledge-search. Update build_public_chat_system_instruction() to use the resolved abilities from get_public_chat_settings(), producing a deny-all instruction when the list is empty and only describing allowed tools when present; preserve the existing allowlist enforcement.includes/Core/Database.php (1)
820-849: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winLog and continue when
managed_profile_keyuniqueness cannot be enforced.
ensure_managed_profile_key_unique_index()returnsfalsewhen non-unique duplicate profile keys exist, butinstall()returns beforeupdate_option( self::DB_VERSION_OPTION, self::DB_VERSION, true ). Since the idempotency check only skips when the stored version equals19.8.0, lateradmin_initactivation calls still run the full multi-tabledbDelta()before exiting again, without leaving the admin informed why the install is failing or skipped. Log a clear schema-repair message and continue recording the DB version so future requests don’t repeatedly perform the migration work.🤖 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 `@includes/Core/Database.php` around lines 820 - 849, The install flow around ensure_managed_profile_key_unique_index() should log a clear schema-repair message when uniqueness cannot be enforced, then continue rather than returning early. Ensure update_option( self::DB_VERSION_OPTION, self::DB_VERSION, true ) still executes so subsequent requests skip the repeated migration work, while preserving the existing behavior when index enforcement succeeds.
🧹 Nitpick comments (7)
tests/SdAiAgent/Services/CustomerAgentRuntimeServiceTest.php (4)
425-431: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winTwo of the five forbidden keys aren't exercised.
apply_consumer_policy_narrowing()deniessystem_instruction,system_prompt,client_abilities,attachments, andtool_calls, but this table omitssystem_instructionandtool_calls— one array entry each in the existing loop.Asserting the exact error code per case rather than just the
forbidden_prefix would also stop a mis-mapped rejection from passing silently.🤖 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 `@tests/SdAiAgent/Services/CustomerAgentRuntimeServiceTest.php` around lines 425 - 431, Update the forbidden-context cases in CustomerAgentRuntimeServiceTest to include entries for system_instruction and tool_calls, matching the keys denied by apply_consumer_policy_narrowing(). Strengthen the loop assertions to verify each case’s exact expected forbidden error code rather than only checking the forbidden_ prefix.
59-63: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winClean up tombstones for every tracked profile key, not just
self::INTEGRATION.Line 59 hardcodes the service's private tombstone naming (
REMOVED_PROFILE_OPTION_PREFIXplushash('sha256', 'integration|' . $key)) for one constant. It covers today's tests, but any future test that callsremove_profile()on a different key leaks a tombstone, and becauseresolve_integration()checksis_removed_profile()first, the leak surfaces as a confusingprofile_removed(410) in an unrelated test.Since
$managed_profile_keysis already tracked, folding the tombstone delete into that loop makes cleanup self-maintaining.♻️ Derive cleanup from the tracked keys
- delete_option( 'sd_ai_agent_customer_agent_removed_profile_' . hash( 'sha256', 'integration|' . self::INTEGRATION ) ); - foreach ( $this->managed_profile_keys as $profile_key ) { + foreach ( array_unique( array_merge( $this->managed_profile_keys, array( self::INTEGRATION ) ) ) as $profile_key ) { + delete_option( 'sd_ai_agent_customer_agent_removed_profile_' . hash( 'sha256', 'integration|' . $profile_key ) ); Agent::delete_managed_customer_profile( $profile_key ); }🤖 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 `@tests/SdAiAgent/Services/CustomerAgentRuntimeServiceTest.php` around lines 59 - 63, Update the teardown cleanup around managed_profile_keys to delete each tracked profile’s tombstone within the existing loop, deriving the option name with the service’s established tombstone prefix and hash format; remove the hardcoded self::INTEGRATION deletion, then retain managed profile deletion and reset the tracking array.
470-479: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winOnly the happy path of handoff validation is covered.
This pins the valid-intent round trip, but
normalise_handoff()'s rejection rules are untested: an intent outside the four-value allowlist, a missing/emptyreason, and a non-arrayhandoffmust all yield nohandoffkey in the DTO. A plain non-JSON reply (the documented backward-compatible path) is also unasserted.Those are the branches that keep unvalidated model output out of the consumer contract, so they're worth pinning.
🤖 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 `@tests/SdAiAgent/Services/CustomerAgentRuntimeServiceTest.php` around lines 470 - 479, Extend the handoff validation tests around inspect_job and normalise_handoff to cover an intent outside the four-value allowlist, missing or empty reason, and non-array handoff; assert each DTO omits the handoff key. Also add a plain non-JSON reply case and assert it remains supported without a handoff entry, while preserving the existing valid-intent assertions.
206-220: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse keys that normalize to the same slug prefix.
managed-slug-a_bandmanaged-slug-a-balready produce distinctsanitize_title()prefixes because underscores are preserved in WordPress title sanitization, so the hash suffix is not the factor making this test pass. Use two keys that collapse to the samesanitize_title()output so the test actually guards collision resistance.🤖 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 `@tests/SdAiAgent/Services/CustomerAgentRuntimeServiceTest.php` around lines 206 - 220, Update the test around ensure_profile and Agent::get_by_managed_profile_key to use two managed profile keys whose sanitize_title() results are identical, such as variants differing only by characters WordPress removes or normalizes. Keep the existing assertions verifying both profiles are created, retrieved, and receive different agent slugs.includes/Services/CustomerAgentRuntimeService.php (3)
1371-1378: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win
drifthas two incompatible shapes across the managed and legacy paths.The managed branch returns
driftwithsafety_envelope_versionandoperator_resources_missing(Lines 371-374); this legacy branch returns onlylegacy_registration. Sinceprofile_status()is an integration-facing contract typed loosely asarray<string,mixed>, a consumer written against the managed shape hits undefined indexes on a legacy profile.Emitting the full key set from both branches (with
legacy_registrationas an additional flag) keeps the response shape stable.🤖 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 `@includes/Services/CustomerAgentRuntimeService.php` around lines 1371 - 1378, The legacy response construction in CustomerAgentRuntimeService must emit the same drift keys as the managed branch. Update the drift array in profile_status() to include safety_envelope_version and operator_resources_missing with the corresponding legacy-path values, while retaining legacy_registration as an additional flag.
346-357: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winN+1 collection lookups run on every customer request, including job polling.
profile_status()is reached fromresolve_integration()(Line 1049), soenqueue_turn,create_or_recover_conversation,inspect_job,cancel_job,close_conversation, andprocess_jobeach issue oneKnowledgeDatabase::get_collection_by_slug()query per approved collection — andget_collection_by_slug()is an uncached direct$wpdb->get_row(includes/Knowledge/KnowledgeDatabase.php lines 175-193). Consumers pollinspect_jobin a loop, so this multiplies.Consider a single batched lookup for the availability probe, and/or restricting the availability probe to the write paths (
ensure_profile,profile_status) rather than every read.🤖 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 `@includes/Services/CustomerAgentRuntimeService.php` around lines 346 - 357, Replace the per-collection KnowledgeDatabase::get_collection_by_slug() calls in profile_status() with a single batched availability lookup, or limit this availability validation to the write paths ensure_profile() and profile_status() so read and job-polling flows avoid repeated queries. Preserve the existing customer_collections_not_approved and collections_unavailable reason behavior.
1255-1281: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win
abilitiesis validated then discarded, andcollectionsis uncapped.Two gaps in the spec contract:
- Lines 1265-1281 validate
$spec['abilities']againstSAFE_ABILITIES, but the normalized spec never carries it and provisioning always writesself::SAFE_ABILITIES(Line 207). A consumer passing'abilities' => array()is told nothing and silently gets knowledge-search. Either honour the narrowing or reject the key outright, so the validation isn't misleading.- Line 1256 accepts an unbounded
collectionslist. Sinceprofile_status()probes each approved slug individually, a large list turns every customer request into a proportionally large query burst. A modest cap here would bound that.🤖 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 `@includes/Services/CustomerAgentRuntimeService.php` around lines 1255 - 1281, Update the customer profile normalization flow around $profile_version, $collections, and $spec['abilities'] so validated abilities are either preserved and used by provisioning instead of always writing self::SAFE_ABILITIES, or the abilities key is rejected rather than ignored. Add a finite maximum for the sanitized collections list and return the existing invalid-spec error when it exceeds that limit, keeping valid lists unchanged.
🤖 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 `@includes/Services/CustomerAgentRuntimeService.php`:
- Around line 1049-1055: Remove readiness enforcement from resolve_integration()
so read and cancellation paths such as find_owned_job(), inspect_job(), and
cancel_job() can resolve existing integrations despite profile drift. Keep
validation limited to resolving a valid, non-removed integration, and apply
profile_status readiness checks only when accepting new work in enqueue_turn()
or create_or_recover_conversation().
- Around line 875-885: Remove the integration-wide lock from the normal enqueue
and job-processing paths around acquire_integration_lock, process_job_locked,
and reschedule_locked_job, since idempotency and claim_queued_job already
provide their required coordination. Retain exclusive locking only around
lifecycle-mutation methods such as ensure_profile, disable_profile, and
remove_profile; if a lock remains necessary in these paths, use a 0–1 second
timeout so live requests fail fast rather than waiting behind another customer’s
provider turn.
- Around line 1727-1734: Update the JSON handling in CustomerAgentRuntimeService
so any decoded array lacking a usable string display_text, including JSON arrays
or alternate-key payloads, replaces the raw reply with the established generic
customer-safe fallback message. Preserve the existing display_text extraction
and handoff normalization when display_text is valid.
- Around line 1163-1185: The acquire_integration_lock method currently relies on
MySQL-specific GET_LOCK semantics that are not valid on SQLite or other
supported backends. Replace this advisory-lock implementation with the project’s
backend-agnostic lifecycle guard, or explicitly enforce and document MySQL-only
support if non-MySQL databases are unsupported, while preserving the busy
WP_Error behavior and lock-release contract.
- Around line 1318-1320: Remove the duplicate `@phpstan-param` annotation for
$approved_collections in the PHPDoc block, keeping one declaration with the
existing list<string> type.
In `@tests/SdAiAgent/Services/CustomerAgentRuntimeServiceTest.php`:
- Around line 529-545: Fix the managed_profile_spec() fixture so profiles are
ready during tests by either seeding an active support-docs knowledge collection
in set_up() or overriding collections to an empty list in the affected tests.
Ensure ensure_profile() succeeds and enqueue_turn() can run before
remove_profile() validates owned runtime records.
---
Outside diff comments:
In `@includes/Core/Database.php`:
- Around line 820-849: The install flow around
ensure_managed_profile_key_unique_index() should log a clear schema-repair
message when uniqueness cannot be enforced, then continue rather than returning
early. Ensure update_option( self::DB_VERSION_OPTION, self::DB_VERSION, true )
still executes so subsequent requests skip the repeated migration work, while
preserving the existing behavior when index enforcement succeeds.
In `@includes/REST/SessionController.php`:
- Around line 1546-1572: The public chat prompt must reflect an explicitly empty
abilities allowlist instead of always advertising knowledge-search. Update
build_public_chat_system_instruction() to use the resolved abilities from
get_public_chat_settings(), producing a deny-all instruction when the list is
empty and only describing allowed tools when present; preserve the existing
allowlist enforcement.
---
Nitpick comments:
In `@includes/Services/CustomerAgentRuntimeService.php`:
- Around line 1371-1378: The legacy response construction in
CustomerAgentRuntimeService must emit the same drift keys as the managed branch.
Update the drift array in profile_status() to include safety_envelope_version
and operator_resources_missing with the corresponding legacy-path values, while
retaining legacy_registration as an additional flag.
- Around line 346-357: Replace the per-collection
KnowledgeDatabase::get_collection_by_slug() calls in profile_status() with a
single batched availability lookup, or limit this availability validation to the
write paths ensure_profile() and profile_status() so read and job-polling flows
avoid repeated queries. Preserve the existing customer_collections_not_approved
and collections_unavailable reason behavior.
- Around line 1255-1281: Update the customer profile normalization flow around
$profile_version, $collections, and $spec['abilities'] so validated abilities
are either preserved and used by provisioning instead of always writing
self::SAFE_ABILITIES, or the abilities key is rejected rather than ignored. Add
a finite maximum for the sanitized collections list and return the existing
invalid-spec error when it exceeds that limit, keeping valid lists unchanged.
In `@tests/SdAiAgent/Services/CustomerAgentRuntimeServiceTest.php`:
- Around line 425-431: Update the forbidden-context cases in
CustomerAgentRuntimeServiceTest to include entries for system_instruction and
tool_calls, matching the keys denied by apply_consumer_policy_narrowing().
Strengthen the loop assertions to verify each case’s exact expected forbidden
error code rather than only checking the forbidden_ prefix.
- Around line 59-63: Update the teardown cleanup around managed_profile_keys to
delete each tracked profile’s tombstone within the existing loop, deriving the
option name with the service’s established tombstone prefix and hash format;
remove the hardcoded self::INTEGRATION deletion, then retain managed profile
deletion and reset the tracking array.
- Around line 470-479: Extend the handoff validation tests around inspect_job
and normalise_handoff to cover an intent outside the four-value allowlist,
missing or empty reason, and non-array handoff; assert each DTO omits the
handoff key. Also add a plain non-JSON reply case and assert it remains
supported without a handoff entry, while preserving the existing valid-intent
assertions.
- Around line 206-220: Update the test around ensure_profile and
Agent::get_by_managed_profile_key to use two managed profile keys whose
sanitize_title() results are identical, such as variants differing only by
characters WordPress removes or normalizes. Keep the existing assertions
verifying both profiles are created, retrieved, and receive different agent
slugs.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 44e85667-c350-43dd-bae6-32141ab85ab3
📒 Files selected for processing (18)
includes/Abilities/KnowledgeAbilities.phpincludes/Contracts/CustomerAgentRuntimeInterface.phpincludes/Core/AgentLoop.phpincludes/Core/CustomerAgentPromptComposer.phpincludes/Core/Database.phpincludes/Models/Agent.phpincludes/Models/CustomerAgentRuntimeRepository.phpincludes/Models/DTO/AgentRow.phpincludes/REST/SessionController.phpincludes/Services/CustomerAgentRuntimeService.phpincludes/Tools/ToolDiscovery.phptests/SdAiAgent/Abilities/KnowledgeAbilitiesTest.phptests/SdAiAgent/Core/CustomerAgentPromptComposerTest.phptests/SdAiAgent/Core/DatabaseSchemaTest.phptests/SdAiAgent/Models/AgentTest.phptests/SdAiAgent/REST/PublicChatControllerTest.phptests/SdAiAgent/Services/CustomerAgentRuntimeServiceTest.phptests/SdAiAgent/Tools/ToolDiscoveryTest.php
|
CLAIM_RELEASED reason=worker_complete runner=superdav42 ts=2026-07-24T20:33:55Z aidevops_version=3.32.180 opencode_version=1.18.4 |
CI repair feedback routed to issue #2321This worker PR had terminal failed CI checks. The check details have been appended Terminal failed checks: Closed by deterministic merge pass (pulse-merge.sh). |
Orphan recovery PR — worker pushed this branch but exited before opening a PR.
Branch
feature/auto-20260724-125342-gh2321was pushed by headless worker sessionissue-2321which released asworker_branch_orphan. This PR was auto-created by the orphan-recovery path (GH#20819) so the change can land via the normal review and merge pipeline.Resolves #2321
aidevops.sh v3.32.180 automated scan.
Summary by CodeRabbit
New Features
Bug Fixes
Database