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
5 changes: 5 additions & 0 deletions .changeset/typed-neon-findings-glow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'neondeck': patch
---

Add a revision-bound ephemeral Neon finding contract with targeted review-surface APIs, events, and Flue capabilities.
7 changes: 7 additions & 0 deletions .plans/DEVIATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ Use this format:
- Reason: Stable query identity, bounded immutable metadata reuse, active-patch prioritization, and bounded warm thread reuse delivered passing warm first-patch and thread medians and removed duplicate/abandoned work. The remaining misses are measured, isolated follow-ups that do not require overlapping changes in the Phase B review-map/cursor seam, but they must not be represented as passing or erased.
- Follow-up: Reprofile the production tree boot/query/render boundary; separate cold network object-fetch time from local metadata before changing refspecs or the <3-second budget; and evaluate uncached GitHub thread latency without weakening cancellation or mutation invalidation. Remeasure the retained immutable real PR before changing any budget, then archive `.plans/PR_REVIEW_PERF_PLAN.md` only after these deferrals are reconciled.

## 2026-07-18 - Diff Review Phase B Finding Backend Split

- Roadmap item: Diff Improvements Plan / Phase B typed Neon finding application and inline rendering
- Decision: Land the versioned finding contract, process-ephemeral review-surface state, bounded local APIs, targeted events, and Flue tools/actions separately from Pierre/React rendering and explicit promotion into GitHub drafts or prepared-diff revision requests. The shared lifecycle vocabulary includes `resolved` and `promoted`, but this backend slice exposes only apply, read, dismiss, clear, automatic staling, and cleanup transitions.
- Reason: Diff Improvements Phase B is split across parallel backend and review-UI workstreams. Keeping promotion out of the finding application path preserves the trust boundary that applying local context cannot mutate GitHub or prepared diffs.
- Follow-up: The review-surface UI workstream should render these findings inline, add navigation and explicit user-owned promotion controls, and transition resolved/promoted lifecycle state only through the existing typed GitHub draft and prepared-diff revision workflows.

## 2026-07-17 - Diff Review Phase A Sequencing

- Roadmap item: Diff Improvements Plan / transition from Phase A to Phase B
Expand Down
100 changes: 100 additions & 0 deletions shared/review-finding.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
export const neonReviewFindingSchemaVersion = 1 as const;

export const neonReviewFindingLimits = {
maxApplyBatch: 50,
maxFindingsPerSurface: 200,
maxTitleLength: 160,
maxExplanationLength: 2_000,
maxSuggestedActionLength: 500,
maxLifecycleReasonLength: 500,
maxEventFindingIds: 50,
} as const;

export type NeonReviewFindingSeverity = 'critical' | 'major' | 'minor' | 'nit';

export type NeonReviewFindingConfidence = 'high' | 'medium' | 'low';

export type NeonReviewFindingState =
'active' | 'stale' | 'resolved' | 'dismissed' | 'promoted';

export type NeonReviewFindingSide = 'additions' | 'deletions';

export type NeonReviewFindingAnchor =
| {
kind: 'line-range';
side: NeonReviewFindingSide;
startLine: number;
endLine: number;
}
| {
kind: 'hunk';
side: NeonReviewFindingSide;
hunkId: string;
};

export type NeonReviewFindingProvenance = {
authorRole: string;
model: string | null;
workflowRunId: string | null;
createdAt: string;
};

export type NeonReviewFindingLifecycle = {
state: NeonReviewFindingState;
changedAt: string;
reason: string | null;
};

export type NeonReviewFinding = {
schemaVersion: typeof neonReviewFindingSchemaVersion;
id: string;
surfaceId: string;
sourceId: string;
revisionKey: string;
file: string;
anchor: NeonReviewFindingAnchor;
title: string;
explanation: string;
severity: NeonReviewFindingSeverity;
confidence: NeonReviewFindingConfidence | null;
suggestedAction: string | null;
provenance: NeonReviewFindingProvenance;
lifecycle: NeonReviewFindingLifecycle;
};

export type NeonReviewFindingDraft = Omit<
NeonReviewFinding,
'surfaceId' | 'provenance' | 'lifecycle'
> & {
provenance: Omit<NeonReviewFindingProvenance, 'createdAt'>;
};

export type NeonReviewFindingSubmission = Omit<
NeonReviewFindingDraft,
'provenance'
>;

export type ReviewSurfaceFindingsApplyRequest = {
revisionKey: string;
findings: NeonReviewFindingSubmission[];
};

export type ReviewSurfaceFindingsDismissRequest = {
sourceId: string;
revisionKey: string;
findingIds: string[];
reason: string | null;
};

export type ReviewSurfaceFindingsClearRequest = {
sourceId: string;
revisionKey: string;
findingIds?: string[];
};

export type ReviewSurfaceFindingChange = {
action: 'applied' | 'dismissed' | 'cleared' | 'staled';
revisionKey: string | null;
findingIds: string[];
count: number;
};
4 changes: 3 additions & 1 deletion shared/review-navigation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export type ReviewFindingSeverity = 'critical' | 'major' | 'minor' | 'nit';
import type { NeonReviewFindingSeverity } from './review-finding';

export type ReviewFindingSeverity = NeonReviewFindingSeverity;

export type ReviewNavigationFile = {
path: string;
Expand Down
51 changes: 50 additions & 1 deletion shared/review-surface.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import type { ReviewSourceSnapshot } from './review-source';
import type {
NeonReviewFinding,
ReviewSurfaceFindingChange,
} from './review-finding';

export const reviewSurfaceSchemaVersion = 1 as const;

export const reviewSurfaceContextPageLimits = {
defaultLimit: 25,
maxLimit: 50,
maxOffset: 5_000,
} as const;

export type ReviewSurfaceSelection = {
path: string;
side: 'additions' | 'deletions';
Expand Down Expand Up @@ -31,6 +41,38 @@ export type ActiveReviewSurface = ReviewSurfaceSnapshot & {
lastNavigationAck: ReviewSurfaceNavigationAck | null;
};

export type ReviewSurfaceContextPageRequest = {
surfaceId: string;
offset?: number;
limit?: number;
};

export type ReviewSurfaceContextWindow<T> = {
items: T[];
offset: number;
limit: number;
total: number;
nextOffset: number | null;
};

export type ReviewSurfaceContextSummary = Omit<
ActiveReviewSurface,
'source' | 'reviewOrder'
> & {
source: Omit<ReviewSourceSnapshot, 'files'>;
counts: {
files: number;
reviewOrder: number;
findings: number;
};
};

export type ReviewSurfaceContextPage = {
files: ReviewSurfaceContextWindow<ReviewSourceSnapshot['files'][number]>;
reviewOrder: ReviewSurfaceContextWindow<string>;
findings: ReviewSurfaceContextWindow<NeonReviewFinding>;
};

export type ReviewSurfaceNavigationTarget = {
path: string;
focus: boolean;
Expand Down Expand Up @@ -62,11 +104,18 @@ export type ReviewSurfaceNavigationAck = {

export type ReviewSurfaceChangeEvent = {
id: string;
action: 'registered' | 'updated' | 'removed' | 'navigation' | 'acknowledged';
action:
| 'registered'
| 'updated'
| 'removed'
| 'navigation'
| 'acknowledged'
| 'findings-changed';
surfaceId: string;
changedAt: string;
surface: ActiveReviewSurface | null;
navigation: ReviewSurfaceNavigationCommand | null;
acknowledgement: ReviewSurfaceNavigationAck | null;
findings: ReviewSurfaceFindingChange | null;
reason: 'closed' | 'expired' | null;
};
3 changes: 3 additions & 0 deletions src/agents/display-assistant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from '../modules/memory';
import { neondeckPrEventActions } from '../modules/pr-events';
import { neondeckPreparedDiffActions } from '../modules/prepared-diffs';
import { neondeckReviewSurfaceActions } from '../modules/review-surfaces';
import {
neondeckRuntimeSkillActions,
runtimeSkillReferencesSync,
Expand Down Expand Up @@ -72,6 +73,7 @@ export default defineAgent(({ id }) => {
'For morning briefings, use neondeck_briefing_profile_read, neondeck_briefing_profile_update, neondeck_briefing_run_now, and neondeck_briefing_run_read for exact persisted grounding. Briefing instructions may request any configured MCP source, but do not add a briefing-specific allowlist or auto-approve mutations. For other scheduled work, use neondeck_scheduled_task_instruction_create. Scheduled instructions run as bounded workflows by default; select an explicit agent session target only when the user needs continuity. Use the scheduled-task list, read, pause, resume, and delete actions to operate existing tasks.',
'For autopilot status, use neondeck_autopilot_state_lookup before explaining what Neon is watching, why it did or did not act, which worktrees are prepared, which approvals are pending, and what repo/watch policy allows. Treat this as read-only operator state; do not invent queue entries, diffs, pushes, or workflow outcomes that are not present in the lookup.',
'For prepared autopilot diffs, use neondeck_prepared_diff_list, neondeck_prepared_diff_summary, neondeck_prepared_diff_changed_files, and neondeck_prepared_diff_file_diff for facts. Use neondeck_autopilot_recovery_options before recommending recovery from prepared, blocked, pushed, or failed autopilot states. Use neondeck_autopilot_recovery_run for bounded inspect, retry-after-new-commit, rebase/resync worktree, retry verify, retry push, retry comment, request revision, cleanup worktree, abandon, or manual-follow-up decisions. These recovery actions dispatch to existing prepared-diff, worktree sync/cleanup, and autopilot services, keep the source worktree as the source of truth, and never bypass confirmation, execution, policy, cleanup, or GitHub gates.',
'For a live diff, use neondeck_review_surfaces_lookup to resolve the intended window and neondeck_review_surface_context_lookup to page through its bounded source metadata and ephemeral findings. Use neondeck_review_surface_navigate only for one explicit surface id, keeping focus=false unless the user asked to be shown the target. Apply findings only through neondeck_review_surface_findings_apply with the exact active source and revision, stable ids, and concise bounded text; Neondeck stamps trusted provenance. Dismiss or clear findings explicitly with the exact active source and revision. Review-surface findings are process-ephemeral local context only and never create GitHub comments, submit reviews, request prepared-diff revisions, or silently re-anchor across revisions.',
'The neondeck_autopilot_prepare_pr_worktree, neondeck_autopilot_fix_pr_review_feedback, neondeck_autopilot_fix_pr_ci_failure, and neondeck_autopilot_push_pr_autofix actions are workflow-only and refuse in interactive chat. Autonomous watcher workflows use them under a Flue run id and remain governed by the configured per-PR mode.',
'For PR event facts and watermarks, use neondeck_github_pr_event_state_get, neondeck_pr_review_comments_lookup, neondeck_pr_requested_changes_lookup, neondeck_pr_branch_permissions_lookup, neondeck_pr_watch_event_state_refresh, and neondeck_pr_watch_event_watermarks_list. These GitHub fact collectors and app-state watermarks do not prepare fixes or push. Use neondeck_pr_comment only when the intended PR comment text is explicit and grounded in deterministic facts; prefer neondeck_autopilot_comment_pr_autofix_result for autonomous prepared-diff result comments because it also records the workflow summary audit.',
'For quick deterministic facts, prefer the neondeck_*_lookup tools. Use actions when you need a durable command, mutation, scheduler tick, or persisted workflow summary.',
Expand Down Expand Up @@ -120,6 +122,7 @@ export default defineAgent(({ id }) => {
...neondeckAutopilotActions,
...neondeckAutopilotRecoveryActions,
...neondeckPreparedDiffActions,
...neondeckReviewSurfaceActions,
...neondeckScheduledTaskActions,
...neondeckSchedulerActions,
...neondeckSessionActions,
Expand Down
2 changes: 2 additions & 0 deletions src/agents/support/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { neondeckMcpTools } from '../../domains/mcp';
import { neondeckPrEventTools } from '../../modules/pr-events';
import { neondeckPreparedDiffTools } from '../../modules/prepared-diffs';
import { neondeckRepoEditTools } from '../../repo-edit';
import { neondeckReviewSurfaceTools } from '../../modules/review-surfaces';
import {
listRepoStatus,
listRuntimeSkills,
Expand Down Expand Up @@ -339,6 +340,7 @@ export const neondeckFactTools = [
safetyPolicyTool,
executionPolicyTool,
...neondeckPrEventTools,
...neondeckReviewSurfaceTools,
...neondeckRepoEditTools,
...neondeckWorktreeTools,
...neondeckKiloTools,
Expand Down
Loading