Skip to main content
Pedro Alizo

Work sample / Source

Statement Analysis Review Workbench

The files below are the source and tests used by the static demo. All scenarios are synthetic; the application makes no external requests.

Project notes Open workbench

src/lib/statement-review.ts
export interface StatementPeriod {
  label: string;
  revenue: number;
  costOfRevenue: number;
  operatingIncome: number;
  currentAssets: number;
  currentLiabilities: number;
}

export interface StatementScenario {
  id: string;
  title: string;
  context: string;
  periods: StatementPeriod[];
}

export const statementScenarios: StatementScenario[] = [
  {
    id: "steady-growth",
    title: "Growth, stable gross margin",
    context: "Synthetic sample with a two-period comparison.",
    periods: [
      {
        label: "Sep 2025",
        revenue: 1000000,
        costOfRevenue: 620000,
        operatingIncome: 110000,
        currentAssets: 460000,
        currentLiabilities: 300000,
      },
      {
        label: "Sep 2026",
        revenue: 1080000,
        costOfRevenue: 669600,
        operatingIncome: 129600,
        currentAssets: 518000,
        currentLiabilities: 350000,
      },
    ],
  },
  {
    id: "margin-pressure",
    title: "Growth, margin pressure",
    context: "Synthetic sample with a two-period comparison.",
    periods: [
      {
        label: "Sep 2025",
        revenue: 2000000,
        costOfRevenue: 1200000,
        operatingIncome: 240000,
        currentAssets: 900000,
        currentLiabilities: 600000,
      },
      {
        label: "Sep 2026",
        revenue: 2120000,
        costOfRevenue: 1314400,
        operatingIncome: 211880,
        currentAssets: 910000,
        currentLiabilities: 650000,
      },
    ],
  },
  {
    id: "new-entity",
    title: "Single period, no comparator",
    context:
      "Synthetic sample with no prior period and no current liabilities.",
    periods: [
      {
        label: "Sep 2026",
        revenue: 320000,
        costOfRevenue: 192000,
        operatingIncome: 19200,
        currentAssets: 110000,
        currentLiabilities: 0,
      },
    ],
  },
];

export interface StatementMetric {
  key:
    | "revenue"
    | "revenue-growth"
    | "gross-margin"
    | "gross-margin-change"
    | "operating-margin"
    | "operating-margin-change"
    | "current-ratio"
    | "current-ratio-change"
    | "working-capital";
  label: string;
  value: number | null;
  unit: "USD" | "percent" | "basis-points" | "ratio" | "ratio-change";
  formula: string;
}

export interface StatementReview {
  current: StatementPeriod;
  previous?: StatementPeriod;
  metrics: StatementMetric[];
  observations: string[];
}

function safeDivide(numerator: number, denominator: number): number | null {
  if (denominator === 0 || !Number.isFinite(numerator / denominator)) {
    return null;
  }
  return numerator / denominator;
}

function grossMargin(period: StatementPeriod): number | null {
  const grossProfit = period.revenue - period.costOfRevenue;
  return safeDivide(grossProfit, period.revenue);
}

function operatingMargin(period: StatementPeriod): number | null {
  return safeDivide(period.operatingIncome, period.revenue);
}

function currentRatio(period: StatementPeriod): number | null {
  return safeDivide(period.currentAssets, period.currentLiabilities);
}

export function reviewStatement(scenario: StatementScenario): StatementReview {
  const current = scenario.periods.at(-1);
  const previous = scenario.periods.at(-2);
  if (!current) throw new Error(`Scenario has no periods: ${scenario.id}`);

  const currentGrossMargin = grossMargin(current);
  const previousGrossMargin = previous ? grossMargin(previous) : null;
  const currentOperatingMargin = operatingMargin(current);
  const previousOperatingMargin = previous ? operatingMargin(previous) : null;
  const currentLiquidity = currentRatio(current);
  const previousLiquidity = previous ? currentRatio(previous) : null;
  const grossMarginChangeBps =
    currentGrossMargin === null || previousGrossMargin === null
      ? null
      : Math.round((currentGrossMargin - previousGrossMargin) * 10000);
  const operatingMarginChangeBps =
    currentOperatingMargin === null || previousOperatingMargin === null
      ? null
      : Math.round((currentOperatingMargin - previousOperatingMargin) * 10000);
  const currentRatioChange =
    currentLiquidity === null || previousLiquidity === null
      ? null
      : Math.round((currentLiquidity - previousLiquidity) * 100) / 100;
  const revenueGrowth = previous
    ? safeDivide(current.revenue - previous.revenue, previous.revenue)
    : null;

  const metrics: StatementMetric[] = [
    {
      key: "revenue",
      label: "Revenue",
      value: current.revenue,
      unit: "USD",
      formula: "Current-period reported revenue",
    },
    {
      key: "revenue-growth",
      label: "Revenue change",
      value: revenueGrowth === null ? null : revenueGrowth * 100,
      unit: "percent",
      formula: previous
        ? `(current revenue - ${previous.label} revenue) / ${previous.label} revenue`
        : "Not calculated: no prior period supplied",
    },
    {
      key: "gross-margin",
      label: "Gross margin",
      value: currentGrossMargin === null ? null : currentGrossMargin * 100,
      unit: "percent",
      formula: "(revenue - cost of revenue) / revenue",
    },
    {
      key: "gross-margin-change",
      label: "Gross margin change",
      value: grossMarginChangeBps,
      unit: "basis-points",
      formula: previous
        ? "(current gross margin - prior gross margin) × 10,000"
        : "Not calculated: no prior period supplied",
    },
    {
      key: "operating-margin",
      label: "Operating margin",
      value:
        currentOperatingMargin === null ? null : currentOperatingMargin * 100,
      unit: "percent",
      formula: "operating income / revenue",
    },
    {
      key: "operating-margin-change",
      label: "Operating margin change",
      value: operatingMarginChangeBps,
      unit: "basis-points",
      formula: previous
        ? "(current operating margin - prior operating margin) × 10,000"
        : "Not calculated: no prior period supplied",
    },
    {
      key: "current-ratio",
      label: "Current ratio",
      value: currentLiquidity,
      unit: "ratio",
      formula: "current assets / current liabilities",
    },
    {
      key: "current-ratio-change",
      label: "Current ratio change",
      value: currentRatioChange,
      unit: "ratio-change",
      formula: previous
        ? "current-period current ratio - prior-period current ratio"
        : "Not calculated: no prior period supplied",
    },
    {
      key: "working-capital",
      label: "Working capital",
      value: current.currentAssets - current.currentLiabilities,
      unit: "USD",
      formula: "current assets - current liabilities",
    },
  ];

  const observations = [
    previous && revenueGrowth !== null
      ? `Revenue ${revenueGrowth >= 0 ? "increased" : "decreased"} by ${Math.abs(revenueGrowth * 100).toFixed(1)}% from ${previous.label} to ${current.label}.`
      : "Revenue change is unavailable because no comparable prior period was supplied.",
    previous && grossMarginChangeBps !== null
      ? grossMarginChangeBps === 0
        ? `Gross margin was unchanged (0 basis points) versus ${previous.label}.`
        : `Gross margin ${grossMarginChangeBps > 0 ? "increased" : "decreased"} by ${Math.abs(grossMarginChangeBps)} basis points versus ${previous.label}.`
      : "Gross-margin change is unavailable because no comparable prior period was supplied.",
    currentLiquidity === null
      ? "Current ratio is not calculated because current liabilities are zero."
      : `Current ratio is ${currentLiquidity.toFixed(2)} for ${current.label}.`,
    previous && currentRatioChange !== null
      ? `Current ratio changed by ${currentRatioChange > 0 ? "+" : ""}${currentRatioChange.toFixed(2)}× from ${previous.label}.`
      : "Current-ratio change is unavailable without two comparable, non-zero-liability periods.",
    "These observations describe arithmetic only; they do not identify causes or recommend action.",
  ];

  return { current, previous, metrics, observations };
}
src/lib/statement-review.test.ts
import { describe, expect, it } from "vitest";
import { reviewStatement, statementScenarios } from "./statement-review";

describe("statement review", () => {
  it("calculates growth and stable gross margin from a two-period case", () => {
    const review = reviewStatement(statementScenarios[0]);
    const revenueGrowth = review.metrics.find(
      (metric) => metric.key === "revenue-growth",
    );
    const grossMarginChange = review.metrics.find(
      (metric) => metric.key === "gross-margin-change",
    );

    expect(revenueGrowth?.value).toBe(8);
    expect(grossMarginChange?.value).toBe(0);
    expect(review.observations).toContain(
      "Gross margin was unchanged (0 basis points) versus Sep 2025.",
    );
    expect(
      review.metrics.find((metric) => metric.key === "current-ratio")?.unit,
    ).toBe("ratio");
  });

  it("reports margin pressure as a formula-derived change", () => {
    const review = reviewStatement(statementScenarios[1]);
    const grossMarginChange = review.metrics.find(
      (metric) => metric.key === "gross-margin-change",
    );

    expect(grossMarginChange?.value).toBe(-200);
    expect(review.observations).toContain(
      "Gross margin decreased by 200 basis points versus Sep 2025.",
    );
    expect(
      review.metrics.find((metric) => metric.key === "current-ratio-change")
        ?.value,
    ).toBe(-0.1);
  });

  it("does not invent comparisons or divide by zero when baselines are absent", () => {
    const review = reviewStatement(statementScenarios[2]);
    const revenueGrowth = review.metrics.find(
      (metric) => metric.key === "revenue-growth",
    );
    const currentRatio = review.metrics.find(
      (metric) => metric.key === "current-ratio",
    );

    expect(revenueGrowth?.value).toBeNull();
    expect(currentRatio?.value).toBeNull();
    expect(review.observations).toContain(
      "Current ratio is not calculated because current liabilities are zero.",
    );
  });

  it("does not infer causes or recommendations from financial ratios", () => {
    const review = reviewStatement(statementScenarios[1]);

    expect(review.observations.at(-1)).toContain(
      "do not identify causes or recommend action",
    );
  });
});
src/pages/lab/statement-review.astro
---
import Section from "@/components/common/Section.astro";
import PageHead from "@/components/seo/PageHead.astro";
import Layout from "@/layouts/Layout.astro";
import { statementScenarios, reviewStatement } from "@/lib/statement-review";
import {
  getDefaultOgPathOrUrl,
  resolveOgImageUrl,
} from "@/lib/resolve-og-image";
import { getConfigurationCollection } from "@/lib/site-config";

const { data: config } = await getConfigurationCollection();
const ogImageUrl = resolveOgImageUrl({
  baseUrl: config.site.baseUrl,
  defaultOgPathOrUrl: getDefaultOgPathOrUrl(config),
});
const money = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  maximumFractionDigits: 0,
});
const formatMetric = (value: number | null, unit: string) => {
  if (value === null) return "Not calculated";
  if (unit === "USD") return money.format(value);
  if (unit === "percent") return `${value.toFixed(1)}%`;
  if (unit === "basis-points") return `${value > 0 ? "+" : ""}${value} bps`;
  if (unit === "ratio-change") {
    return `${value > 0 ? "+" : ""}${value.toFixed(2)}×`;
  }
  return `${value.toFixed(2)}×`;
};
---

<Layout>
  <Fragment slot="head">
    <PageHead
      title="Statement Analysis Review Workbench — Pedro Alizo"
      description="A Cloudflare Pages-compatible, browser-only finance statement review prototype using synthetic data and deterministic calculations."
      canonicalPath="/lab/statement-review"
      baseUrl={config.site.baseUrl}
      ogImageUrl={ogImageUrl}
      keywords={["financial statements", "finance workflow", "synthetic data"]}
      includeLanguageMeta
      robots="noindex, follow"
    />
  </Fragment>
  <Section class="my-8 pt-8">
    <header class="mb-8 max-w-prose">
      <p class="mb-3 font-mono text-sm uppercase zag-muted">
        Lab / Static prototype
      </p>
      <h1 class="mb-4 text-3xl page-title font-semibold leading-tight sm:text-4xl">
        Statement analysis review
      </h1>
      <p class="mb-4">
        A reviewer-facing statement workbench: inspect synthetic financial
        inputs, verify calculated ratios, and read a short set of arithmetic
        observations with their formulas.
      </p>
      <p class="text-sm zag-muted">
        Static browser app for Cloudflare Pages. All scenarios are invented. No
        uploads, external requests, model calls, or stored user data. The
        observations describe arithmetic, not causes or recommendations.
      </p>
    </header>

    <div class="mb-6 flex flex-col gap-2 sm:max-w-lg">
      <label for="statement-scenario" class="font-mono text-sm font-semibold">
        Synthetic scenario
      </label>
      <select id="statement-scenario" class="zag-input" data-scenario-select>
        {statementScenarios.map((scenario, index) => (
          <option value={scenario.id} selected={index === 0}>
            {scenario.title}
          </option>
        ))}
      </select>
    </div>

    <div data-statement-review>
      {statementScenarios.map((scenario, scenarioIndex) => {
        const review = reviewStatement(scenario);
        return (
          <section
            data-scenario-panel={scenario.id}
            hidden={scenarioIndex !== 0}
            aria-labelledby={`scenario-heading-${scenario.id}`}
          >
            <div class="mb-6 border-y zag-border py-4">
              <h2
                id={`scenario-heading-${scenario.id}`}
                class="mb-1 page-title text-xl font-semibold"
              >
                {scenario.title}
              </h2>
              <p class="text-sm zag-muted">{scenario.context}</p>
              <p class="mt-2 font-mono text-xs uppercase zag-muted">
                Current period: {review.current.label}
                {review.previous
                  ? ` · Comparison: ${review.previous.label}`
                  : " · No comparator"}
              </p>
            </div>

            <section
              class="mb-8"
              aria-labelledby={`metrics-heading-${scenario.id}`}
            >
              <h3
                id={`metrics-heading-${scenario.id}`}
                class="mb-4 page-title text-lg font-semibold"
              >
                Calculated metrics
              </h3>
              <dl class="grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
                {review.metrics.map((metric) => (
                  <div class="zag-border border-2 p-4">
                    <dt class="text-xs zag-muted">{metric.label}</dt>
                    <dd class="mt-2 font-mono text-xl font-semibold tabular-nums">
                      {formatMetric(metric.value, metric.unit)}
                    </dd>
                    <details class="mt-3 text-xs zag-muted">
                      <summary class="cursor-pointer">Calculation</summary>
                      <p class="mt-2 break-words">{metric.formula}</p>
                    </details>
                  </div>
                ))}
              </dl>
            </section>

            <div class="grid gap-8 border-t zag-border pt-6 lg:grid-cols-[1fr_1fr]">
              <section aria-labelledby={`observations-heading-${scenario.id}`}>
                <h3
                  id={`observations-heading-${scenario.id}`}
                  class="mb-4 page-title text-lg font-semibold"
                >
                  Arithmetic observations
                </h3>
                <ul class="list-disc space-y-3 pl-5 text-sm">
                  {review.observations.map((observation) => (
                    <li>{observation}</li>
                  ))}
                </ul>
              </section>

              <section aria-labelledby={`inputs-heading-${scenario.id}`}>
                <h3
                  id={`inputs-heading-${scenario.id}`}
                  class="mb-4 page-title text-lg font-semibold"
                >
                  Synthetic inputs
                </h3>
                <div class="flex flex-col gap-4">
                  {scenario.periods.map((period) => (
                    <div class="border zag-border p-4">
                      <h4 class="mb-3 font-mono text-sm font-semibold">
                        {period.label}
                      </h4>
                      <dl class="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
                        <div>
                          <dt class="text-xs zag-muted">Revenue</dt>
                          <dd class="mt-1 font-mono tabular-nums">
                            {money.format(period.revenue)}
                          </dd>
                        </div>
                        <div>
                          <dt class="text-xs zag-muted">Cost of revenue</dt>
                          <dd class="mt-1 font-mono tabular-nums">
                            {money.format(period.costOfRevenue)}
                          </dd>
                        </div>
                        <div>
                          <dt class="text-xs zag-muted">Operating income</dt>
                          <dd class="mt-1 font-mono tabular-nums">
                            {money.format(period.operatingIncome)}
                          </dd>
                        </div>
                        <div>
                          <dt class="text-xs zag-muted">Current assets</dt>
                          <dd class="mt-1 font-mono tabular-nums">
                            {money.format(period.currentAssets)}
                          </dd>
                        </div>
                        <div>
                          <dt class="text-xs zag-muted">Current liabilities</dt>
                          <dd class="mt-1 font-mono tabular-nums">
                            {money.format(period.currentLiabilities)}
                          </dd>
                        </div>
                      </dl>
                    </div>
                  ))}
                </div>
              </section>
            </div>
          </section>
        );
      })}
    </div>

    <section
      class="mt-10 max-w-prose border-t zag-border pt-6"
      aria-labelledby="boundary-heading"
    >
      <h2 id="boundary-heading" class="mb-3 page-title text-lg font-semibold">
        Deployment boundary
      </h2>
      <p class="text-sm">
        This demo is a deterministic baseline, not the private LLM prototype and
        not a production finance system. It runs from static assets and needs no
        server-side runtime or secret. A real deployment would first need
        permission-aware data access, approved metric definitions, durable
        review records, failure controls, and domain-reviewed evaluation.
      </p>
    </section>
  </Section>
</Layout>

<script>
  const scenarioSelect = document.querySelector("[data-scenario-select]");
  const scenarioPanels = Array.from(
    document.querySelectorAll("[data-scenario-panel]"),
  );

  if (scenarioSelect instanceof HTMLSelectElement) {
    scenarioSelect.addEventListener("change", () => {
      for (const panel of scenarioPanels) {
        if (!(panel instanceof HTMLElement)) continue;
        panel.hidden = panel.dataset.scenarioPanel !== scenarioSelect.value;
      }
    });
  }
</script>