Skip to content

feat(opencode): show Judgment Day rows in profiles#920

Open
ninjoan wants to merge 3 commits into
Gentleman-Programming:mainfrom
ninjoan:feat/jd-profiles-screens
Open

feat(opencode): show Judgment Day rows in profiles#920
ninjoan wants to merge 3 commits into
Gentleman-Programming:mainfrom
ninjoan:feat/jd-profiles-screens

Conversation

@ninjoan

@ninjoan ninjoan commented Jun 17, 2026

Copy link
Copy Markdown

🔗 Linked Issue

Closes #907


🏷️ PR Type

What kind of change does this PR introduce?

  • type:bug — Bug fix (non-breaking change that fixes an issue)
  • type:feature — New feature (non-breaking change that adds functionality)
  • type:docs — Documentation only
  • type:refactor — Code refactoring (no functional changes)
  • type:chore — Build, CI, or tooling changes
  • type:breaking-change — Breaking change (fix or feature that changes existing behavior)

📝 Summary

  • Shows Judgment Day assignment rows in the OpenCode SDD profile model picker.
  • Adds profile-create labels/counts for combined SDD + Judgment Day assignment rows.
  • Keeps this PR focused on the visible profile configuration surface; state/persistence follow in the next slice.

📂 Changes

File / Area What Changed
internal/tui/screens/model_picker.go Includes JD rows in profile model picker mode.
internal/tui/screens/profile_create.go Updates profile create copy/count behavior for combined SDD + JD assignments.
internal/tui/screens/*_test.go Adds regression coverage for visible JD rows and option counts.

🧪 Test Plan

Focused tests

go test ./internal/tui/...
go test ./internal/components/sdd ./internal/cli ./internal/tui/...
  • Unit tests pass (go test ./internal/tui/...)
  • Focused integration package tests pass (go test ./internal/components/sdd ./internal/cli ./internal/tui/...)
  • E2E tests pass (cd e2e && ./docker-test.sh) — not run; TUI-only slice
  • Manually tested locally from the Gentle AI TUI profile flow

🤖 Automated Checks

The following checks run automatically on this PR:

Check Status Description
Check PR Cognitive Load PR should stay within 400 changed lines (additions + deletions) or use size:exception
Check Issue Reference PR body must contain Closes/Fixes/Resolves #N
Check Issue Has status:approved Linked issue must have been approved before work began
Check PR Has type:* Label Exactly one type:* label must be applied
Unit Tests go test ./... must pass
E2E Tests cd e2e && ./docker-test.sh must pass

✅ Contributor Checklist

  • PR is linked to an issue with status:approved
  • PR stays within 400 changed lines, or I have requested/obtained maintainer-applied size:exception with rationale documented
  • I have added the appropriate type:* label to this PR — maintainer label may be required because contributor token cannot label repo items
  • Unit tests pass (go test ./internal/tui/...)
  • E2E tests pass (cd e2e && ./docker-test.sh) — not run; TUI-only slice
  • I have updated documentation if necessary — documentation follows in a separate slice
  • My commits follow Conventional Commits format
  • My commits do not include Co-Authored-By trailers

💬 Notes for Reviewers

This is the first TUI slice after upstream added profile-scoped Judgment Day runtime/CLI support. It makes the JD slots visible in the OpenCode SDD Profile model picker. A follow-up slice will cover TUI state persistence/clear/default behavior, then docs.

Please add the type:feature label if GitHub does not let the contributor apply it.

Summary by CodeRabbit

  • New Features

    • Profile creation now supports assigning optional Judgment Day (JD) agents in addition to standard agents.
    • Updated picker help to include a backspace: clear hint for removing the currently selected assignment.
  • Bug Fixes

    • Improved keyboard handling in the picker: Up/Down and enter navigation skip the non-selectable separator row, and separator selection becomes a no-op.
    • When no model providers are available, Enter behavior now varies by cursor position (including correct continue/back flow).
    • Backspace clears the selected JD assignment (and other selected picker assignments) without affecting others.
  • Documentation

    • Adjusted UI wording from “Phase assignments” to “Model assignments” in profile confirmation.

@ninjoan

ninjoan commented Jun 17, 2026

Copy link
Copy Markdown
Author

Thanks for approving #907. I don't have permission to apply labels from this account, so this PR needs the type:feature label from a maintainer for the PR validation check to pass.

@Alan-TheGentleman Alan-TheGentleman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey @ninjoan, really nice work here. The design is clean: having ModelPickerRowsForProfile() delegate to ModelPickerRows() means profiles reuse the global row contract and the already-working apply/nav logic, so this stays low risk. Test coverage is solid, keeping JD out of "Set all SDD phases" is the right call (and tested), and the empty-providers option count fix (1 to 2) is a nice catch that aligns the count with the two options the screen already renders.

One change before merge: ClearModelPickerAssignment is exported and has two tests, but it has zero production callers and no key binding or help text exposes a clear action. As it stands it is dead code, and the tests give false confidence that clearing works in the UI when it is not reachable.

Two ways to resolve it:

  • Wire it into the phase-list key handler (e.g. a backspace/d binding) and add it to the help text, so the feature is actually usable, or
  • Drop the function and its two tests until the PR that wires it up.

Verified locally on top of current main: build, tests, gofmt, and vet are all clean, and it merges cleanly. It complements the profile-scoped JD backend from 7620986 rather than conflicting with it. Once the dead-code point is sorted this is good to merge and will close #907.

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR extends the Profile Create/Edit TUI flow to support Judgment Day (JD) agent model assignments. ModelPickerRowsForProfile now returns the full row list including the JD separator and JD agent rows. A new ClearModelPickerAssignment helper deletes assignments by row index. Keyboard handling in model.go adds Backspace support for clearing JD assignments in step 1, centralizes separator-skip logic via shouldSkipModelPickerSeparator, and updates confirmProfileCreate to conditionally build OrchestratorModel and PhaseAssignments. UI copy and option count logic are adjusted accordingly.

Changes

Profile Create/Edit: JD Agent Assignment Support

Layer / File(s) Summary
ModelPicker profile mode: JD rows and ClearModelPickerAssignment
internal/tui/screens/model_picker.go, internal/tui/screens/model_picker_test.go
ModelPickerRowsForProfile now delegates to the full ModelPickerRows output (including JD separator and agents). ClearModelPickerAssignment is added to delete assignments by selected row index, handling orchestrator, SDD, AllPhases, separator (no-op), and JD rows. Renderer updates title to "SDD Phases & JD Agents" in profile mode, uses formatAssignmentLabel for JD rows, and adds a "backspace: clear" hint. Tests consolidated into a single TestModelPickerRowsForProfile verifying JD row presence and separator index.
Profile create screen: option count, labels, and docs
internal/tui/screens/profile_create.go, internal/tui/screens/profile_create_test.go
ProfileCreateOptionCount for step 1 returns 2 when AvailableIDs is empty. Confirm step label changed from "Phase assignments" to "Model assignments". Comments updated to describe orchestrator/SDD/JD scope. Tests updated and added for JD row rendering, "backspace: clear" hint, and both empty/non-empty provider option counts.
TUI model: key handling, separator skip, and assignment transfer
internal/tui/model.go, internal/tui/model_test.go
Backspace in step 1 phase-list mode calls ClearModelPickerAssignment for non-separator rows. shouldSkipModelPickerSeparator centralizes the separator-skip predicate for both the main picker and Profile Create step 1. confirmProfileCreate routes Enter by cursor position when AvailableIDs is empty and conditionally constructs OrchestratorModel plus PhaseAssignments (excluding the orchestrator key). Three new regression tests and updated existing tests cover these paths.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • #907 — This PR directly implements the TUI portion of that feature request: profile-scoped JD agent row display, assignment, clearing, and transfer into ProfileDraft.
  • #725 — The PR addresses two issues: JD agent effort-label display by using formatAssignmentLabel on JD rows, and corrected JD assignment transfer into PhaseAssignments to ensure the orchestrator has complete JD agent model information.

Suggested labels

type:feature

Suggested reviewers

  • Alan-TheGentleman
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.46% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(opencode): show Judgment Day rows in profiles' accurately summarizes the main feature added—making JD rows visible in the profile model picker interface.
Linked Issues check ✅ Passed The PR implements the TUI visibility requirements from issue #907: profiles now show JD slots (jd-judge-a, jd-judge-b, jd-fix-agent) during creation/editing with proper option counting and assignment clearing via backspace.
Out of Scope Changes check ✅ Passed All changes are scoped to TUI visibility for JD rows in profiles. No out-of-scope modifications to state management, persistence, or global defaults are present, consistent with the PR's stated focus.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@ninjoan

ninjoan commented Jun 17, 2026

Copy link
Copy Markdown
Author

Thanks for the clear review. I went with option 1 and wired the clear action into the production profile model-assignment flow.

What changed:

  • backspace now clears the selected profile assignment from the phase-list step.
  • The profile model step help text now exposes backspace: clear.
  • Empty-provider Continue with defaults / Back now follows the visible UI contract.
  • Separator rows are ignored/skipped instead of opening provider selection.
  • Added production-path tests through Model.Update, not just helper-level tests.

Validation:

  • go test ./internal/tui -run 'TestProfileCreate(EmptyProviderEnterContinuesAndBacksOut|SeparatorIsIgnoredAndSkipped|BackspaceClearsSelectedJDAssignment)'
  • go test ./internal/tui/screens -run 'Test(RenderProfileCreate_Step1_ShowsJDRowsAssignmentAndClearHelp|ProfileCreateOptionCount_Step1EmptyProvidersIncludesContinueAndBack|ProfileCreateOptionCount_Step1IncludesJDRows|SeparatorRowIdx_Value|ModelPickerRowsForProfile)'
  • go test ./internal/tui/...
  • git diff --check origin/main

The effective diff is 355 changed lines, still under the 400-line budget.

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/tui/screens/model_picker.go (1)

680-688: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Back-option copy is incorrect in profile flow when providers are unavailable.

At Line 687, the fallback option label says ← Back to SDD mode, but in profile create step-1 the back path returns to profile flow (step 0 or profile list), not SDD mode. This is misleading UX.

Suggested fix
-		b.WriteString(renderOptions([]string{"Continue with defaults", "← Back to SDD mode"}, cursor))
+		backLabel := "← Back to SDD mode"
+		if state.ForProfile {
+			backLabel = "← Back"
+		}
+		b.WriteString(renderOptions([]string{"Continue with defaults", backLabel}, cursor))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/tui/screens/model_picker.go` around lines 680 - 688, The back option
label in the renderOptions call is hardcoded as "← Back to SDD mode", but when
this screen appears during profile creation (step 1), the back action returns to
the profile flow, not to SDD mode. Update the second string in the renderOptions
array to accurately reflect that the back option returns to the profile flow or
profile list instead of SDD mode, so users understand where the back button will
take them.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@internal/tui/screens/model_picker.go`:
- Around line 680-688: The back option label in the renderOptions call is
hardcoded as "← Back to SDD mode", but when this screen appears during profile
creation (step 1), the back action returns to the profile flow, not to SDD mode.
Update the second string in the renderOptions array to accurately reflect that
the back option returns to the profile flow or profile list instead of SDD mode,
so users understand where the back button will take them.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ad7a6e66-b04f-4423-8815-eb630753a38d

📥 Commits

Reviewing files that changed from the base of the PR and between 2eed5a1 and 064f21e.

📒 Files selected for processing (6)
  • internal/tui/model.go
  • internal/tui/model_test.go
  • internal/tui/screens/model_picker.go
  • internal/tui/screens/model_picker_test.go
  • internal/tui/screens/profile_create.go
  • internal/tui/screens/profile_create_test.go

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/tui/screens/model_picker.go (1)

669-672: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Redundant conditional branches — title is identical in both.

Both branches of the if state.ForProfile conditional assign the same string to title. This appears to be leftover from a refactor where the profile mode title was updated to match the non-profile title.

♻️ Suggested simplification
-	title := "Assign Models to SDD Phases & JD Agents"
-	if state.ForProfile {
-		title = "Assign Models to SDD Phases & JD Agents"
-	}
+	title := "Assign Models to SDD Phases & JD Agents"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/tui/screens/model_picker.go` around lines 669 - 672, The title
assignment in model_picker.go contains a redundant conditional branch where both
the initial assignment and the if state.ForProfile block assign the identical
string value "Assign Models to SDD Phases & JD Agents" to the title variable.
Remove the entire if state.ForProfile conditional block and keep only the
initial title assignment statement, since both branches produce the same result
making the condition unnecessary.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@internal/tui/screens/model_picker.go`:
- Around line 669-672: The title assignment in model_picker.go contains a
redundant conditional branch where both the initial assignment and the if
state.ForProfile block assign the identical string value "Assign Models to SDD
Phases & JD Agents" to the title variable. Remove the entire if state.ForProfile
conditional block and keep only the initial title assignment statement, since
both branches produce the same result making the condition unnecessary.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6d57a15e-7082-4575-9b4d-4eefe171c2bf

📥 Commits

Reviewing files that changed from the base of the PR and between 064f21e and e792694.

📒 Files selected for processing (2)
  • internal/tui/model.go
  • internal/tui/screens/model_picker.go

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.

feat(opencode): allow SDD profiles to configure Judgment Day models

2 participants