Skip to content

Add Pandora Promotion Request Board v1#138

Open
besfeng23 wants to merge 1 commit into
mainfrom
codex/add-pandora-promotion-request-board-v1
Open

Add Pandora Promotion Request Board v1#138
besfeng23 wants to merge 1 commit into
mainfrom
codex/add-pandora-promotion-request-board-v1

Conversation

@besfeng23

Copy link
Copy Markdown
Owner

Motivation

  • Provide a production-safe, human-approved Promotion Request Board to capture deterministic promotion and rollback plans from approved shadow-pack preflights without executing any promotion.
  • Keep strict safety boundaries so operators can plan and review promotions while preventing any mutation of core memory truth tables or automatic promotions.

Description

  • Add additive Supabase migration supabase/migrations/20260704020000_pandora_promotion_request_board.sql that creates pandora_promotion_requests and pandora_promotion_request_events with RLS policies, indexes, updated_at trigger, and unique(user_id, preflight_id).
  • Implement lib/services/pandora-promotion-request-service.ts which builds deterministic promotion_plan and rollback_plan, enforces namespace/user/preflight/shadow ownership, computes blockers/warnings, and exposes CRUD and event APIs (list, get, getByPreflight, createOrRefresh, submit, updateReview, archive, createEvent).
  • Extend operator actions to include prepare_promotion_request in lib/services/pandora-operator-action-service.ts so dry-runs compute plan snapshots only and approved execution creates/refreshes promotion request rows without performing promotions or core memory mutations.
  • Add API routes under app/api/pandora/promotion-requests/* and app/api/pandora/shadow-pack-preflights/[id]/promotion-request that require server-derived sessions and reject user_id overrides.
  • Add UI components and wiring: promotion request board card, list, plan/rollback viewers, risk snapshot, review form, controls, and safe create/refresh button; and wire promotions into the /pandora dashboard and preflight list while clearly showing the banner "Promotion request only — execution unavailable".
  • Update types (components/pandora/types.ts), docs (docs/pandora-promotion-request-board.md and related updates), and safety guard tests to reflect the new board while maintaining the non-execution boundary.

Testing

  • Ran npm run typecheck and TypeScript checks passed with no blocking errors.
  • Ran npm run lint which completed and reported only existing non-blocking warnings in unrelated files.
  • Ran npm run test and unit suite completed successfully (99 test files, 635 tests passed).
  • Built the app with npm run build which finished successfully with existing Next/Supabase runtime warnings only.
  • Verified environment policy with npm run env:policy which passed for discovered env keys.
  • Added unit tests tests/unit/pandora-promotion-request-service.test.ts and updated guard tests to assert safety boundaries, and the new tests passed as part of the full test run.

Codex Task

@vercel

vercel Bot commented Jul 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
memory Ready Ready Preview, Comment Jul 4, 2026 1:34am

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@besfeng23, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 5 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 812aa380-40a9-42ed-9b2c-b4396e0051b5

📥 Commits

Reviewing files that changed from the base of the PR and between d301813 and 5f2bfbb.

📒 Files selected for processing (30)
  • app/api/pandora/promotion-requests/[id]/archive/route.ts
  • app/api/pandora/promotion-requests/[id]/review/route.ts
  • app/api/pandora/promotion-requests/[id]/route.ts
  • app/api/pandora/promotion-requests/[id]/submit/route.ts
  • app/api/pandora/promotion-requests/route.ts
  • app/api/pandora/shadow-pack-preflights/[id]/promotion-request/route.ts
  • components/pandora/OperatorActionComposer.tsx
  • components/pandora/PandoraDashboard.tsx
  • components/pandora/PromotionPlanViewer.tsx
  • components/pandora/PromotionRequestBoardCard.tsx
  • components/pandora/PromotionRequestControls.tsx
  • components/pandora/PromotionRequestCreateButton.tsx
  • components/pandora/PromotionRequestList.tsx
  • components/pandora/PromotionRequestReviewForm.tsx
  • components/pandora/PromotionRequestRiskSnapshot.tsx
  • components/pandora/RollbackPlanViewer.tsx
  • components/pandora/ShadowPackPreflightList.tsx
  • components/pandora/mock-data.ts
  • components/pandora/types.ts
  • docs/pandora-operator-action-center.md
  • docs/pandora-promotion-request-board.md
  • docs/pandora-readonly-action-runner.md
  • docs/pandora-shadow-context-pack-lab.md
  • docs/pandora-shadow-pack-preflight.md
  • lib/services/pandora-dashboard-service.ts
  • lib/services/pandora-operator-action-service.ts
  • lib/services/pandora-promotion-request-service.ts
  • supabase/migrations/20260704020000_pandora_promotion_request_board.sql
  • tests/unit/pandora-operator-action-guards.test.ts
  • tests/unit/pandora-promotion-request-service.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/add-pandora-promotion-request-board-v1

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5f2bfbb6b8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

export type OperatorActionDbClient = { from: (table: string) => any };

const ACTIONS = new Set<OperatorActionType>(["verify_namespace_invariants", "verify_pack_supersession", "check_retrieval_eval_status", "refresh_dashboard_snapshot", "prepare_distill_smoke_plan", "prepare_shadow_context_pack", "prepare_shadow_pack_preflight"]);
const ACTIONS = new Set<OperatorActionType>(["verify_namespace_invariants", "verify_pack_supersession", "check_retrieval_eval_status", "refresh_dashboard_snapshot", "prepare_distill_smoke_plan", "prepare_shadow_context_pack", "prepare_shadow_pack_preflight", "prepare_promotion_request"]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add DB constraint support for promotion actions

When prepare_promotion_request is accepted here, proposeOperatorAction can now try to insert that value into pandora_operator_actions.action_type, but the migrations in this repo leave pandora_operator_actions_action_type_check without this new enum value. In deployed databases, selecting this new action through the composer or API will pass the service guard and then fail at insert with a check-constraint violation, so the operator-action path for promotion requests is unusable until the migration updates the constraint.

Useful? React with 👍 / 👎.

const rollback_plan={ plan_version:"promotion_request_board_v1", rollback_available_after_future_promotion:true, steps:["identify newly promoted master","archive newly promoted master","restore previous active master","write rollback audit event","re-run verification"], rollback_execution_available:false };
return { preflight, shadow, currentMaster, status, blockers, warnings:Array.from(new Set(warnings)), promotion_plan, rollback_plan, risk_snapshot:risk, diff_snapshot:preflight.diff_summary, request_id:input.requestId??randomUUID(), title:`Promotion request for ${preflight.namespace} shadow pack`, summary:`Human-approved promotion request only for shadow pack ${shadow.id}. Approval does not execute promotion.` };
}
export async function createOrRefreshPromotionRequest(client:PromotionRequestDbClient,input:{userId:string; preflightId:string; requestId?:string}):Promise<PromotionRequestRow>{ const built=await buildPromotionRequestPlan(client,input); const existing=await getPromotionRequestByPreflight(client,{userId:input.userId,preflightId:input.preflightId}); const now=new Date().toISOString(); const base={user_id:input.userId,request_id:existing?.request_id??built.request_id,namespace:built.preflight.namespace,shadow_pack_id:built.shadow.id,preflight_id:built.preflight.id,active_master_pack_id:built.preflight.active_master_pack_id,status:built.status,title:built.title,summary:built.summary,promotion_plan:built.promotion_plan,rollback_plan:built.rollback_plan,risk_snapshot:built.risk_snapshot,diff_snapshot:built.diff_snapshot,warnings:built.warnings,updated_at:now}; const row=existing?await single(client.from("pandora_promotion_requests").update(base).eq("user_id",input.userId).eq("id",existing.id).select("*").single()):await single(client.from("pandora_promotion_requests").insert({id:randomUUID(),...base,reviewer_notes:"",reviewer_decision:null,created_at:now,submitted_at:null,approved_at:null,blocked_at:built.status==="blocked"?now:null,archived_at:null}).select("*").single()); if(!row) throw new Error("Unable to create or refresh promotion request"); await createPromotionRequestEvent(client,{userId:input.userId,promotionRequestId:row.id,shadowPackId:built.shadow.id,preflightId:built.preflight.id,eventType:existing?"promotion_request_refreshed":"promotion_request_created",message:"Promotion request prepared only; no promotion or core memory mutation performed.",metadata:{blockers:built.blockers,promotion_execution_available:false,no_core_memory_mutation_performed:true,no_promotion_performed:true}}); return row; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve reviewed promotion request status on refresh

When an existing request is refreshed from the preflight button or prepare_promotion_request execution, this update always writes status: built.status, which is either draft or blocked. That means refreshing an already submitted, approved, or archived request silently reopens or overwrites its review state while leaving the old reviewer fields/timestamps behind, corrupting the human-approval audit trail for any preflight that is refreshed after review.

Useful? React with 👍 / 👎.

export async function getPromotionRequest(client:PromotionRequestDbClient,input:{userId:string; promotionRequestId:string}):Promise<PromotionRequestRow>{ const row=await single(client.from("pandora_promotion_requests").select("*").eq("user_id",input.userId).eq("id",input.promotionRequestId).limit(1)); if(!row) throw new Error("Promotion request not found for current user"); return row; }
export async function getPromotionRequestByPreflight(client:PromotionRequestDbClient,input:{userId:string; preflightId:string}):Promise<PromotionRequestRow|null>{ return single(client.from("pandora_promotion_requests").select("*").eq("user_id",input.userId).eq("preflight_id",input.preflightId).limit(1)); }
export async function createPromotionRequestEvent(client:PromotionRequestDbClient,input:{userId:string; promotionRequestId:string; shadowPackId:string; preflightId:string; eventType:string; message:string; metadata?:Record<string,unknown>}):Promise<PromotionRequestEventRow|null>{ const row={id:randomUUID(),user_id:input.userId,promotion_request_id:input.promotionRequestId,shadow_pack_id:input.shadowPackId,preflight_id:input.preflightId,event_type:input.eventType,message:input.message,metadata:input.metadata??{},created_at:new Date().toISOString()}; return single(client.from("pandora_promotion_request_events").insert(row).select("*").single()); }
export async function buildPromotionRequestPlan(client:PromotionRequestDbClient,input:{userId:string; preflightId:string; requestId?:string}){ const preflight=await getShadowPackPreflight(client as any,{userId:input.userId,preflightId:input.preflightId}); assertNamespace(preflight.namespace); const shadow=await getShadowContextPack(client as any,{userId:input.userId,shadowPackId:preflight.shadow_pack_id}); if(shadow.id!==preflight.shadow_pack_id) throw new Error("Preflight shadow pack mismatch"); if(shadow.namespace!==preflight.namespace) throw new Error("Shadow pack and preflight namespace mismatch"); const currentMaster=await activeMaster(client,input.userId,preflight.namespace); if(currentMaster && currentMaster.namespace!==preflight.namespace) throw new Error("Active master namespace mismatch"); const risk=preflight.risk_summary ?? { status:"blocked", blockers:["risk summary unavailable"], warnings:[]}; const warnings=[...(Array.isArray(preflight.warnings)?preflight.warnings:[]),...(Array.isArray((risk as any).warnings)?(risk as any).warnings:[])]; const blockers:string[]=[]; if(preflight.status!=="approved_for_promotion") blockers.push("Preflight is not approved_for_promotion."); if((risk as any).status==="blocked") blockers.push("Preflight risk status is blocked."); if(!currentMaster && (risk as any).status==="blocked") blockers.push("Active master is missing while risk status is blocked."); if((risk as any).status==="high") warnings.push("Risk status is high; human review should be cautious."); if(["rejected","archived"].includes(String(shadow.status))) warnings.push(`Shadow pack status is ${shadow.status}; promotion execution remains unavailable.`); if(new Date(preflight.updated_at).getTime() < new Date(shadow.updated_at).getTime()) warnings.push("Preflight is older than the shadow pack update timestamp."); if((preflight.active_master_pack_id??null)!==(currentMaster?.id??null)) warnings.push("Active master id in preflight no longer matches current active master id."); const status:PromotionRequestStatus=blockers.length?"blocked":"draft"; const promotion_plan={ plan_version:"promotion_request_board_v1", namespace:preflight.namespace, shadow_pack_id:shadow.id, preflight_id:preflight.id, active_master_pack_id:preflight.active_master_pack_id, intended_operation:"replace_active_master_with_shadow_candidate", steps:["verify preflight is approved_for_promotion","verify active master still matches preflight active_master_pack_id","verify shadow pack still reviewed or ready_for_review","archive existing active master","create new active master from shadow candidate","write audit event","refresh dashboard verification"], required_checks:["same_user","same_namespace","preflight_approved","risk_not_blocked","active_master_unchanged","no_duplicate_active_master_after_promotion"], execution_available:false, blockers };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Block stale active-master promotion plans

If the active master changes or disappears after the preflight was approved, this only adds a warning, but submitPromotionRequest and approval only reject built.blockers. In that scenario the board can still mark a request approved with a promotion_plan.active_master_pack_id that no longer matches the current master, even though the plan lists active_master_unchanged as a required check; stale preflight/master mismatches should be blockers before submit or approval.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant