feat(FN-2597): merge fusion/fn-2597 (auto-resolved)
- feat(FN-2597): complete Step 4 — add docs update and changeset - test(FN-2597): complete Step 2 — align dashboard tests with reviewer labels - feat(FN-2597): complete Step 1 — rename validator UI labels to reviewer
This commit is contained in:
5
.changeset/rename-validator-to-reviewer-ui.md
Normal file
5
.changeset/rename-validator-to-reviewer-ui.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@runfusion/fusion": patch
|
||||
---
|
||||
|
||||
Rename "Validator" to "Reviewer" across all dashboard UI labels and descriptions.
|
||||
@@ -112,7 +112,7 @@ Defaults from `DEFAULT_PROJECT_SETTINGS`; key scope from `PROJECT_SETTINGS_KEYS`
|
||||
| `validatorModelId` | `string` | `undefined` | Model ID for plan/code reviewers. |
|
||||
| `validatorFallbackProvider` | `string` | `undefined` | Fallback provider for reviewers. |
|
||||
| `validatorFallbackModelId` | `string` | `undefined` | Fallback model ID for reviewers. |
|
||||
| `modelPresets` | `ModelPreset[]` | `[]` | Reusable executor/validator model presets. |
|
||||
| `modelPresets` | `ModelPreset[]` | `[]` | Reusable executor/reviewer model presets. |
|
||||
| `autoSelectModelPreset` | `boolean` | `false` | Auto-select presets by task size. |
|
||||
| `defaultPresetBySize` | `{ S?: string; M?: string; L?: string }` | `{}` | Mapping for `S`/`M`/`L` → preset ID. |
|
||||
| `autoResolveConflicts` | `boolean` | `true` | Enable automatic merge conflict resolution. |
|
||||
|
||||
@@ -200,7 +200,7 @@ export function AgentLogViewer({
|
||||
}
|
||||
if (hasValidatorOverride) {
|
||||
providers.push({
|
||||
role: "Validator",
|
||||
role: "Reviewer",
|
||||
provider: validatorModel!.provider!,
|
||||
modelId: validatorModel!.modelId,
|
||||
});
|
||||
@@ -307,7 +307,7 @@ export function AgentLogViewer({
|
||||
)}
|
||||
</div>
|
||||
<div className="agent-log-model-group">
|
||||
<span className="agent-log-model-label">Validator:</span>
|
||||
<span className="agent-log-model-label">Reviewer:</span>
|
||||
{hasValidatorOverride ? (
|
||||
<span className="agent-log-model-value">
|
||||
<ProviderIcon provider={validatorModel.provider!} size="sm" />
|
||||
|
||||
@@ -701,7 +701,7 @@ export function ListView({
|
||||
models={availableModels}
|
||||
value={validatorModel}
|
||||
onChange={setValidatorModel}
|
||||
label="Validator Model"
|
||||
label="Reviewer Model"
|
||||
noChangeValue="__no_change__"
|
||||
noChangeLabel="No change"
|
||||
favoriteProviders={favoriteProviders}
|
||||
|
||||
@@ -2395,7 +2395,7 @@ export function MissionManager({ isOpen, isInline = false, onClose, addToast, pr
|
||||
</span>
|
||||
<span className="mission-validation-round__feature">{round.featureTitle}</span>
|
||||
<span className="mission-validation-round__attempts">
|
||||
impl #{round.implementationAttempt} · validator #{round.validatorAttempt}
|
||||
impl #{round.implementationAttempt} · reviewer #{round.validatorAttempt}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@ export function ModelSelectionModal({
|
||||
<div className="task-detail-section">
|
||||
<div className="inline-create-model-row">
|
||||
<label htmlFor="model-selection-validator" className="inline-create-model-label">
|
||||
Validator Model
|
||||
Reviewer Model
|
||||
</label>
|
||||
<span
|
||||
className={`model-badge ${hasValidatorOverride ? "model-badge-custom" : "model-badge-default"}`}
|
||||
@@ -247,11 +247,11 @@ export function ModelSelectionModal({
|
||||
</span>
|
||||
<CustomModelDropdown
|
||||
id="model-selection-validator"
|
||||
label="Validator Model"
|
||||
label="Reviewer Model"
|
||||
value={validatorValue}
|
||||
onChange={handleValidatorChange}
|
||||
models={models}
|
||||
placeholder="Select validator model…"
|
||||
placeholder="Select reviewer model…"
|
||||
favoriteProviders={favoriteProviders}
|
||||
onToggleFavorite={onToggleFavorite}
|
||||
favoriteModels={favoriteModels}
|
||||
|
||||
@@ -115,7 +115,7 @@ function selectionsEqual(a: ModelSelection, b: ModelSelection): boolean {
|
||||
function getSuccessToastMessage(target: "executor" | "validator" | "planning", selection: ModelSelection): string {
|
||||
const labels: Record<string, string> = {
|
||||
executor: "Executor",
|
||||
validator: "Validator",
|
||||
validator: "Reviewer",
|
||||
planning: "Planning",
|
||||
};
|
||||
const label = labels[target] || target;
|
||||
@@ -480,7 +480,7 @@ export function ModelSelectorTab({ task, addToast, onTaskUpdated, settings }: Mo
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="validatorModel">Validator Model</label>
|
||||
<label htmlFor="validatorModel">Reviewer Model</label>
|
||||
<div className="model-selector-current">
|
||||
{validatorUsingDefault ? (
|
||||
<span className="model-badge model-badge-default">
|
||||
@@ -495,12 +495,12 @@ export function ModelSelectorTab({ task, addToast, onTaskUpdated, settings }: Mo
|
||||
</div>
|
||||
<CustomModelDropdown
|
||||
id="validatorModel"
|
||||
label="Validator Model"
|
||||
label="Reviewer Model"
|
||||
value={validatorValue}
|
||||
onChange={handleValidatorChange}
|
||||
models={availableModels}
|
||||
disabled={isSaving}
|
||||
placeholder="Select validator model…"
|
||||
placeholder="Select reviewer model…"
|
||||
favoriteProviders={favoriteProviders}
|
||||
onToggleFavorite={handleToggleFavorite}
|
||||
favoriteModels={favoriteModels}
|
||||
|
||||
@@ -1483,7 +1483,7 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
|
||||
}}
|
||||
>
|
||||
{activeModelSubmenu === null ? (
|
||||
// Top-level menu with Plan/Executor/Validator choices
|
||||
// Top-level menu with Plan/Executor/Reviewer choices
|
||||
<div className="model-menu-items">
|
||||
<button
|
||||
type="button"
|
||||
@@ -1527,7 +1527,7 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
|
||||
>
|
||||
<span className="model-menu-item-label">
|
||||
<Brain size={12} style={{ verticalAlign: "middle", marginRight: 6 }} />
|
||||
Validator
|
||||
Reviewer
|
||||
</span>
|
||||
<span className="model-menu-item-value">
|
||||
{hasValidatorOverride
|
||||
@@ -1552,7 +1552,7 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
|
||||
<div className="model-submenu-header">
|
||||
{activeModelSubmenu === "plan" && "Plan Model"}
|
||||
{activeModelSubmenu === "executor" && "Executor Model"}
|
||||
{activeModelSubmenu === "validator" && "Validator Model"}
|
||||
{activeModelSubmenu === "validator" && "Reviewer Model"}
|
||||
</div>
|
||||
<CustomModelDropdown
|
||||
models={loadedModels}
|
||||
|
||||
@@ -887,13 +887,13 @@ export function SettingsModal({
|
||||
},
|
||||
{
|
||||
laneId: "validator",
|
||||
label: "Validator Model",
|
||||
label: "Reviewer Model",
|
||||
globalProviderKey: "validatorGlobalProvider",
|
||||
globalModelKey: "validatorGlobalModelId",
|
||||
projectProviderKey: "validatorProvider",
|
||||
projectModelKey: "validatorModelId",
|
||||
helperText: "AI model used for code and specification review.",
|
||||
fallbackOrder: "Project override → Global validator lane → Global default lane → Automatic resolution",
|
||||
fallbackOrder: "Project override → Global reviewer lane → Global default lane → Automatic resolution",
|
||||
},
|
||||
{
|
||||
laneId: "summarization",
|
||||
@@ -1701,10 +1701,10 @@ export function SettingsModal({
|
||||
<small>Used if the planning model fails due to rate limits or provider overload. Defaults to the global fallback model.</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="validatorFallbackModel">Validator Fallback Model</label>
|
||||
<label htmlFor="validatorFallbackModel">Reviewer Fallback Model</label>
|
||||
<CustomModelDropdown
|
||||
id="validatorFallbackModel"
|
||||
label="Validator Fallback Model"
|
||||
label="Reviewer Fallback Model"
|
||||
models={availableModels}
|
||||
value={form.validatorFallbackProvider && form.validatorFallbackModelId ? `${form.validatorFallbackProvider}/${form.validatorFallbackModelId}` : ""}
|
||||
onChange={(val) => {
|
||||
@@ -1725,7 +1725,7 @@ export function SettingsModal({
|
||||
favoriteModels={favoriteModels}
|
||||
onToggleModelFavorite={handleToggleModelFavorite}
|
||||
/>
|
||||
<small>Used if the validator model fails due to rate limits or provider overload. Defaults to the global fallback model.</small>
|
||||
<small>Used if the reviewer model fails due to rate limits or provider overload. Defaults to the global fallback model.</small>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@@ -1849,10 +1849,10 @@ export function SettingsModal({
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="preset-validator-model">Validator model</label>
|
||||
<label htmlFor="preset-validator-model">Reviewer model</label>
|
||||
<CustomModelDropdown
|
||||
id="preset-validator-model"
|
||||
label="Preset validator model"
|
||||
label="Preset reviewer model"
|
||||
models={availableModels}
|
||||
value={presetDraft.validatorProvider && presetDraft.validatorModelId ? `${presetDraft.validatorProvider}/${presetDraft.validatorModelId}` : ""}
|
||||
onChange={(val) => {
|
||||
|
||||
@@ -977,10 +977,10 @@ export function TaskForm({
|
||||
/>
|
||||
</div>
|
||||
<div className="model-select-row">
|
||||
<label htmlFor="validator-model" className="model-select-label">Validator</label>
|
||||
<label htmlFor="validator-model" className="model-select-label">Reviewer</label>
|
||||
<CustomModelDropdown
|
||||
id="validator-model"
|
||||
label="Validator Model"
|
||||
label="Reviewer Model"
|
||||
value={validatorModel}
|
||||
onChange={(value) => {
|
||||
onPresetModeChange("custom");
|
||||
|
||||
@@ -335,10 +335,10 @@ describe("AgentLogViewer", () => {
|
||||
const header = container.querySelector("[data-testid='agent-log-model-header']");
|
||||
expect(header).toBeTruthy();
|
||||
expect(container.querySelector('[data-provider="openai"]')).toBeTruthy();
|
||||
expect(header!.textContent).not.toContain("Validator:");
|
||||
expect(header!.textContent).not.toContain("Reviewer:");
|
||||
|
||||
fireEvent.click(screen.getByTestId("agent-log-model-expand"));
|
||||
expect(header!.textContent).toContain("Validator:");
|
||||
expect(header!.textContent).toContain("Reviewer:");
|
||||
expect(header!.textContent).toContain("openai/gpt-4o");
|
||||
});
|
||||
|
||||
|
||||
@@ -74,9 +74,9 @@ vi.mock("../ModelSelectionModal", () => ({
|
||||
<div data-testid="modal-props-has-preset-change">{onPresetChange ? "yes" : "no"}</div>
|
||||
<button data-testid="modal-close" onClick={onClose}>Close</button>
|
||||
<button data-testid="modal-select-executor" onClick={() => onExecutorChange("anthropic/claude-sonnet-4-5")}>Select Executor</button>
|
||||
<button data-testid="modal-select-validator" onClick={() => onValidatorChange("openai/gpt-4o")}>Select Validator</button>
|
||||
<button data-testid="modal-select-validator" onClick={() => onValidatorChange("openai/gpt-4o")}>Select Reviewer</button>
|
||||
<button data-testid="modal-clear-executor" onClick={() => onExecutorChange("")}>Clear Executor</button>
|
||||
<button data-testid="modal-clear-validator" onClick={() => onValidatorChange("")}>Clear Validator</button>
|
||||
<button data-testid="modal-clear-validator" onClick={() => onValidatorChange("")}>Clear Reviewer</button>
|
||||
<button data-testid="modal-retry" onClick={onRetry}>Retry</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -2220,7 +2220,7 @@ describe("ListView - Bulk Selection", () => {
|
||||
// Verify the menu has the three options
|
||||
expect(menu.textContent).toContain("Plan");
|
||||
expect(menu.textContent).toContain("Executor");
|
||||
expect(menu.textContent).toContain("Validator");
|
||||
expect(menu.textContent).toContain("Reviewer");
|
||||
});
|
||||
|
||||
describe("ListView Mobile Cards", () => {
|
||||
|
||||
@@ -273,7 +273,7 @@ describe("ModelSelectionModal", () => {
|
||||
"anthropic/claude-sonnet-4-5",
|
||||
);
|
||||
expect(screen.getByTestId("dropdown-label-model-selection-validator").textContent).toBe(
|
||||
"Validator Model",
|
||||
"Reviewer Model",
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ describe("ModelSelectorTab", () => {
|
||||
|
||||
await waitForSelectors();
|
||||
|
||||
expect(screen.getByLabelText("Validator Model")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("Reviewer Model")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("Planning Model")).toBeInTheDocument();
|
||||
expect(screen.queryByText("Save")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Reset")).not.toBeInTheDocument();
|
||||
@@ -155,7 +155,7 @@ describe("ModelSelectorTab", () => {
|
||||
const executorSection = getSection("Executor Model");
|
||||
expect(within(executorSection!).getByText("Using default")).toBeInTheDocument();
|
||||
|
||||
const validatorSection = getSection("Validator Model");
|
||||
const validatorSection = getSection("Reviewer Model");
|
||||
expect(within(validatorSection!).getByText("Using default")).toBeInTheDocument();
|
||||
|
||||
const planningSection = getSection("Planning Model");
|
||||
@@ -206,7 +206,7 @@ describe("ModelSelectorTab", () => {
|
||||
|
||||
await waitForSelectors();
|
||||
|
||||
const validatorSection = getSection("Validator Model");
|
||||
const validatorSection = getSection("Reviewer Model");
|
||||
expect(within(validatorSection!).getByText("Using default (openai/gpt-4o)")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -365,7 +365,7 @@ describe("ModelSelectorTab", () => {
|
||||
}));
|
||||
});
|
||||
|
||||
await selectOption("Validator Model", "GPT-4o");
|
||||
await selectOption("Reviewer Model", "GPT-4o");
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockUpdateTask).toHaveBeenNthCalledWith(2, "FN-001", expectedModelCall({
|
||||
@@ -441,7 +441,7 @@ describe("ModelSelectorTab", () => {
|
||||
render(<ModelSelectorTab task={taskWithExecutor} addToast={mockAddToast} />);
|
||||
|
||||
await waitForSelectors();
|
||||
await selectOption("Validator Model", "GPT-4o");
|
||||
await selectOption("Reviewer Model", "GPT-4o");
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockUpdateTask).toHaveBeenCalledWith("FN-001", expectedModelCall({
|
||||
@@ -469,7 +469,7 @@ describe("ModelSelectorTab", () => {
|
||||
|
||||
await waitForSelectors();
|
||||
|
||||
await user.click(getSelector("Validator Model"));
|
||||
await user.click(getSelector("Reviewer Model"));
|
||||
await user.click(getUseDefaultOption());
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -517,7 +517,7 @@ describe("ModelSelectorTab", () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getSelector("Executor Model")).toBeDisabled();
|
||||
expect(getSelector("Validator Model")).toBeDisabled();
|
||||
expect(getSelector("Reviewer Model")).toBeDisabled();
|
||||
expect(getSelector("Planning Model")).toBeDisabled();
|
||||
});
|
||||
|
||||
@@ -529,7 +529,7 @@ describe("ModelSelectorTab", () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getSelector("Executor Model")).not.toBeDisabled();
|
||||
expect(getSelector("Validator Model")).not.toBeDisabled();
|
||||
expect(getSelector("Reviewer Model")).not.toBeDisabled();
|
||||
expect(getSelector("Planning Model")).not.toBeDisabled();
|
||||
});
|
||||
});
|
||||
@@ -619,10 +619,10 @@ describe("ModelSelectorTab", () => {
|
||||
render(<ModelSelectorTab task={FAKE_TASK} addToast={mockAddToast} />);
|
||||
|
||||
await waitForSelectors();
|
||||
await selectOption("Validator Model", "GPT-4o");
|
||||
await selectOption("Reviewer Model", "GPT-4o");
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockAddToast).toHaveBeenCalledWith("Validator model set to openai/gpt-4o", "success");
|
||||
expect(mockAddToast).toHaveBeenCalledWith("Reviewer model set to openai/gpt-4o", "success");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -797,7 +797,7 @@ describe("QuickEntryBox", () => {
|
||||
expect(screen.getByTestId("model-nested-menu")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("shows Plan, Executor, and Validator options in model menu", () => {
|
||||
it("shows Plan, Executor, and Reviewer options in model menu", () => {
|
||||
renderQuickEntryBox({});
|
||||
expandQuickEntry();
|
||||
const textarea = screen.getByTestId("quick-entry-input");
|
||||
@@ -837,7 +837,7 @@ describe("QuickEntryBox", () => {
|
||||
expect(screen.getByTestId("custom-model-dropdown-plan model")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("clicking Validator opens submenu with CustomModelDropdown", () => {
|
||||
it("clicking Reviewer opens submenu with CustomModelDropdown", () => {
|
||||
renderQuickEntryBox({});
|
||||
expandQuickEntry();
|
||||
const textarea = screen.getByTestId("quick-entry-input");
|
||||
@@ -913,7 +913,7 @@ describe("QuickEntryBox", () => {
|
||||
expect(planItem.classList.contains("model-menu-item--active")).toBe(true);
|
||||
});
|
||||
|
||||
it("selecting Validator model updates the Validator menu item value", () => {
|
||||
it("selecting Reviewer model updates the Reviewer menu item value", () => {
|
||||
renderQuickEntryBox({});
|
||||
expandQuickEntry();
|
||||
const textarea = screen.getByTestId("quick-entry-input");
|
||||
@@ -928,7 +928,7 @@ describe("QuickEntryBox", () => {
|
||||
// Go back to top-level menu
|
||||
fireEvent.click(screen.getByTestId("model-submenu-back"));
|
||||
|
||||
// Validator menu item should show the selected model
|
||||
// Reviewer menu item should show the selected model
|
||||
const validatorItem = screen.getByTestId("model-menu-validator");
|
||||
expect(validatorItem.textContent).toContain("anthropic/claude-sonnet-4-5");
|
||||
expect(validatorItem.classList.contains("model-menu-item--active")).toBe(true);
|
||||
|
||||
@@ -4891,7 +4891,7 @@ describe("TaskDetailModal", () => {
|
||||
);
|
||||
});
|
||||
|
||||
await user.click(screen.getByLabelText("Validator Model"));
|
||||
await user.click(screen.getByLabelText("Reviewer Model"));
|
||||
await user.click(screen.getByText("GPT-4o"));
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -4909,7 +4909,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByLabelText("Executor Model")).toHaveTextContent("Claude Sonnet 4.5");
|
||||
expect(screen.getByLabelText("Validator Model")).toHaveTextContent("GPT-4o");
|
||||
expect(screen.getByLabelText("Reviewer Model")).toHaveTextContent("GPT-4o");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user