// Model tab — the uploaded model as a Collection of data products. Left menu = // the workbook's sheet tabs (exact .xlsx order); each is a DP that is either // Analytical (a micro-model) or Operational (a schedule). Every DP carries the // same header + four faces (Artifact / Data / Control / Context) as the Dashboard // DPs, for one consistent layout. Data is live (the sheet grid); Context/Control // are templated per DP; Artifact is the deferred formatted view (option A). // Per-DP metadata (kind + role + sources + owner) — powers the Context/Control // faces. Kind: 'A' = Analytical (micro-model), 'O' = Operational (schedule). window.MODEL_DP_META = { 'Assumptions': { k: 'A', role: 'The model’s input levers — growth, cost structure, working capital, capex and tax. Everything else reads from here.', src: 'Manual inputs (blue) + the opening balance sheet.', owner: 'Jose Patel · CFO' }, 'Income Statement': { k: 'A', role: 'Monthly P&L and forecast — the assembled revenue-to-net-income model.', src: 'Revenue Build, GL Detail (actuals), Assumptions (forecast).', owner: 'Jose Patel · CFO' }, 'Balance Sheet': { k: 'A', role: 'Opening balance plus cumulative GL activity — balances by construction every period.', src: 'Assumptions (opening BS), GL Detail, Working Capital, Debt & PP&E schedules.', owner: 'Trevor Garcia · FP&A' }, 'Cash Flow': { k: 'A', role: 'Indirect-method cash flow; ending cash ties to the balance sheet every period.', src: 'Income Statement + balance-sheet movements.', owner: 'Trevor Garcia · FP&A' }, 'Capacity & Utilization': { k: 'A', role: 'Per-line practical capacity and utilization %, driven by production volume. Modeled in Proxa — not in any source file.', src: 'Computed from the Production Log (units) ÷ Assumptions (line capacities). Feeds the Revenue Build.', owner: 'Operations' }, 'GL Detail': { k: 'O', role: 'The general ledger summarized to a trial balance — every account behind the statements.', src: 'CascadeRidge-GL-Export.xlsx (accounting-system journal). Feeds the Income Statement & Balance Sheet.', owner: 'Jose Patel · CFO' }, 'Debt Schedule': { k: 'O', role: 'Term-loan amortization — principal, interest and balance by month.', src: 'Assumptions (rate, principal) + opening term debt. Feeds Cash Flow & interest.', owner: 'Trevor Garcia · FP&A' }, 'PP&E Schedule': { k: 'O', role: 'Fixed-asset rollforward and depreciation, including the LEB-L5 capex.', src: 'Assumptions (capex, D&A) + opening PP&E. Feeds Balance Sheet & D&A.', owner: 'Trevor Garcia · FP&A' }, 'Working Capital': { k: 'O', role: 'AR / AP / accrual rollforwards on DSO and DPO.', src: 'Revenue Build, GL Detail, Assumptions (DSO/DPO). Feeds Balance Sheet & Cash Flow.', owner: 'Trevor Garcia · FP&A' }, 'Revenue Build': { k: 'O', role: 'Revenue by segment and turnkey/tolling, actual + forecast.', src: 'Invoices / GL, Assumptions (growth). Feeds the Income Statement.', owner: 'Jose Patel · CFO' }, 'Headcount': { k: 'O', role: 'Monthly headcount and labor cost by group.', src: 'HR roster + Assumptions. Feeds Income Statement labor lines.', owner: 'People · Finance' }, 'Revenue Build (bottom-up)': { k: 'A', role: 'Revenue by line & product family — allocated from actual revenue by production volume, so it ties to the Income Statement and slices revenue by line, family and plant. Modeled in Proxa; completes the Revenue chain: Production Log → Production Schedule → here.', src: 'Computed from the Production Schedule (units) × blended price; reconciles to the Income Statement / GL.', owner: 'Jose Patel · CFO' }, 'Production Schedule': { k: 'O', role: 'Units by line and product family, dates across (aligned to the statements) — the production schedule the model runs on. Actuals; forecast is built in the Revenue Build.', src: 'CascadeRidge-Production-Log.xlsx (plant MES run log), priced via Customer Contracts. Feeds Capacity & Utilization and Revenue Build.', owner: 'Operations' }, }; // The additional workbooks (Revenue & Customer, COGS, Operations, HR, Working // Capital, Capex, Debt, Tax, Scenarios, Consolidation, Transaction, Outputs) that // carry the model up to a full ~100-tab Cohesive Model. Representational; their // per-DP metadata is generated alongside the sheets in tabs/model_ext.js. Object.assign(window.MODEL_DP_META, window.MODEL_DP_META_EXT || {}); const MDL_FACES = [['artifact', 'Artifact'], ['data', 'Data'], ['control', 'Control'], ['context', 'Context']]; function mdlKindLabel(k) { return k === 'A' ? 'Analytical' : 'Operational'; } function ModelCell({ text, first }) { const numeric = !first && /\d/.test(text) && /^[-(]?[\d$]/.test(text.trim()); const cls = 'mdl-cell' + (first ? ' mdl-cell--label' : (numeric ? ' mdl-cell--num' : '')); return {text}; } function ModelDataFace({ sheet }) { return (
{sheet.nrows_total.toLocaleString()} rows × {sheet.ncols} cols {sheet.capped ? ` · showing first ${sheet.shown}` : ''}
{sheet.rows.map((row, ri) => {row.map((cell, ci) => )} )}
); } function ModelContextFace({ name, meta, source }) { return (
What this is

{meta.role}

Kind

{mdlKindLabel(meta.k)} {meta.k === 'A' ? ' — a micro-model: assumptions + logic that project outcomes.' : ' — a schedule: a rollforward/register of record that feeds the models.'}

Sources

{meta.src}

Owner

{meta.owner}

Status

Draft Claude-authored from the workbook — validate to pin it as memory.

); } function ModelControlFace({ meta, source }) { return (
Sync
{source ?

In sync with {source} · last synced 1d ago

:

Computed in Proxa — recomputes whenever its inputs re-sync. No source file.

}
Source

{meta.src}

Reconciliation

Work in Excel or in Proxa — the hub Control tab tracks sync across the whole collection and flags any tab that drifts out of sync.

); } function ModelArtifactFace({ name, onViewData }) { const stmt = (window.MODEL_STMT || {})[name] || (window.MODEL_ARTIFACTS || {})[name]; if (stmt) { return
; } return (
Formatted artifact

A presentation view of this data product is coming. The Data view shows the full sheet, live from the workbook.

); } function FinanceModelCanvas() { const data = (window.MODEL_DATA) || { order: [], sheets: {}, source: '' }; const meta = window.MODEL_DP_META || {}; const order = data.order || []; // Split the workbook tabs by where they belong: the financial model (statements // + supporting schedules; GL Detail stays for now, tagged ERP) vs the Proxa // model (operational/granular layer — production & capacity, feeding future // granular builds like the bottom-up Revenue Build). const has = (n) => !!data.sheets[n]; // The Finance Model is ASSEMBLED FROM SOURCES. Each source is a real file (a // chip that expands to what it contributes); the model workbook holds the // 3-statement model, the raw operational exports ground the actuals, and a // final group is what Proxa itself computes (no source file — it's modeled). const SOURCES = [ { id: 'model', kind: 'file', file: data.source || 'CascadeRidge-Financial-Model.xlsx', note: 'Model workbook', sheets: ['Assumptions', 'Income Statement', 'Balance Sheet', 'Cash Flow', 'Revenue Build', 'Working Capital', 'Debt Schedule', 'PP&E Schedule', 'Headcount'] }, { id: 'gl', kind: 'file', file: 'CascadeRidge-GL-Export.xlsx', note: 'Accounting system · raw export', sheets: ['GL Detail'] }, { id: 'prod', kind: 'file', file: 'CascadeRidge-Production-Log.xlsx', note: 'Plant MES · raw export', sheets: ['Production Schedule'] }, { id: 'modeled', kind: 'modeled', file: 'Modeled in Proxa', note: 'Computed — no source file', sheets: ['Capacity & Utilization', 'Revenue Build (bottom-up)'] }, // The additional workbooks that fill the model out to ~100 tabs (from // tabs/model_ext.js). Same {id, kind, file, note, sheets} shape as above. ...(window.MODEL_EXT_SOURCES || []), ].map((s) => ({ ...s, sheets: s.sheets.filter(has) })).filter((s) => s.sheets.length); const nFiles = SOURCES.filter((s) => s.kind === 'file').length; const nModeled = SOURCES.filter((s) => s.kind === 'modeled').reduce((a, s) => a + s.sheets.length, 0); const initial = order.indexOf('Income Statement') >= 0 ? 'Income Statement' : order[0]; const [sel, setSel] = React.useState(initial); const [face, setFace] = React.useState('data'); const [canvasOpen, setCanvasOpen] = React.useState(false); const [openSec, setOpenSec] = React.useState(() => Object.fromEntries(SOURCES.map((s) => [s.id, true]))); const toggleSec = (k) => setOpenSec((o) => ({ ...o, [k]: !o[k] })); const pickSheet = (n) => { setSel(n); setCanvasOpen(true); }; const sheet = data.sheets[sel] || { rows: [], ncols: 0, nrows_total: 0, shown: 0, capped: false }; const dp = meta[sel] || { k: 'O', role: '', src: '', owner: '' }; const selSrcGroup = SOURCES.find((s) => s.sheets.includes(sel)) || {}; const selSource = selSrcGroup.kind === 'modeled' ? null : selSrcGroup.file; return (
setCanvasOpen(false)} ariaLabel={sel}> ({ label: n, active: n === sel, onClick: () => pickSheet(n) }))} faces={[ { key: 'data', label: 'Data', render: () => }, { key: 'artifact', label: 'Artifact', render: (setFace) => setFace('data')} /> }, { key: 'control', label: 'Control', render: () => }, { key: 'context', label: 'Context', render: () => }, ]} />
); } window.FinanceModelCanvas = FinanceModelCanvas;