Skip to content

[codex] Polish public demo and externalize database#1

Draft
manynames3 wants to merge 1 commit into
mainfrom
codex/neon-demo-polish
Draft

[codex] Polish public demo and externalize database#1
manynames3 wants to merge 1 commit into
mainfrom
codex/neon-demo-polish

Conversation

@manynames3

Copy link
Copy Markdown
Owner

Summary

  • Reworks the public demo UX around an immediate demo review, three polished sample scenarios, decision briefs, GitHub preview, trust signals, onboarding copy, and mobile-friendly findings cards.
  • Updates hosted demo safeguards, including explicit Neon / external Postgres status and production build env values for the Cloudflare client bundle.
  • Removes the AWS public demo RDS/VPC Terraform resources so future applies use the external database URL instead of recreating RDS.

Validation

  • npm run lint
  • npm run build
  • npm run deploy:cloudflare
  • terraform validate
  • Live smoke test on https://terragate.hangi87.workers.dev, including demo run creation and mobile overflow check.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request migrates the public demo deployment from an AWS RDS PostgreSQL instance and VPC to an external PostgreSQL database (such as Neon Free) to eliminate idle infrastructure costs. It also introduces UI improvements, including a mobile-responsive findings table, a dashboard decision card, and a detailed decision brief component. The review feedback identifies several critical issues: potential runtime crashes due to missing optional chaining on nested run and finding.evidence properties, a fragile index-based icon mapping on the dashboard, and an invalid OpenAI model name (gpt-5.4-mini) configured in the Terraform Lambda environment variables.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +434 to +441
function buildDecisionBrief(run: RunDetail, findings: Finding[]): DecisionBriefData {
const critical = run.severity_counts.critical ?? 0;
const high = run.severity_counts.high ?? 0;
const criticalRisk = run.risk_level === "critical";
const replacements = run.plan_summary.replacements ?? 0;
const costOverThreshold = Boolean(run.cost_estimate.over_threshold);
const productionStatefulChange = run.environment === "prod" && replacements > 0 && (run.blast_radius.level === "high" || run.blast_radius.level === "critical");
const topFinding = findings.slice().sort(compareFindingsBySeverity)[0];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

Accessing nested properties on the run object (such as severity_counts, plan_summary, cost_estimate, and blast_radius) without optional chaining can lead to runtime crashes if any of these fields are null or undefined in the API response. Using optional chaining ensures robust rendering.

Suggested change
function buildDecisionBrief(run: RunDetail, findings: Finding[]): DecisionBriefData {
const critical = run.severity_counts.critical ?? 0;
const high = run.severity_counts.high ?? 0;
const criticalRisk = run.risk_level === "critical";
const replacements = run.plan_summary.replacements ?? 0;
const costOverThreshold = Boolean(run.cost_estimate.over_threshold);
const productionStatefulChange = run.environment === "prod" && replacements > 0 && (run.blast_radius.level === "high" || run.blast_radius.level === "critical");
const topFinding = findings.slice().sort(compareFindingsBySeverity)[0];
function buildDecisionBrief(run: RunDetail, findings: Finding[]): DecisionBriefData {
const critical = run.severity_counts?.critical ?? 0;
const high = run.severity_counts?.high ?? 0;
const criticalRisk = run.risk_level === "critical";
const replacements = run.plan_summary?.replacements ?? 0;
const costOverThreshold = Boolean(run.cost_estimate?.over_threshold);
const productionStatefulChange = run.environment === "prod" && replacements > 0 && (run.blast_radius?.level === "high" || run.blast_radius?.level === "critical");
const topFinding = findings.slice().sort(compareFindingsBySeverity)[0];

Comment on lines +482 to +503
function DecisionBrief({ run, report, decision, topFindings }: { run: RunDetail; report: Report; decision: DecisionBriefData; topFindings: Finding[] }) {
const changes = run.plan_summary;
const monthlyDelta = Number(run.cost_estimate.monthly_delta ?? 0);
return (
<Card className="p-5">
<div className="grid min-w-0 gap-5 xl:grid-cols-[minmax(0,1fr)_360px]">
<div>
<div className="flex flex-wrap items-center gap-2">
<Badge tone={decision.tone}>{decision.title}</Badge>
<Badge tone={run.github_check?.state === "fail" ? "danger" : run.github_check?.state === "warn" ? "warn" : "neutral"}>
GitHub check: {run.github_check?.state ?? "not created"}
</Badge>
</div>
<h2 className="mt-4 text-xl font-semibold text-white">What this means for the reviewer</h2>
<p className="mt-2 text-sm leading-6 text-slate-300">{decision.summary}</p>
<p className="mt-2 text-sm leading-6 text-slate-400">{report.risk_score.summary}</p>
<div className="mt-5 grid gap-3 md:grid-cols-3">
<DecisionMetric icon={FileSearch} label="Changed resources" value={String(changes.total_resource_changes ?? 0)} detail={`${changes.creates ?? 0} create / ${changes.updates ?? 0} update / ${changes.deletes ?? 0} delete`} />
<DecisionMetric icon={AlertTriangle} label="Blast radius" value={`${run.blast_radius.score ?? 0}`} detail={run.blast_radius.summary ?? "No destructive stateful changes detected."} />
<DecisionMetric icon={DollarSign} label="Cost delta" value={`$${monthlyDelta.toFixed(2)}/mo`} detail={run.cost_estimate.message ?? "Heuristic estimate"} />
</div>
</div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

Similarly to buildDecisionBrief, the DecisionBrief component accesses nested properties on run (like plan_summary, cost_estimate, and blast_radius) directly. If any of these objects are null or undefined, the component will crash. Applying optional chaining prevents potential runtime errors.

function DecisionBrief({ run, report, decision, topFindings }: { run: RunDetail; report: Report; decision: DecisionBriefData; topFindings: Finding[] }) {
  const changes = run.plan_summary;
  const monthlyDelta = Number(run.cost_estimate?.monthly_delta ?? 0);
  return (
    <Card className="p-5">
      <div className="grid min-w-0 gap-5 xl:grid-cols-[minmax(0,1fr)_360px]">
        <div>
          <div className="flex flex-wrap items-center gap-2">
            <Badge tone={decision.tone}>{decision.title}</Badge>
            <Badge tone={run.github_check?.state === "fail" ? "danger" : run.github_check?.state === "warn" ? "warn" : "neutral"}>
              GitHub check: {run.github_check?.state ?? "not created"}
            </Badge>
          </div>
          <h2 className="mt-4 text-xl font-semibold text-white">What this means for the reviewer</h2>
          <p className="mt-2 text-sm leading-6 text-slate-300">{decision.summary}</p>
          <p className="mt-2 text-sm leading-6 text-slate-400">{report.risk_score.summary}</p>
          <div className="mt-5 grid gap-3 md:grid-cols-3">
            <DecisionMetric icon={FileSearch} label="Changed resources" value={String(changes?.total_resource_changes ?? 0)} detail={`${changes?.creates ?? 0} create / ${changes?.updates ?? 0} update / ${changes?.deletes ?? 0} delete`} />
            <DecisionMetric icon={AlertTriangle} label="Blast radius" value={`${run.blast_radius?.score ?? 0}`} detail={run.blast_radius?.summary ?? "No destructive stateful changes detected."} />
            <DecisionMetric icon={DollarSign} label="Cost delta" value={`$${monthlyDelta.toFixed(2)}/mo`} detail={run.cost_estimate?.message ?? "Heuristic estimate"} />
          </div>
        </div>

DATABASE_URL = var.database_url
LANGSMITH_PROJECT = "terragate"
LANGSMITH_TRACING = "false"
OPENAI_MODEL = "gpt-5.4-mini"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The OpenAI model gpt-5.4-mini does not exist. This typo will cause runtime API errors when calling OpenAI. It should be corrected to a valid model name such as gpt-4o-mini.

        OPENAI_MODEL                        = "gpt-4o-mini"

Comment on lines +44 to +45
{filtered.map((finding) => {
const evidence = finding.evidence[0];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

If finding.evidence is undefined or null, accessing finding.evidence[0] will throw a TypeError and crash the findings list rendering. Using optional chaining (finding.evidence?.[0]) is safer.

Suggested change
{filtered.map((finding) => {
const evidence = finding.evidence[0];
{filtered.map((finding) => {
const evidence = finding.evidence?.[0];

Comment on lines +78 to +79
{filtered.map((finding) => {
const evidence = finding.evidence[0];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

If finding.evidence is undefined or null, accessing finding.evidence[0] will throw a TypeError and crash the findings table rendering. Using optional chaining (finding.evidence?.[0]) is safer.

Suggested change
{filtered.map((finding) => {
const evidence = finding.evidence[0];
{filtered.map((finding) => {
const evidence = finding.evidence?.[0];

Comment on lines +238 to 240
{trustSignals.map((control, index) => {
const Icon = trustControlIcons[index];
return (

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Mapping trustSignals to trustControlIcons by index is fragile. If trustSignals is updated in demo-scenarios.ts without a corresponding update to trustControlIcons in dashboard.tsx, Icon will be undefined, causing a rendering crash. Adding a guard prevents this.

          {trustSignals.map((control, index) => {
            const Icon = trustControlIcons[index];
            if (!Icon) return null;
            return (

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.

1 participant