Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ All notable changes to this project are documented in this file.
- Expanded doctor summary coverage to include context resilience subsystem health checks.
- Expanded selftest coverage for model-routing trace persistence and runtime fallback-chain reporting.
- Expanded README guidance with category-driven routing examples and troubleshooting steps for unexpected model selection.
- Expanded routing verification coverage for deterministic trace stability and explicit fallback/no-fallback explain outcomes, and added `/routing` smoke hints in install output.

## v0.2.0 - 2026-02-12

Expand Down
21 changes: 11 additions & 10 deletions IMPLEMENTATION_ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Use this map to avoid overlapping implementations.
| E9 | Conditional Rules Injector | done | High | E1 | bd-1q8, bd-3rj, bd-fo8, bd-2ik | Enforce project conventions with scoped rules |
| E10 | Auto Slash Command Detector | paused | Medium | E1, E8 | TBD | Resume only if intent precision stays high in prototypes |
| E11 | Context-Window Resilience Toolkit | done | High | E4 | bd-2tj, bd-n9y, bd-2t0, bd-18e | Improve long-session stability and recovery |
| E12 | Provider/Model Fallback Visibility | in_progress | Medium | E5 | bd-1jq, bd-298, bd-194 | Explain why model routing decisions happen |
| E12 | Provider/Model Fallback Visibility | done | Medium | E5 | bd-1jq, bd-298, bd-194, bd-2gq | Explain why model routing decisions happen |
| E13 | Browser Automation Profile Switching | planned | Medium | E1 | TBD | Toggle Playwright/agent-browser with checks |
| E14 | Plan-to-Execution Bridge Command | planned | Medium | E2, E3 | TBD | Execute validated plans with progress tracking |
| E15 | Todo Enforcer and Plan Compliance | planned | High | E14 | TBD | Keep execution aligned with approved checklists |
Expand Down Expand Up @@ -172,7 +172,7 @@ Every command-oriented epic must ship all of the following:

## Epic 1 - Config Layering + JSONC Support

**Status:** `done`
**Status:** `paused`
**Priority:** High
**Goal:** Add user/project layered config and JSONC parsing so behavior can be customized per repo without mutating global defaults.
**Depends on:** None
Expand Down Expand Up @@ -439,7 +439,7 @@ Every command-oriented epic must ship all of the following:

## Epic 10 - Auto Slash Command Detector

**Status:** `in_progress`
**Status:** `paused`
**Priority:** Medium
**Goal:** Detect natural-language intent that maps to existing slash commands and optionally execute with guardrails.
**Depends on:** Epic 1, Epic 8
Expand Down Expand Up @@ -499,7 +499,7 @@ Every command-oriented epic must ship all of the following:

## Epic 12 - Provider/Model Fallback Visibility

**Status:** `in_progress`
**Status:** `done`
**Priority:** Medium
**Goal:** Make model routing and provider fallback decisions observable and explainable.
**Depends on:** Epic 5
Expand All @@ -519,12 +519,13 @@ Every command-oriented epic must ship all of the following:
- [x] Subtask 12.3.2: Add examples for category-driven routing outcomes
- [x] Subtask 12.3.3: Add docs for troubleshooting unexpected model selection
- [x] Notes: Added `scripts/routing_command.py`, routed aliases in `opencode.json`, and README examples/troubleshooting for compact explainability workflows.
- [ ] Task 12.4: Verification
- [ ] Subtask 12.4.1: Add tests for deterministic trace output
- [ ] Subtask 12.4.2: Add tests for fallback and no-fallback scenarios
- [ ] Subtask 12.4.3: Add install-test smoke checks
- [ ] Exit criteria: users can explain model/provider selection for every routed task
- [ ] Exit criteria: trace output remains readable in default mode
- [x] Task 12.4: Verification
- [x] Subtask 12.4.1: Add tests for deterministic trace output
- [x] Subtask 12.4.2: Add tests for fallback and no-fallback scenarios
- [x] Subtask 12.4.3: Add install-test smoke checks
- [x] Notes: Expanded `scripts/selftest.py` with deterministic resolution-trace assertions plus fallback/no-fallback routing explain scenarios and added `/routing` smoke hints in `install.sh`.
- [x] Exit criteria: users can explain model/provider selection for every routed task
- [x] Exit criteria: trace output remains readable in default mode

---

Expand Down
2 changes: 2 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ printf " /hooks enable\n"
printf " /hooks doctor --json\n"
printf " /model-routing status\n"
printf " /model-profile status\n"
printf " /routing status\n"
printf " /routing explain --category deep --json\n"
printf " /keyword-mode status\n"
printf " /keyword-mode detect --prompt 'safe-apply deep-analyze investigate this refactor'\n"
printf " /keyword-mode disable-keyword ulw\n"
Expand Down
64 changes: 64 additions & 0 deletions scripts/selftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,70 @@ def run_bg(*args: str) -> subprocess.CompletedProcess[str]:
isinstance(routing_explain_report.get("resolution_trace"), dict),
"routing explain should include structured resolution trace",
)
expect(
routing_explain_report.get("fallback_reason")
== "fallback_unavailable_model_to_category",
"routing explain should report fallback reason for unavailable model scenario",
)

routing_explain_no_fallback = subprocess.run(
[
sys.executable,
str(ROUTING_SCRIPT),
"explain",
"--category",
"quick",
"--available-models",
"openai/gpt-5-mini,openai/gpt-5.3-codex",
"--json",
],
capture_output=True,
text=True,
env=refactor_env,
check=False,
cwd=REPO_ROOT,
)
expect(
routing_explain_no_fallback.returncode == 0,
"routing explain should succeed for no-fallback scenario",
)
routing_explain_no_fallback_report = parse_json_output(
routing_explain_no_fallback.stdout
)
expect(
routing_explain_no_fallback_report.get("fallback_reason") == "none",
"routing explain should report explicit no-fallback reason when first candidate is accepted",
)

deterministic_trace_a = resolve_model_settings(
schema=routing_schema,
requested_category="deep",
user_overrides={"model": "openai/nonexistent"},
system_defaults={
"model": "openai/gpt-5.3-codex",
"temperature": 0.2,
"reasoning": "medium",
"verbosity": "medium",
},
available_models={"openai/gpt-5-mini", "openai/gpt-5.3-codex"},
)
deterministic_trace_b = resolve_model_settings(
schema=routing_schema,
requested_category="deep",
user_overrides={"model": "openai/nonexistent"},
system_defaults={
"model": "openai/gpt-5.3-codex",
"temperature": 0.2,
"reasoning": "medium",
"verbosity": "medium",
},
available_models={"openai/gpt-5-mini", "openai/gpt-5.3-codex"},
)
expect(
deterministic_trace_a.get("resolution_trace")
== deterministic_trace_b.get("resolution_trace"),
"model routing resolution trace should remain deterministic for identical inputs",
)

keyword_report = resolve_prompt_modes(
"Please safe-apply and deep-analyze this migration; ulw can wait.",
Expand Down