-
Notifications
You must be signed in to change notification settings - Fork 487
feature/validate-features #284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature/validate-features #284
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughThis pull request introduces a feature validation system that integrates an AgentService on the server with validation UI controls on the client. A new POST /validate-feature endpoint is added that uses an agent to assess feature implementation status. The UI surfaces validation actions at the board, card, and action levels with loading states and result handling. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant UI as UI Component
participant Hook as Board Actions Hook
participant Client as HTTP Client
participant Server as Features Route
participant Agent as AgentService
User->>UI: Click Validate Feature Button
UI->>Hook: handleValidateFeature(feature)
Hook->>Hook: Mark feature as validating
Hook->>Client: validateFeature(projectPath, featureId)
Client->>Server: POST /api/features/validate-feature
Server->>Server: Load feature from featureLoader
alt Feature Not Found
Server-->>Client: 404 Error
else Feature Found
Server->>Agent: Create session with feature metadata
Server->>Agent: Initialize conversation
Server->>Agent: Send validation prompt
alt Agent Fails
Agent-->>Server: Error response
Server->>Agent: Cleanup session
Server-->>Client: 500 Error
else Agent Succeeds
Agent-->>Server: Text response
Server->>Server: Parse assessment/reasoning/evidence
Server->>Agent: Cleanup session
Server-->>Client: 200 OK with validation result
end
end
Client-->>Hook: Validation result
Hook->>Hook: Update feature metadata
alt Assessment = FULLY_IMPLEMENTED
Hook->>Hook: Move to waiting_approval
end
Hook->>Hook: Clear validating state
Hook-->>UI: Update UI
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
Comment |
Summary of ChangesHello @NomadicDaddy, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request implements a new AI-driven feature validation system for the Kanban board. It enables users to verify the implementation status of backlog features, either individually or in a batch, and automatically transitions fully implemented items to a 'Waiting Approval' state. This enhancement aims to improve workflow efficiency by leveraging AI to assess code against feature descriptions. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
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 valuable feature for validating backlog items against the existing codebase using an AI agent. The implementation is well-structured, with clear separation of concerns between the backend route, UI hooks, and components. The logic for handling both individual and bulk validation is robust, including good UI feedback with loading states and error handling. My review focuses on improving the backend handler's type safety, parsing logic, and error handling to make it even more resilient.
| ) { | ||
| return async (req: any, res: any) => { | ||
| try { | ||
| const { projectPath, featureId }: ValidateFeatureRequest = req.body; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| try { | ||
| await agentService.deleteSession(session.id); | ||
| } catch (cleanupError) { | ||
| console.error('[ValidateFeature] Failed to cleanup session:', cleanupError); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this catch block, you attempt to clean up the agent session. However, if the initial session creation at lines 56-61 failed in a way that session is undefined but no error was thrown, accessing session.id here would cause a TypeError. This would prevent the proper error response from being sent to the client. The same issue exists in the cleanup block on lines 102-106.
You should add a check to ensure session is defined before trying to access its properties, for example by wrapping this try-catch block in an if (session) { ... }.
| const assessmentMatch = response.match( | ||
| /ASSESSMENT:\s*\*{0,2}(FULLY_IMPLEMENTED|PARTIALLY_IMPLEMENTED|NOT_IMPLEMENTED)\*{0,2}/ | ||
| ); | ||
| const reasoningMatch = response.match(/REASONING:\s*\*{0,2}([^\n*]+)\*{0,2}/); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The regex for parsing REASONING is a bit brittle. The character class [^\n*]+ will stop matching at the first newline OR the first asterisk. This means if the reasoning text contains an asterisk (e.g., for emphasis or in a code snippet like *.log), the reasoning will be truncated. It also prevents multi-line reasoning.
A more robust approach would be to match non-greedily until the next section (EVIDENCE:) or a double newline. This would better handle variations in the AI's output. I'd also recommend trimming the result on line 130 (e.g., reasoningMatch?.[1]?.trim()).
| const reasoningMatch = response.match(/REASONING:\s*\*{0,2}([^\n*]+)\*{0,2}/); | |
| const reasoningMatch = response.match(/REASONING:\s*\*{0,2}([\s\S]+?)(?=\n\s*\*{0,2}EVIDENCE:|\n\n|$)/); |
| if (!response.ok) { | ||
| const errorText = await response.text(); | ||
| console.error( | ||
| `[HttpApiClient] POST ${endpoint} failed: ${response.status} ${response.statusText}`, | ||
| errorText | ||
| ); | ||
| throw new Error(`HTTP ${response.status}: ${response.statusText}`); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's great that you've added error handling for non-2xx responses in the post method. This significantly improves the robustness of the API client. This same pattern of checking response.ok and throwing an error should be applied to the get, put, and delete methods as well to ensure consistent error handling across all HTTP requests.
| featureLoader: FeatureLoader, | ||
| agentService: AgentService | ||
| ) { | ||
| return async (req: any, res: any) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| /ASSESSMENT:\s*\*{0,2}(FULLY_IMPLEMENTED|PARTIALLY_IMPLEMENTED|NOT_IMPLEMENTED)\*{0,2}/ | ||
| ); | ||
| const reasoningMatch = response.match(/REASONING:\s*\*{0,2}([^\n*]+)\*{0,2}/); | ||
| const evidenceMatch = response.match(/EVIDENCE:\s*\*{0,2}([\s\S]*?)\*{0,2}(?=\n\n|$)/); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the reasoningMatch regex, this one can be improved. The trailing \*{0,2} could mistakenly consume asterisks that are part of the evidence text. It's safer to remove it from the main pattern and rely on the lookahead and trim() to clean up the result. I'd also recommend trimming the result on line 131 (e.g., evidenceMatch?.[1]?.trim()).
| const evidenceMatch = response.match(/EVIDENCE:\s*\*{0,2}([\s\S]*?)\*{0,2}(?=\n\n|$)/); | |
| const evidenceMatch = response.match(/EVIDENCE:\s*\*{0,2}([\s\S]+?)(?=\n\n|$)/); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (4)
apps/ui/src/lib/http-api-client.ts (2)
165-235: Non‑2xx HTTP responses now throw – verify callers handle this new behavior
post,get,put, andhttpDeletenow:
- Log body text for non‑
okresponses.- Throw
Error("HTTP <status>: <statusText>")instead of returning the parsed JSON body.This is a behavior change from the previous implementation that would return whatever JSON the server sent (often
{ success: false, error: ... }). Any call sites that rely onresult.success/result.errorfor 4xx/5xx responses but do not wrap the call intry/catchwill now see rejected promises instead.Consider:
- Auditing high-traffic and UX-critical callers to ensure they
try/catchthese methods.- Optionally, standardizing on a response envelope (e.g., always returning
{ success, error? }) even for non‑2xx by not throwing, and letting higher layers decide, if that better matches existing patterns.
575-576:features.validateFeaturewiring matches server contractThe new
features.validateFeaturecall correctly posts{ projectPath, featureId }to/api/features/validate-featureand will be typed byFeaturesAPI.validateFeature. For extra clarity and IDE help, you could make the response type explicit:validateFeature: (projectPath: string, featureId: string) => this.post<ReturnType<ElectronAPI['features']>['validateFeature'] extends (...args: any) => Promise<infer R> ? R : unknown>( '/api/features/validate-feature', { projectPath, featureId }, )Optional, current implementation is acceptable.
apps/ui/src/components/views/board-view.tsx (1)
372-381: Column‑aware validation wiring is solid; double‑check interaction with filtering for completed/verified countsUsing
useBoardColumnFeaturesbeforeuseBoardActionsand passinggetColumnFeaturesinto both the actions hook andKanbanBoardcleanly ties validation to the visible column ordering. The newonValidate/onValidateAllBacklogprops are also wired correctly into the board.One behavioral detail to verify:
completedFeaturesandgetColumnFeatures('verified')likely respectsearchQueryand worktree filters. That means:
- Completed features modal and
- The “Archive All Verified” dialog count
may now reflect only the filtered subset rather than all project-wide completed/verified features. If previous UX expected global counts, you may want to source those from the raw feature list instead of the column-filtered view.
Also applies to: 383-405, 1074-1076
apps/ui/src/components/views/board-view/hooks/use-board-actions.ts (1)
43-45: Validation handlers are well‑structured; consider a couple of small hardeningsThe new validation flow in this hook is generally solid:
getColumnFeaturesplumbs column ordering intohandleValidateAllBacklogso bulk validation follows visible board order.handleValidateFeature:
- Marks a per‑feature
metadata["validating-<id>"]flag before calling the API.- Interprets the validation result and, on
FULLY_IMPLEMENTED, moves the feature towaiting_approvaland persists it.- Uses
try/catch/finallyto clear the validating flag even on failures (unless the feature was moved).- Both single and bulk validation are wrapped in
try/catch, so they cooperate correctly with the new throwing HTTP helpers.A few small improvements to consider:
Defensive handling if
validationis unexpectedly missing
Types declarevalidation?, but the code assumes it exists wheneverresponse.successis true:const { validation } = response; // ... validation.assessmentTo avoid a hard runtime failure if the server ever responds with
{ success: true }but novalidation(e.g., a bug or version skew), you could guard:if (!response.validation) { toast.error('Validation failed', { description: 'No validation payload returned.' }); return; } const { validation } = response;Metadata field is purely UI‑local
Usingfeature.metadatato track thevalidating-<id>flag is fine, but it depends on the underlyingFeatureshape tolerating arbitrary metadata. If you later introduce a strongly typedmetadataproperty onFeature, this pattern may need revisiting. For now, it’s acceptable but worth a brief comment near the firstmetadatausage to document that it’s UI-only state.Bulk validation UX
handleValidateAllBacklogalready adds a 1s delay between validations, which is good for rate limiting. If you haven’t already, you may also want to surface an “is validating all” boolean in state (passed asisValidatingAll) to:
- Disable per-card validate buttons during bulk runs.
- Disable the “Validate All” trigger while it’s already running.
From the props on
KanbanCard/CardActions, it looks like you’re partially set up for this; just ensure the state toggling is wired where this handler is invoked.Overall, the structure is good; these are just guardrails to make failure modes clearer and future type evolution smoother.
Also applies to: 74-75, 868-1006, 1028-1029
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (10)
apps/server/src/index.tsapps/server/src/routes/features/index.tsapps/server/src/routes/features/routes/validate-feature.tsapps/ui/src/components/views/board-view.tsxapps/ui/src/components/views/board-view/components/kanban-card/card-actions.tsxapps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsxapps/ui/src/components/views/board-view/hooks/use-board-actions.tsapps/ui/src/components/views/board-view/kanban-board.tsxapps/ui/src/lib/electron.tsapps/ui/src/lib/http-api-client.ts
🧰 Additional context used
🧬 Code graph analysis (5)
apps/server/src/routes/features/routes/validate-feature.ts (1)
apps/server/src/services/feature-loader.ts (1)
FeatureLoader(22-384)
apps/ui/src/components/views/board-view/hooks/use-board-actions.ts (3)
apps/ui/src/store/app-store.ts (1)
Feature(256-272)libs/types/src/feature.ts (1)
Feature(24-58)apps/ui/src/lib/electron.ts (1)
getElectronAPI(720-729)
apps/server/src/index.ts (1)
apps/server/src/routes/features/index.ts (1)
createFeaturesRoutes(18-38)
apps/ui/src/components/views/board-view/kanban-board.tsx (2)
apps/ui/src/lib/utils.ts (1)
cn(5-7)apps/ui/src/components/ui/hotkey-button.tsx (1)
HotkeyButton(169-288)
apps/ui/src/components/views/board-view/components/kanban-card/card-actions.tsx (1)
apps/ui/src/components/ui/button.tsx (1)
Button(108-108)
🔇 Additional comments (9)
apps/server/src/index.ts (1)
147-147: Features routes correctly wired with AgentServicePassing
agentServiceintocreateFeaturesRoutesaligns with the updated route factory and keeps feature validation using the shared AgentService instance. No issues here.apps/server/src/routes/features/index.ts (1)
15-21: Feature validation route is cleanly integrated into the features routerThe route factory’s new
agentServicedependency and the/validate-featurePOST registration (withvalidatePathParams('projectPath')) look consistent with the rest of the features API and server wiring. No issues spotted.Also applies to: 31-35
apps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsx (1)
29-33: Validation props are cleanly threaded through KanbanCardAdding
onValidateandisValidatingAlltoKanbanCardPropsand forwarding them toCardActionsis done cleanly and doesn’t affect existing behavior. This keeps the card component thin and letsCardActionsown the validation UI logic. No issues here.Also applies to: 58-62, 171-189
apps/ui/src/components/views/board-view/components/kanban-card/card-actions.tsx (2)
13-14: LGTM! Props and imports are correctly added.The new
isValidatingAllandonValidateprops are properly typed and integrated into the component signature. The icon imports support the validation UI.Also applies to: 21-21, 34-34, 41-41, 54-54
307-329: LGTM! Validate button implementation is solid.The button correctly:
- Guards against concurrent validation (per-feature and global states)
- Shows appropriate loading indicators
- Prevents event propagation to avoid card selection
- Includes accessibility attributes
apps/ui/src/components/views/board-view/kanban-board.tsx (4)
96-109: LGTM! Loading state management is well-structured.The wrapper correctly:
- Prevents concurrent executions with a guard
- Uses try/finally to ensure state cleanup
- Leverages useCallback for performance
167-196: LGTM! Validate All button has appropriate loading states.The button correctly:
- Shows loading spinner and disabled state during validation
- Updates styling and title text based on state
- Uses semantic icons (CheckCircle/Loader2)
197-208: Verify whether the hotkey should be disabled.The
hotkeyActive={false}prop disables the keyboard shortcut for starting next features, meaning users can only click the button. Was this intentional, or should the hotkey remain active?If the hotkey should be active, apply this change:
🔎 Enable the keyboard shortcut
<HotkeyButton variant="ghost" size="sm" className="h-6 px-2 text-xs text-primary hover:text-primary hover:bg-primary/10" onClick={onStartNextFeatures} hotkey={shortcuts.startNext} - hotkeyActive={false} + hotkeyActive={true} data-testid="start-next-button" >
243-243: LGTM! Props are correctly passed to KanbanCard.The validation callback and loading state are properly propagated to individual cards.
Also applies to: 246-246
| /** | ||
| * Validate feature route - Uses AI agent to check if a feature is already implemented | ||
| */ | ||
|
|
||
| import type { Request, Response } from 'express'; | ||
| import { FeatureLoader } from '../../../services/feature-loader.js'; | ||
| import { AgentService } from '../../../services/agent-service.js'; | ||
| import { getErrorMessage, logError } from '../common.js'; | ||
| import type { Feature } from '@automaker/types'; | ||
|
|
||
| export function createValidateFeatureHandler( | ||
| featureLoader: FeatureLoader, | ||
| agentService: AgentService | ||
| ) { | ||
| return async (req: any, res: any) => { | ||
| try { | ||
| const { projectPath, featureId }: ValidateFeatureRequest = req.body; | ||
|
|
||
| // Load the feature | ||
| const feature = await featureLoader.get(projectPath, featureId); | ||
| if (!feature) { | ||
| return res.status(404).json({ | ||
| success: false, | ||
| error: 'Feature not found', | ||
| }); | ||
| } | ||
|
|
||
| // Create a validation prompt | ||
| const validationPrompt = `Your task is to review this feature and the existing codebase and determine whether or not it has been fully/partially/not implemented. | ||
| Feature Details: | ||
| - Title: ${feature.title} | ||
| - Category: ${feature.category} | ||
| - Description: ${feature.description} | ||
| Please analyze the codebase and provide your assessment in the following format (plain text, no markdown): | ||
| ASSESSMENT: [FULLY_IMPLEMENTED|PARTIALLY_IMPLEMENTED|NOT_IMPLEMENTED] | ||
| REASONING: [Brief explanation of your decision] | ||
| EVIDENCE: [Specific code/files that support your assessment] | ||
| Be thorough in your analysis. Check for: | ||
| - Related components, functions, or classes | ||
| - Test files | ||
| - Configuration changes | ||
| - Documentation updates | ||
| - Any other relevant implementation details | ||
| If the feature is FULLY_IMPLEMENTED, it should be complete and ready for approval. | ||
| If PARTIALLY_IMPLEMENTED, explain what's missing. | ||
| If NOT_IMPLEMENTED, explain why you believe this feature hasn't been addressed.`; | ||
|
|
||
| // Create a temporary session for validation | ||
| let session; | ||
| try { | ||
| // First create the session metadata | ||
| session = await agentService.createSession( | ||
| `Feature Validation: ${feature.title}`, | ||
| projectPath, | ||
| projectPath | ||
| ); | ||
|
|
||
| // Then initialize the conversation session in memory | ||
| await agentService.startConversation({ | ||
| sessionId: session.id, | ||
| workingDirectory: projectPath, | ||
| }); | ||
| } catch (sessionError) { | ||
| console.error('[ValidateFeature] Failed to create session:', sessionError); | ||
| return res.status(500).json({ | ||
| success: false, | ||
| error: 'Failed to create agent session', | ||
| }); | ||
| } | ||
|
|
||
| // Send the validation prompt to the agent | ||
| let result; | ||
| try { | ||
| result = await agentService.sendMessage({ | ||
| sessionId: session.id, | ||
| message: validationPrompt, | ||
| workingDirectory: projectPath, | ||
| }); | ||
| } catch (messageError) { | ||
| console.error('[ValidateFeature] Failed to send message:', messageError); | ||
|
|
||
| // Clean up the session if it exists | ||
| try { | ||
| await agentService.deleteSession(session.id); | ||
| } catch (cleanupError) { | ||
| console.error('[ValidateFeature] Failed to cleanup session:', cleanupError); | ||
| } | ||
|
|
||
| return res.status(500).json({ | ||
| success: false, | ||
| error: 'Failed to send message to agent', | ||
| }); | ||
| } | ||
|
|
||
| if (!result.success) { | ||
| // Clean up the session | ||
| try { | ||
| await agentService.deleteSession(session.id); | ||
| } catch (cleanupError) { | ||
| console.error('[ValidateFeature] Failed to cleanup session:', cleanupError); | ||
| } | ||
|
|
||
| return res.status(500).json({ | ||
| success: false, | ||
| error: 'Failed to validate feature', | ||
| }); | ||
| } | ||
|
|
||
| // Parse the agent response | ||
| const response = result.message?.content || ''; | ||
| console.log('[ValidateFeature] Raw AI Response:', response); | ||
|
|
||
| const assessmentMatch = response.match( | ||
| /ASSESSMENT:\s*\*{0,2}(FULLY_IMPLEMENTED|PARTIALLY_IMPLEMENTED|NOT_IMPLEMENTED)\*{0,2}/ | ||
| ); | ||
| const reasoningMatch = response.match(/REASONING:\s*\*{0,2}([^\n*]+)\*{0,2}/); | ||
| const evidenceMatch = response.match(/EVIDENCE:\s*\*{0,2}([\s\S]*?)\*{0,2}(?=\n\n|$)/); | ||
|
|
||
| console.log('[ValidateFeature] Regex matches:'); | ||
| console.log(' - Assessment match:', assessmentMatch); | ||
| console.log(' - Reasoning match:', reasoningMatch); | ||
| console.log(' - Evidence match:', evidenceMatch); | ||
|
|
||
| const assessment = assessmentMatch?.[1] || 'NOT_IMPLEMENTED'; | ||
| const reasoning = reasoningMatch?.[1] || 'Unable to determine reasoning'; | ||
| const evidence = evidenceMatch?.[1] || 'No specific evidence provided'; | ||
|
|
||
| console.log('[ValidateFeature] Extracted values:'); | ||
| console.log(' - Assessment:', assessment); | ||
| console.log(' - Reasoning:', reasoning); | ||
| console.log(' - Evidence:', evidence?.substring(0, 200) + '...'); | ||
|
|
||
| // Clean up the session | ||
| await agentService.deleteSession(session.id); | ||
|
|
||
| return res.json({ | ||
| success: true, | ||
| validation: { | ||
| assessment, | ||
| reasoning, | ||
| evidence, | ||
| fullResponse: response, | ||
| }, | ||
| }); | ||
| } catch (error) { | ||
| console.error('[ValidateFeature] Error:', error); | ||
| return res.status(500).json({ | ||
| success: false, | ||
| error: (error as Error).message, | ||
| }); | ||
| } | ||
| }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Define ValidateFeatureRequest and tighten error/session handling
The overall validation flow (load feature → create agent session → send structured prompt → parse ASSESSMENT/REASONING/EVIDENCE → clean up session) looks good, but there are a few concrete issues and improvement opportunities:
-
Missing
ValidateFeatureRequestdefinition/import (likely compile error)
You destructure with a typed annotation:const { projectPath, featureId }: ValidateFeatureRequest = req.body;
but no
ValidateFeatureRequesttype is defined or imported in this file. Unless it’s a global ambient type, this will fail type-checking. A simple local definition is probably enough here:interface ValidateFeatureRequest { projectPath: string; featureId: string; }
Place it above
createValidateFeatureHandler. -
Inconsistent use of shared error utilities
You importgetErrorMessageandlogErrorfrom../common.jsbut never use them, and instead callconsole.errordirectly. For consistency with other routes and better logging, consider:} catch (error) { logError('[ValidateFeature] Error validating feature', error); return res.status(500).json({ success: false, error: getErrorMessage(error), }); }
-
Session cleanup in unexpected error paths
You correctly clean up the session in most early‑return error branches and on the happy path:- After failed
sendMessage - When
result.successis false - After successful parsing
However, if an exception is thrown after
sendMessagesucceeds but beforedeleteSession(session.id)(e.g., due to an unexpected response shape or a regex edge case), the outercatchcurrently does not attempt to delete the session, which could leave orphaned session metadata. Consider trackingsessionIdseparately and cleaning it up in the outer catch when available. - After failed
-
Regex robustness / logging volume (optional)
- The regexes are reasonably defensive, but any deviation from the expected format falls back to
NOT_IMPLEMENTED. If the model ever returns slightly different formatting, that may pessimistically classify real implementations as not implemented. You might want to log a warning in that case or relax the patterns slightly. - Logging the full raw AI response plus all regex matches on every validation could be quite noisy in production logs. It may be worth guarding these logs behind a debug flag or log level.
- The regexes are reasonably defensive, but any deviation from the expected format falls back to
Addressing (1) is essential for compilation; (2) and (3) improve reliability and consistency; (4) is a nice-to-have.
🤖 Prompt for AI Agents
apps/server/src/routes/features/routes/validate-feature.ts lines 1-158: add a
local ValidateFeatureRequest interface above createValidateFeatureHandler to
define { projectPath: string; featureId: string } so the destructuring is
properly typed; replace console.error usages in the outer catch and
session-related error handlers with the imported logError and return errors
using getErrorMessage(error) for consistent logging/response; and ensure session
cleanup on any thrown exception by tracking sessionId (e.g., capture session?.id
into a local variable after creation) and attempting
agentService.deleteSession(sessionId) in the outer catch before returning.
| onValidate?: (feature: Feature) => void; | ||
| onValidateAllBacklog?: () => void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type signature should reflect async usage.
onValidateAllBacklog is awaited on Line 105, but its type signature declares it as returning void rather than Promise<void>.
🔎 Proposed type fix
onValidate?: (feature: Feature) => void;
- onValidateAllBacklog?: () => void;
+ onValidateAllBacklog?: () => Promise<void>;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| onValidate?: (feature: Feature) => void; | |
| onValidateAllBacklog?: () => void; | |
| onValidate?: (feature: Feature) => void; | |
| onValidateAllBacklog?: () => Promise<void>; |
🤖 Prompt for AI Agents
In apps/ui/src/components/views/board-view/kanban-board.tsx around lines 47-48,
the prop onValidateAllBacklog is declared as returning void but is awaited at
line 105; change its type from () => void to () => Promise<void> so it reflects
async usage, and update any call-sites/implementations to return a Promise (or
be async functions) to satisfy the new signature.
| validateFeature: ( | ||
| projectPath: string, | ||
| featureId: string | ||
| ) => Promise<{ | ||
| success: boolean; | ||
| validation?: { | ||
| assessment: 'FULLY_IMPLEMENTED' | 'PARTIALLY_IMPLEMENTED' | 'NOT_IMPLEMENTED'; | ||
| reasoning: string; | ||
| evidence: string; | ||
| fullResponse: string; | ||
| }; | ||
| error?: string; | ||
| }>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add validateFeature to the mock Features API to avoid runtime/type breakage
The new FeaturesAPI.validateFeature signature looks good and matches the server route shape. However, createMockFeaturesAPI() (later in this file) still returns an object without validateFeature, even though its return type is FeaturesAPI. This can cause:
- TypeScript errors (object missing required property).
- Runtime failures in web/mock mode when
api.features.validateFeatureis invoked.
Consider adding a no-op/mock implementation, e.g.:
Proposed mock implementation
function createMockFeaturesAPI(): FeaturesAPI {
// Store features in mock file system using features/{id}/feature.json pattern
return {
@@
generateTitle: async (description: string) => {
console.log('[Mock] Generating title for:', description.substring(0, 50));
// Mock title generation - just take first few words
const words = description.split(/\s+/).slice(0, 6).join(' ');
const title = words.length > 40 ? words.substring(0, 40) + '...' : words;
return { success: true, title: `Add ${title}` };
},
+ validateFeature: async (projectPath: string, featureId: string) => {
+ console.log('[Mock] Validating feature (mock):', { projectPath, featureId });
+ return {
+ success: true,
+ validation: {
+ assessment: 'PARTIALLY_IMPLEMENTED',
+ reasoning: 'Mock validation – backend validation is not available in web preview.',
+ evidence: 'No real code analysis performed in mock mode.',
+ fullResponse: 'Mock validation response.',
+ },
+ };
+ },
};
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/ui/src/lib/electron.ts around lines 343-355, the mock Features API
returned by createMockFeaturesAPI is missing the new validateFeature method
which causes TypeScript and runtime breakage; add a validateFeature
implementation that matches the declared signature (projectPath: string,
featureId: string) => Promise<{ success: boolean; validation?: { assessment:
'FULLY_IMPLEMENTED' | 'PARTIALLY_IMPLEMENTED' | 'NOT_IMPLEMENTED'; reasoning:
string; evidence: string; fullResponse: string; }; error?: string }> and return
a safe no-op/mock response (e.g., resolve success: true with a default
validation object or resolve success: false with an error) so callers can invoke
api.features.validateFeature without crashes and types remain satisfied.
|
closing, too many conflicts |
This PR introduces a comprehensive feature validation system for the Kanban board that allows users to validate whether backlog features are already implemented in the codebase. The validation uses AI analysis to determine implementation status and automatically moves fully implemented features to the "Waiting Approval" lane.
Features Added
Individual Feature Validation
Bulk Validation ("Validate All")
Validation Logic
FULLY_IMPLEMENTED,PARTIALLY_IMPLEMENTED, orNOT_IMPLEMENTEDFULLY_IMPLEMENTEDare automatically moved to "Waiting Approval"Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.