← Revelata deepKPICONTENT HISTORY
WHAT CHANGED
Update to Revelata deepKPI
Snapshot Oct 24, 2026 · 13:30 UTC · version 1.1.0
Collection source: downloaded plugin package.
First saved snapshot
No earlier snapshot is available to establish a change.
Save Revelata deepKPI and check future changes in Following.
Up to 10 plugins free · no card required.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"description": "Builds a full Excel operating model for a US public company from Revelata deepKPI data. Resolves a ticker or company name, classifies it as restaurant, retail, or software, and stops without creating a workbook for unsupported industries. Creates a single-sheet model with Revenue, Costs, Consolidated Financials, Depreciation Schedule, and Net Working Capital sections; discovers the KPI inventory once; and orchestrates the section sub-skills in dependency order. Triggers include \"build an operating model\", \"build a model for\", \"model out this company\", \"set up the model\", and \"scaffold a model\". For a single section, KPI pull, or filing text, use the narrower skills.\n",
"included_files": [
{
"relative_path": "consolidated-financials/consolidated-financials.md",
"size_in_bytes": 59208
},
{
"relative_path": "costs/costs.md",
"size_in_bytes": 9313
},
{
"relative_path": "costs/episodicLines.md",
"size_in_bytes": 8863
},
{
"relative_path": "costs/restaurants/restaurantsCosts.md",
"size_in_bytes": 82694
},
{
"relative_path": "costs/retail/retailCosts.md",
"size_in_bytes": 116453
},
{
"relative_path": "costs/segmentSpine.md",
"size_in_bytes": 7133
},
{
"relative_path": "costs/software/softwareCosts.md",
"size_in_bytes": 86419
},
{
"relative_path": "depreciation-schedule/depreciation-schedule.md",
"size_in_bytes": 65994
},
{
"relative_path": "guidance/guidance.md",
"size_in_bytes": 10089
},
{
"relative_path": "industry-classification/industry-classification.md",
"size_in_bytes": 14286
},
{
"relative_path": "net-working-capital/net-working-capital.md",
"size_in_bytes": 67190
},
{
"relative_path": "net-working-capital/restaurants/restaurantsNWC.md",
"size_in_bytes": 14901
},
{
"relative_path": "net-working-capital/retail/retailNWC.md",
"size_in_bytes": 13428
},
{
"relative_path": "net-working-capital/software/softwareNWC.md",
"size_in_bytes": 13331
},
{
"relative_path": "revenue/restaurants/comparableSalesGrowthBuild/comparableSalesGrowthBuild.md",
"size_in_bytes": 37415
},
{
"relative_path": "revenue/restaurants/comparableStoresBuild/comparableStoresBuild.md",
"size_in_bytes": 137823
},
{
"relative_path": "revenue/restaurants/franchiseRevenueBuild/franchiseRevenueBuild.md",
"size_in_bytes": 28958
},
{
"relative_path": "revenue/restaurants/locationBuild/locationBuild.md",
"size_in_bytes": 64937
},
{
"relative_path": "revenue/restaurants/other/other.md",
"size_in_bytes": 32707
},
{
"relative_path": "revenue/restaurants/restaurants.md",
"size_in_bytes": 23185
},
{
"relative_path": "revenue/restaurants/revenuePerRestaurantBuild/revenuePerRestaurantBuild.md",
"size_in_bytes": 44258
},
{
"relative_path": "revenue/retail/comparableStoresBuild/comparableStoresBuild.md",
"size_in_bytes": 218652
},
{
"relative_path": "revenue/retail/locationBuild/locationBuild.md",
"size_in_bytes": 85734
},
{
"relative_path": "revenue/retail/other/other.md",
"size_in_bytes": 43408
},
{
"relative_path": "revenue/retail/retail.md",
"size_in_bytes": 39183
},
{
"relative_path": "revenue/retail/sqftBuild/sqftBuild.md",
"size_in_bytes": 90674
},
{
"relative_path": "revenue/retail/unitsBuild/unitsBuild.md",
"size_in_bytes": 120932
},
{
"relative_path": "revenue/revenue.md",
"size_in_bytes": 6812
},
{
"relative_path": "revenue/software/arpuBuild/arpuBuild.md",
"size_in_bytes": 72611
},
{
"relative_path": "revenue/software/arrBuild/arrBuild.md",
"size_in_bytes": 66803
},
{
"relative_path": "revenue/software/customerRollForward/customerRollForward.md",
"size_in_bytes": 49822
},
{
"relative_path": "revenue/software/other/other.md",
"size_in_bytes": 43116
},
{
"relative_path": "revenue/software/software.md",
"size_in_bytes": 23925
},
{
"relative_path": "revenue/software/trBuild/trBuild.md",
"size_in_bytes": 82026
},
{
"relative_path": "scripts/README.md",
"size_in_bytes": 3338
},
{
"relative_path": "scripts/audit.py",
"size_in_bytes": 16187
},
{
"relative_path": "scripts/framework.py",
"size_in_bytes": 17707
},
{
"relative_path": "scripts/style.py",
"size_in_bytes": 6710
}
],
"name": "operating-model",
"skill_md_contents": "---\nname: operating-model\ndescription: >\n Builds a full Excel operating model for a US public company from Revelata\n deepKPI data. Resolves a ticker or company name, classifies it as restaurant,\n retail, or software, and stops without creating a workbook for unsupported\n industries. Creates a single-sheet model with Revenue, Costs, Consolidated\n Financials, Depreciation Schedule, and Net Working Capital sections; discovers\n the KPI inventory once; and orchestrates the section sub-skills in dependency\n order. Triggers include \"build an operating model\", \"build a model for\",\n \"model out this company\", \"set up the model\", and \"scaffold a model\". For a\n single section, KPI pull, or filing text, use the narrower skills.\n---\n\n# operating-model\n\nThis skill is the **orchestrator** for building an operating model. Its own job\nis narrow: **resolve the company**, **have its industry classified once** (and\nstop if it is not one the skill models), **lay down a styled, empty workbook\nskeleton** with the five canonical section headers, and **discover the company's\nfull KPI inventory once** so it can be shared. It does **not** populate any\nsection itself — each section is built by a dedicated sub-skill that this skill\ninvokes in turn, drawing on the shared KPI inventory.\n\n**The sole data source for all figures is deepKPI.** Do not use training\nknowledge, analyst reports, or any other source for financial figures. Every\nnumber that eventually lands in the workbook must trace back to a deepKPI call\n(enforced by the sub-skills).\n\n## GOLDEN RULES (non-negotiable — read before every build)\n\nThese rules override convenience, speed, and your own judgment. Violating any of\nthem is a failed build, even if the output looks correct.\n\n1. **Follow the workflow exactly, in order. Never look ahead.** Execute this\n skill's steps (and each sub-skill's steps) strictly in sequence. Do **not**\n open, read, or reason about a downstream sub-skill before the workflow has\n actually routed you there. You may only read a sub-skill's file at the moment\n the workflow hands control to it. Peeking ahead to \"see what's coming\" or to\n pre-plan biases your decisions and is prohibited.\n\n2. **Never skip `list_kpis`, and always wait for it to fully resolve.** The full\n KPI inventory discovery (Step 3) is mandatory and must complete before **any**\n routing or sub-skill work begins. It may be large and slow — that is expected.\n Wait for it. If the result is too large to read inline, page through it / parse\n it from the saved file, but **do not** substitute a handful of `search_kpis`\n guesses for the full inventory. Every routing decision depends on the complete\n inventory being in hand, and the sub-skills rely on it to know exactly what to\n call.\n\n3. **Route only on the available KPIs — never on your own knowledge.** Routing\n decisions (e.g. which revenue sub-build to use) must be made **solely** from\n what the KPI inventory contains, exactly as each router's criteria specify. Do\n **not** factor in anything else — not the company's real-world characteristics,\n and not which sub-skill is more complete. Facts about the **nature of the\n business** are not the routers' to decide: the company's **industry** and, for\n software, its **revenue model** (platform / subscription / advertising / mixed)\n are determined exactly once, by the `industry-classification` sub-skill in\n Step 1.2, from the 10-K business description, and handed to the routers as\n inputs. A router may use those determinations and the inventory, and nothing\n else. A company outside the three supported industries (restaurant, retail,\n software) stops at Step 1.2. Nothing is ever routed to a placeholder.\n\n4. **Do not go off on tangents. Build only what the active skill specifies —\n nothing more.** If a sub-skill says it is authored section by section and that\n only the sections present are implemented, build **exactly** those sections and\n **stop**. Do **not** invent, add, \"improve,\" or extrapolate extra sections,\n line items, or analysis beyond what the current skill explicitly defines, even\n if you think it would be helpful. When a skill is incomplete, stop and say so —\n do not fill the gap with your own construction.\n\nIf a rule here conflicts with something you want to do, the rule wins. When in\ndoubt, stop and ask the user rather than improvising.\n\n## Model timeline — historical and projection years\n\nThis section is the **single source of truth** for the model's fiscal-year\ncolumns. **Every sub-skill inherits this timeline; none defines its own.**\n\nLet **`N`** = the **last historical fiscal year** — the most recent fiscal year\nfor which deepKPI has complete reported actuals.\n\n- **Historical years (actuals).** The **four most recent fiscal years** with\n deepKPI actuals: **`N−3`, `N−2`, `N−1`, `N`**. This is the established window the\n revenue build lays down and every downstream section mirrors; older years are\n dropped.\n- **Projection years (forecast).** The **five fiscal years immediately after the\n last historical year**: **`N+1`, `N+2`, `N+3`, `N+4`, `N+5`**. The projection\n window is therefore **always five years long**, beginning the year after the last\n historical year.\n - *Example:* if the last historical year is **FY2025**, the projection years are\n **FY2026, FY2027, FY2028, FY2029, FY2030**.\n- **Full model horizon** = the four historical years followed by the five\n projection years, oldest → newest, left → right: **`N−3 … N`** (historical) then\n **`N+1 … N+5`** (projection) — **nine fiscal-year columns** in total.\n\nNotes on this definition:\n\n- **\"Fiscal year\" means the company's fiscal year-end**, not the calendar year —\n many issuers are non-December. `N` is the latest fiscal year fully reported in\n deepKPI.\n- The historical/projection boundary is also where cell behavior changes:\n historical columns carry reported deepKPI inputs and live historical formulas;\n projection columns carry the forward drivers/assumptions.\n- **Scope of this section:** it fixes *which* fiscal years are historical and\n which are projection, and nothing else. How each section lays its projection\n columns — its drivers, their seeds and the formulas that invert them — is\n defined in that section's own file (every build carries a Projections section);\n build the projection columns exactly as the active sub-skill instructs, never\n from this definition alone.\n\n## Units, scale, and number format\n\n`../_common/revelata-excel-units-and-scale.md` is the **single source of truth** for how\nevery number in this model is stored, scaled, and labeled. **Read it before\nwriting any cell, and follow it in every section.** Like the **Model timeline**\nabove, it is a sheet-wide contract that the sub-skills inherit.\n\nA sub-skill may override a **display scale** or a **tag** for a named row or family\nwhere its own file says so explicitly; nothing may override base-unit storage or\nreintroduce a scale constant. Money **precision** is not a stage's choice either: the\nrenderer derives one format per money family from the stored historical inputs (one\ndecimal when the issuer reports below the display unit, whole units otherwise, the\ncontract's Rule 3) and the audit verifies it. The contract's **Rule 6** defines the audit that\n**Step 5** runs before delivery.\n\n## Contract rows — the labels sections may reference across section boundaries\n\nThe CONSOLIDATED FINANCIALS and DEPRECIATION SCHEDULE builders are identical for every\nindustry and carry no industry knowledge; they reach into the REVENUE and COSTS sections\n**only through the rows below, by these exact labels**. The NET WORKING CAPITAL\nbuilder's mechanics are industry-free too, and its industry knowledge is confined to\none **driver map** per industry (`net-working-capital/<industry>/`) that names which\nupstream rows its drivers divide by — the contract rows below plus, under the\nissuer's own captions, the cost-of-sales and labor lines the map describes. Every revenue\nand cost build must lay the rows that apply to it under these labels, whatever the\nissuer's own caption is (the issuer's wording goes in the Col C comment). A downstream\nbuilder never resolves a label by industry, by example, or by fallback between two\nspellings. Each contract row also has a **fixed key**, the `{key}` a formula writes to\nreference it (Build mechanics), so a cross-section reference is exact whatever anyone's\nspelling of the label; and an **existence condition**, evaluable from the shared\ninventory or a hand-back report, which is how a downstream stage tells a row that is\nmissing from one that never exists for this company (Step 4.2).\n\n| Contract row | Key | Laid by | Exists when | Meaning | Status |\n|---|---|---|---|---|---|\n| `Total Revenue` | `rev_total` | every revenue build (the grand-total row of its consolidated revenue table) | always | reported total revenue in history; the assembled total in projection | in force 2026-10-12 |\n| `Revenue from <Stream>` | `rev_<stream>` (slug of the issuer's caption), one per stream | the software revenue builds and the retail units and square-footage builds, one row per named revenue stream each lays; a build whose single metric covers all revenue lays none — its one row is `Total Revenue` (the ARPU build's covers-all case) — (the stream's own block value row and the row that restates it in the consolidated revenue table carry this same label; `<Stream>` is the issuer's caption with the issuer's own revenue noun removed and every other word kept, including a qualifier such as \", net\": `Subscription` → `Revenue from Subscription`; `Credit card revenues, net` → `Revenue from Credit Card, net`; `Macy's Media Network revenue, net` → `Revenue from Macy's Media Network, net`; `Net revenue from licensing` → `Revenue from Licensing, net`. The noun removed is one of revenue, revenues, sales, net sales; nothing else is shortened, reordered or renamed, and the issuer's full caption goes in the Col C comment. A caption that is only a revenue noun (`Revenues`, `Net sales`) is a total, never a stream; the residual plug is always `Other Revenue` and never carries a stream name) | for each named stream the revenue build lays; never for the residual, which is `Other Revenue` (`rev_other`) | that stream's revenue — the denominator a cost-of-revenue line divides by; the software cost build matches a cost line to its stream by this label and falls back to `Total Revenue` when no row matches | in force 2026-10-12 |\n| `Net Sales` | `net_sales` | every retail revenue build, only when the issuer's income statement shows a merchandise net sales line **and** at least one separate revenue line (membership fees, other revenue); omitted for a single-revenue-line issuer | the shared inventory's `Consolidated Income Statement` shows a merchandise net sales line **and** at least one separate revenue line | the reported merchandise net sales line — the base the retail cost build strikes cost of sales against; it falls back to `Total Revenue` when the row is absent (a row-presence test). Retail-internal, like `Revenue from <Stream>` for software | in force 2026-10-13 |\n| `Total Costs and Expenses` | `tce` | every cost build | always | the all-in total of every additive cost line between revenue and `Operating Income (modeled)`, including cost of sales / cost of revenue; `Operating Income (modeled) = Total Revenue − Total Costs and Expenses` | in force 2026-10-12 |\n| `Total Costs and Expenses — <Segment>` | `tce_<segment>` | cost builds on a segment path (C1 / C2) | the cost build ran a segment path (its hand-back report says which) | that segment's all-in subtotal; forward, the segment subtotals and the consolidated total tie by the spine rule in `costs/segmentSpine.md` | in force 2026-10-12 |\n| `Operating Income (modeled)` / `Operating Income (reported)` | `oi_modeled` / `oi_reported` | every cost build | always / when the inventory lists a reported operating-income line | modeled operating income and the reported cross-check | in force 2026-10-12 |\n| `Depreciation & Amortization` | `dna` | the depreciation schedule (its `Depreciation` build) | always | the model's single D&A source: cash-flow D&A in history, `prior-year Net PP&E ÷ Implied Useful Life` forward. CONSOLIDATED FINANCIALS' `Total Depreciation & Amortization` references it in every column; a cost build's total-D&A line references it in the projection columns. A cost build that carries no D&A line (D&A embedded in its cost lines) references nothing — the consolidated section still has its source | in force 2026-10-12 |\n| `Company-Operated EOP Balance` | `coeop_total` (consolidated); `coeop_<brand>` per brand / banner block | every location build (its consolidated Total block) | a location build ran (the revenue hand-back report says so) | the consolidated company-operated unit count — the per-location denominator for the cost builds' per-location rows and NWC's lease driver; a downstream builder keys its fallback on the row's absence, never on the industry | in force 2026-10-12 |\nThe cost-of-sales line is **not** a contract row: its only downstream reader, the NET\nWORKING CAPITAL build, resolves it through its industry driver map, under the issuer's\nown caption.\n\n**The segment map.** A segment's revenue is not a contract row either, because a revenue\nbuild may lay it as one row or as several (a brand's row; an advertising stream plus that\nsegment's other-revenue stream). The revenue stage's hand-back report therefore carries a\n**segment map**: for each issuer segment the build laid revenue rows for, the segment's\nname as the inventory's segment series spell it and the keys of those rows; an empty map\nwhen the build laid no segment, brand or banner rows. The orchestrator passes it with\nthe revenue hand-back to the costs router and to the consolidated section (Step 4). A\ncost build on a segment path takes each segment's revenue from the map and from nothing\nelse; the consolidated section lays its segment revenue lines from the same map. No\ndownstream stage resolves a segment by comparing labels.\n\n### Lays when — the row-condition vocabulary\n\nEvery stage file specifies its rows in tables that carry a **`Lays when`** column. That\ncolumn says under what condition the row must be on the sheet, and `scripts/audit.py`\nreads it at Step 5 to check that every specified row was laid. The values below are\nthe only ones the column may hold; they are defined here once, mirrored as constants\nin `scripts/audit.py`, and `make lint` rejects any other value.\n\n| Value | Meaning |\n|---|---|\n| *(blank)* | the row is always laid, and its historical cells are never all dashes. This is the default; `ALWAYS_COMPLETE` is its explicit spelling. |\n| `ALWAYS_COMPLETE` | as blank, written out |\n| `ALWAYS_DASHES_OK` | the row is always laid; its historical cells may all be dashes where the issuer reported nothing (an intermittent impairment line, a stream disclosed in one year) |\n| `DATA_DEPENDENT` | the row is laid only when the issuer reports the line, which the sheet cannot prove either way; the audit does not check it. Prefer `ALWAYS_DASHES_OK` wherever the text can lay the row empty instead — except for a reported anchor (`<row> (reported)`) and its `Memo: … − reported` check: when the issuer does not report the figure, both are omitted, never laid as dashes, because a check row with nothing to check reads as a failed check; completeness is still tested by the required `Operating Income (reported)` foot |\n| a flag expression | the row is laid, complete, exactly when the expression is true; `NOT` and `AND` over the flags below, e.g. `NOT HAS_DNA_EMBEDDED`, `HAS_LOCATION_BLOCK AND HAS_SEGMENT_ROWS` |\n\nEach flag is the presence of one fixed-label row on the finished sheet, so the audit\nreads it from the workbook and never from a hand-back:\n\n| Flag | True when the sheet has |\n|---|---|\n| `HAS_GROSS_PROFIT_ROW` | a `Gross profit` row in COSTS (the issuer presents a gross-profit subtotal) |\n| `HAS_DNA_EMBEDDED` | a `Memo: depreciation and amortization (embedded in the lines above)` row in COSTS — the retail cost build's memo row for an issuer whose D&A sits inside cost of sales and SG&A with no face line; the software build records the same fact in Notes and lays no row, so the flag is false on a software sheet and no software row keys on it |\n| `HAS_SEGMENT_ROWS` | any `Total Costs and Expenses — <Segment>` row in COSTS (a segment cost path ran) |\n| `HAS_LOCATION_BLOCK` | a `Company-Operated EOP Balance` row in REVENUE (a location build ran) |\n| `HAS_NET_SALES_ROW` | a `Net Sales` row in REVENUE (the issuer reports merchandise net sales separately) |\n\nA row whose label is a template (`Revenue from <Stream>`, `<Banner> — Costs`) is not\nchecked by label; the memo rows that foot those families to reported totals are what\nguard them, and the audit checks every memo's content.\n\n## Build mechanics — compose the sections, then render the workbook\n\nThe workbook is never edited in place. Every section is composed as a list of keyed\nrows, and the whole workbook is regenerated from those lists on every render, in the\nscaffold order of Step 2. `scripts/framework.py` is the single implementation of this\nmechanic, `scripts/style.py` the single implementation of the styling and units\ncontracts, and `scripts/README.md` shows the build-directory layout. Four rules\nfollow:\n\n- **One module per section, returning rows.** A section module returns its rows\n (`Row` objects) and its notes, nothing else. It never opens the workbook, never\n writes a cell, never computes a sheet address.\n- **Formulas reference rows by key, never by address.** A formula writes `{key}`\n where it needs another row's row number (`=F{rev_total}-F{cost_total}`), and the\n renderer resolves every key at render time. A section may therefore reference a row\n that another section lays down, whichever is written first and wherever it sits on\n the sheet.\n- **Build order and sheet order are independent.** Step 4 builds the sections in\n dependency order (revenue → depreciation schedule → costs → consolidated financials\n → net working capital); `assemble()` always places them in the Step 2 scaffold\n order. Nothing about the sheet layout changes when the build order changes.\n- **Rendering is whole-workbook, from scratch.** `render()` assigns row numbers,\n resolves keys, applies the styling in `style.py`, sets every row's indent from its\n kind (the styling rules' indent hierarchy: a stage indents only its headers), writes\n the Notes block, and saves.\n Re-running the build after any change re-resolves every reference: there is no\n insertion into a saved workbook and no address that can go stale. A key that no\n assembled section lays down is a render error naming the key and the referencing\n row, not a `#REF!` discovered later.\n\n- **A stage owns its rows; the renderer is never the fix.** Every row has one owner,\n the section or sub-build whose file defines it, and no stage adds, removes or edits a\n row in another stage's module. A stage that needs a row it does not lay references it\n by key and, if the row is missing, reports it (Step 4.2) rather than laying it. What\n gets edited in a correction is always the owner's **section module**, the file the\n agent wrote for that stage; `framework.py`, `style.py` and `audit.py` are fixed plugin\n code. Build-process history — findings, re-runs, their outcomes — goes to\n `BUILD_LOG.md` in the build directory, never into the workbook's Notes block, which\n carries only modeling facts. A **modeling fact** is what a reader needs to interpret\n a number on the sheet: what a line contains, why a plug or a ratio has the size it\n has, which convention or basis was applied. **Build history** is what was tried,\n changed or re-run. The explanation of a plug is a fact and stays on the sheet; the\n story of how the builder found it is history and goes to the log.\n- **Three places for what a build records, and the test for each.** Everything a\n stage would write down goes to exactly one of these:\n - **Notes block** — a modeling fact an analyst needs to read the model: what a line\n contains, which basis or convention a ratio uses, a judgment the build made where\n the filing allowed more than one reading, a default the analyst may want to\n override. One line per fact, written as `<Section>: <fact>` in the analyst's\n words, for a reader who has not read this skill: no section numbers, no route,\n tier, path, mode, case or layout names, no driver colors, no words such as\n contract row, spine, hand-back or stage.\n - **`BUILD_LOG.md`** — build history: which route, tier, path or mode ran and why,\n which series was chosen over a sibling, which checks were run and what they\n returned, every re-run and its outcome, every data trap met.\n - **Cell comment** — provenance and basis for one row, on its Col C label cell: the\n series or filing a value came from, the denominator a ratio divides by, which rung\n set a seed. An input cell itself carries no comment — its hyperlink and Col A series\n name are the provenance — unless the value is an override or on a basis the link\n does not show.\n A stage file that says \"record\" or \"note\" something names the place; where it\n does not, apply the test above.\n\nAfter every render, recalculate with the xlsx skill's `recalc.py` (zero formula\nerrors); at Step 5, run `scripts/audit.py`.\n\nThe styling rules and the units contract in `../_common/` remain the specification;\n`style.py` carries their values (colors, number formats, borders) once. Skill text\nnames a convention — \"pale-green input fill\", \"red driver\", \"SUM-BAR\" — and never\nrestates a color code or a format string. A change to a rule is made in the rule\ntext and in `style.py` in the same commit.\n\n- **A rate names its base, and a count identity holds only counts.** A rate\n driver's Col D tag names the row its formula multiplies or divides by, and that\n row is on the sheet; a formula never applies a rate to a different row than its\n tag names. A row inside an identity of counts (a unit roll, a store roll) is a\n count, so a percentage never enters a sum of counts. A quantity the issuer states\n as a share of a base is converted on the sheet from a visible share input against\n the row that carries that base, never typed into a formula as a constant; where\n the issuer's base is not one row, the share applies pro rata to each row that\n carries part of it, the comment saying so.\n- **The default driver seed is the analyst's: guidance, else the latest year.**\n Every forward driver the builds lay takes its `N+1` value from the first of\n these rungs that applies, and every later year references the `N+1` cell, so\n the assumption is held flat and an override of `N+1` moves the whole line:\n 1. **Guided.** The shared guidance table from Step 3.5 names the driver for\n fiscal year `N+1`: the midpoint of the range, written with `drivers_fixed()`\n as a red driver hyperlinked to the earnings-release exhibit, the comment\n quoting the issuer's words.\n 2. **Latest year, on the issuer's normalized basis.** The issuer discloses the\n latest year's figure with a distortion removed (organic or constant-currency\n growth, a 52-week comparable, a go-forward sales change, a balance net of a\n named one-off item): that figure, as a red constant with the disclosure cited\n in the comment. The reported historical cell is never changed.\n 3. **Latest year as reported.** `drivers()` in `scripts/framework.py` writes\n `= IF(ISNUMBER(N), N, IF(ISNUMBER(N−1), N−1, IF(ISNUMBER(N−2), N−2, 0)))`:\n the most recent numeric value among the three seed years, and **0** when\n there is none (a decomposition disclosed only in the base year). The guard is\n `ISNUMBER`, never `IFERROR`, so a genuine error still surfaces.\n 4. **Latest undistorted year.** Only when `N` itself is a disclosed distortion\n and no normalized figure exists — a program year in a unit roll, a 53-week\n `N` under a growth driver, the first comparison after an acquisition — the\n seed references the latest clean year among `N−1` and `N−2`, and the comment\n names the distortion.\n No build averages years into an `N+1` seed, drops a year on its own judgment, or\n seeds a CAGR. The one stated exception is the comparable-sales builds' `N+2`\n rate, which reverts to the historical average comp as the long-run rate after a\n guided or recency-seeded first year; elsewhere a multi-year average appears only\n where a file lays it as a memo. The latest year\n is the convention because it carries no mechanical step at `N+1`: the first\n forward year continues the last actual, and the analyst's view goes on top as an\n override. The driver's cell comment states which rung set it; the build does not\n stop or ask.\n- **Episodic cost lines are the one exception to the default seed.** Impairments,\n restructuring and closing charges, settlements and asset gains or losses are seeded\n by the rule in `costs/episodicLines.md`, which every cost build reads at its driver\n methodology step: zero for a one-off, a run-rate for a recurring program line, the\n disclosed remaining cost where the filing states one. The renderer writes those\n seeds with `drivers_fixed()` and `drivers_runrate()`; the default seed is never\n applied to a line in that class.\n- **One seed for every driver; the residual is a ratio driver.** No build seeds a\n driver on a CAGR: a named revenue stream's `YoY %` takes the\n default seed above, and a historical CAGR appears only as an informational memo\n where a build lays one. A revenue build's residual plug (`Other Revenue`, the\n reported total less the named components) cannot stay a plug in projection,\n because there is no reported total to plug against, and it is never seeded to zero\n dollars, which would step projected revenue down at `N+1`. It is projected as a\n **share of modeled revenue**: a driver row `Other Revenue — % of modeled revenue`,\n tagged `(% of modeled revenue)`, holds the historical ratio of the residual to\n the named components the build projects (never to a total that contains the\n residual, which would be circular) and takes the default seed in projection; the\n residual is then that driver times those components. The row's historical cells\n are the build's fit diagnostic (low single digits expected) and are visible, not a\n memo.\n\n## Data source\n\nSee `../_common/data-source-rules.md` for the MCP-vs-REST routing table and the\ncanonical inventory of deepKPI operations. This skill uses `query_company_id`\n(to resolve the company) and `list_kpis` (to discover the full, shared KPI\ninventory once); the `industry-classification` sub-skill it invokes at Step 1.2\nuses `get_company_summary` once; the `guidance` sub-skill it invokes at Step 3.5\nuses `list_sec_filing_markdowns` and one `get_sec_filing_markdown` to read the\nlatest earnings-release exhibit once; the section sub-skills then use\n`search_kpis` and the statement operations against that shared inventory.\n\n## Hard stop if deepKPI access fails\n\nSee `../_common/connection-failure.md`. If deepKPI is unreachable, STOP and ask\nthe user before falling back to any other source.\n\n## Opening line\n\nBefore doing anything else, say:\n\n**\"Let me resolve the company in deepKPI and set up the operating model\nscaffold.\"**\n\n## Step 1 — Resolve the company and classify its industry\n\n### 1.1 — Resolve the company\n\nThe user provides **either a ticker or a company name**. Detect which:\n\n- **Looks like a ticker** — 1–5 characters, all uppercase, no spaces (e.g.\n `DRI`, `CMG`, `AAPL`): map it to the **official registrant name** first. Use\n your knowledge of the common ticker → issuer mapping, and if there is any\n ambiguity, ask the user to confirm the company before proceeding. `query_company_id`\n resolves by **name**, not ticker.\n- **Looks like a company / brand name** (e.g. `Darden`, `Olive Garden`,\n `Chipotle`): use it directly. If the user named a **brand or subsidiary**, map\n it to the **parent registrant** first (e.g. \"Olive Garden\" → \"Darden\n Restaurants\").\n\nThen call **`query_company_id`** with the official `company_name` (set\n`num_of_res` to 3 so you can disambiguate). Take the `company_id` (SEC CIK for US\ncompanies) from the response. If multiple plausible matches come back, show them\nand ask the user to pick. **The `company_id` is required by every sub-skill**, so\ncarry it forward.\n\n### 1.2 — Classify the industry (supported: restaurant, retail, software)\n\nInvoke **`industry-classification/industry-classification.md`**, passing the\nresolved `company_id` and the official company name. It makes one\n`get_company_summary` call, applies its criteria in fixed precedence, and hands\nback either **`industry: restaurant | retail | software`** with a one-line basis,\nor **`UNSUPPORTED — <basis>`**.\n\n- **Supported** → carry the industry and its basis forward — and, for software,\n the **revenue model** the skill also returns. The `revenue` router, the `costs`\n router and the `net-working-capital` build receive the industry in Step 4 and\n act on it; the software revenue router also receives the revenue model. None of\n them re-classifies.\n- **`UNSUPPORTED`** → **stop here.** Tell the user, in one short paragraph, that\n this skill currently models **restaurant, retail and software** issuers, what\n the company was classified as and why (the basis), and that no workbook was\n created. Do not scaffold, do not run `list_kpis`, do not route anywhere, and do\n not improvise a generic build. The classification runs before Step 2 precisely\n so that an unsupported company costs nothing and leaves nothing behind.\n\n## Step 2 — Build the empty, styled workbook scaffold\n\nProduce **one** `.xlsx` workbook with a **single worksheet** containing the five\nsections **stacked vertically in this exact order**:\n\n1. `REVENUE`\n2. `COSTS`\n3. `CONSOLIDATED FINANCIALS`\n4. `DEPRECIATION SCHEDULE`\n5. `NET WORKING CAPITAL`\n\n**Fix the model timeline first.** The renderer cannot render anything, the scaffold\nincluded, without a configured timeline, and it writes every fiscal year-end into the\nperiod header row on every render. So before the scaffold, set a **provisional `N`**:\nthe fiscal year of the latest annual filing in the free `list_sec_filing_markdowns`\nlisting (one call, no credits), with the issuer's fiscal year-end convention read from\nthe same listing. Pass `hist = N−3 … N`, `proj = N+1 … N+5` and the year-end dates to\n`configure(...)`. `N` is provisional because the listing can run a year ahead of the\nannual series deepKPI holds; the revenue build confirms it (Step 4, item 1).\n\nProduce it with the renderer — `scaffold()` in `scripts/framework.py` after\n`configure(...)` (see **Build mechanics**) — which applies\n**`../_common/revelata-excel-styling-rules.md`** for all layout and visual\nconventions. The scaffold is what the renderer produces when no section has been\nassembled yet. Concretely:\n\n- **Columns A and B are hidden** (audit-trail columns); leave **A1:B1 empty**.\n- **C1** = the workbook title: **bold, Calibri, 12pt, sentence case**, containing\n the **full official registrant name** (from `query_company_id`) plus what the\n sheet is, e.g. `Darden Restaurants, Inc. — operating model (deepKPI)`. Merge\n rightward (C1:D1) if long.\n- **Row 2 is fully blank** (spacer between the title and the body).\n- **Gridlines off** for the sheet; font **Calibri** throughout.\n- Lay down the five **ALL-CAPS section header rows** in the label column (Col C),\n each **bold and underlined and font size 16**, separated by at least one blank\n spacer row. The renderer places each section's rows beneath its header on every\n render; nothing is inserted into this file later.\n- **The period header row carries the timeline's year-end dates**, written by the\n renderer from `configure(...)`: the four historical fiscal years followed by the\n five projection years, per the **Model timeline** above. Nothing else is filled in:\n no data, line items or values. The sub-skills lay the rows beneath the headers.\n- Apply **freeze panes** consistent with the styling rules (Cols A–D and the\n title region stay visible).\n\nSave the scaffold to the user's workspace folder and report the saved path, as a link\nwhere the runtime offers one, so the user can see the skeleton before sections are\nfilled.\n\n## Step 3 — Discover the full KPI inventory (once, shared)\n\n**After** the scaffold is laid down and **before** routing to any sub-skill,\ndiscover **every KPI deepKPI has for this company** in a single call, so all the\nsub-skills draw from **one shared inventory** instead of each re-discovering KPIs\non their own.\n\nCall **`list_kpis`** with the resolved `company_id`. See\n`../_common/deepkpi-api.md` (the `/v1.0/list_kpis` entry and \"Step 2 — Discover\navailable KPIs\") for the exact call. Key points:\n\n- **This call is free** — no credits — so always run it here rather than letting\n each sub-skill spend `search_kpis` credits to find the same names.\n- Omit the `source` filter so the inventory spans **all filing types** (both\n annual 10-K and quarterly 10-Q metrics).\n- The response is a JSON object keyed by **category** — `Company KPIs`, `Segment\n Financials`, `Consolidated Income Statement`, `Consolidated Balance Sheet`,\n `Consolidated Cash Flow`, `Capital Structure`, `Taxes`, `Miscellaneous`,\n `Off-Balance Sheet Items` — with each value an array of exact KPI name strings.\n\nRead through the full inventory and **understand what is available** before\nproceeding: note which categories are populated, which segments/brands appear,\nand which KPI names map to each of the five sections. **Retain this inventory in\ncontext as the shared KPI map** and pass it to every sub-skill in Step 4.\n\nIf `list_kpis` returns nothing or fails, follow `../_common/connection-failure.md`\n(STOP and ask) — do not silently fall back to per-section discovery or other\nsources.\n\n**Which filing a historical value comes from.** A series' points are each taken from\nsome filing, and an issuer may present the same year differently in a later one: a\nline reclassified, a figure restated, a line absorbed into another. Every stage applies\none rule: **a historical value is carried on the latest filing's presentation.**\n\n- Before a stage takes a series for any line, it **lists every inventory series whose\n caption names that line** (the face caption, a `Total …` prefix, the note total, a\n segment or geography variant), across **every category** of the inventory and not\n only the category the line was found in; the inventory is in hand and the scan\n costs nothing.\n When that scan finds **two or more series for one caption**, compare their\n overlapping years with the latest 10-K and take the series that matches it; where\n the latest 10-K does not present the year, the provenance-id test below decides.\n Never take the first series found, and never skip the scan because the first\n series looked complete.\n- When a later filing **restates** an earlier year, the restated figure is the value and\n the as-filed figure goes in the cell comment (\"as filed in the FY<year> 10-K: <value>\").\n Which filing a point comes from is read from its provenance id, not from the filing\n text: a deepKPI point carries a date and a docviewer id, and every point sharing one\n id was taken from one filing, so **the latest-dated point under an id is that\n filing's own year**. For year `Y`, the point whose id also carries a later year came\n from the later filing and is the restated value. Where the competing ids both end at\n `Y`, the FY`N` 10-K read in Step 3 settles it; where `Y` is outside that 10-K's\n window and the ids still tie, carry the point whose id ends at `Y`, the other in the\n comment, and log the choice.\n- When a line reported in earlier years is later **absorbed into another line**, the\n receiving line is on a consistent basis only if the absorbed line is carried as its own\n row in the years it was separate, dashes after, so the totals agree across the window;\n where the inventory has no series for it, carry the latest presentation and state the\n break in a Notes line (\"<Section>: FY<a>–FY<b> <line> excludes <absorbed line>, which\n the issuer folded into it from FY<c>\"). A line reported in some years only is never\n omitted on that ground alone.\n- Every such choice is one line in `BUILD_LOG.md`; a historical cell that differs from\n the as-filed figure gets the Notes line above.\n\n## Step 3.5 — Pull the issuer's guidance (once, shared)\n\nAfter the inventory and before any section is built, invoke\n**`guidance/guidance.md`**, passing the `company_id`, the company name and the\nmodel timeline. It lists the company's 8-K filings, pulls the **latest\nearnings-release exhibit** once, and hands back a **guidance table** for fiscal\nyear `N+1`: each guided item from its fixed list with the low, high and midpoint,\nthe basis the issuer states, the verbatim phrase and the citation. An issuer that\nguides nothing hands back an empty table, which is a normal outcome, not a stop.\n**Retain the table in context and pass it to every sub-skill in Step 4** beside\nthe inventory: it is the first rung of the default driver seed (Build mechanics)\nand the source of the guidance check in CONSOLIDATED FINANCIALS. No sub-skill\npulls a filing to look for guidance on its own.\n\n## Step 4 — Hand off each section to its sub-skill\n\nAfter the scaffold exists **and the shared KPI inventory and guidance table are in\nhand**, build the sections **in order** by invoking the sibling sub-skills, passing\neach the resolved `company_id`, the official company name, the workbook path, **the\nshared KPI inventory from Step 3 and the guidance table from Step 3.5** so they can\ngo straight to the relevant KPI names (using `search_kpis` only for the specific\nseries they need, not to re-discover the catalog) and seed guided drivers without\nre-reading any filing. Every sub-skill inherits the **Model timeline** defined\nabove — the four historical fiscal years (`N−3 … N`) plus the five projection\nyears (`N+1 … N+5`) — and must not define its own:\n\n1. **`revenue`** — routes by industry and builds the revenue model beneath the\n `REVENUE` header. Pass it the **industry determination from Step 1.2** — and,\n for software, the **revenue model** — in addition to the standard inputs; it\n routes on those and does not classify.\n **Capture, when the revenue build returns, the segment map** from its hand-back\n report (\"The segment map\", above) and, **for retail, the revenue build method**\n (which revenue sub-build ran) — the costs router and the consolidated section need\n them.\n **Confirm `N`** when the revenue build returns: its first annual series shows the\n last fiscal year with complete actuals. If that differs from the provisional `N`\n of Step 2, re-run `configure(...)` with the corrected timeline, re-run Step 3.5\n (its table is keyed on `N+1`), re-run the revenue stage against the corrected\n years, and render again; rendering is whole-workbook, so nothing provisional\n survives. No later stage has run at that point.\n2. **`depreciation-schedule`** — builds the PP&E roll-forward beneath the\n `DEPRECIATION SCHEDULE` header, including the model's single D&A source (the\n contract row `Depreciation & Amortization`). **Runs after `revenue`** (its capex\n and Other rows are a % of `Total Revenue`) **and before `costs`**, because the\n cost build's forward D&A and the consolidated financials' D&A reference it. On\n the sheet it still sits fourth; see **Build mechanics**.\n3. **`costs`** — builds the cost structure beneath the `COSTS` header. **Runs only\n after the `revenue` build is fully done** (it depends on the revenue lines and\n on the industry classification established during the revenue build) **and\n after the depreciation schedule** (its total-D&A line's projected cells reference\n the schedule). Pass it the **industry determination from Step 1.2, the segment map and, for\n retail, the build method captured from Step 4, item 1** in addition to the\n `company_id`, company name, workbook path, and shared KPI inventory, so the\n costs router can route by industry **without re-classifying**.\n4. **`consolidated-financials`** — builds the consolidated statements beneath the\n `CONSOLIDATED FINANCIALS` header, as references to the REVENUE and COSTS rows and\n to the depreciation schedule's `Depreciation & Amortization` row. Pass it the\n **segment map** captured at item 1 and the cost build's hand-back report (which\n path it ran).\n5. **`net-working-capital`** — builds the net working capital schedule. Pass it the\n **industry determination from Step 1.2** as well: it reads that industry's driver\n map (`net-working-capital/restaurants/`, `retail/` or `software/`) for which\n current operating lines to expect and which upstream rows its drivers divide by;\n its mechanics are the same for every industry.\n\n**Order dependency (non-negotiable):** `revenue` first; the `depreciation-schedule`\nbefore `costs`; `costs` before `consolidated-financials`; `net-working-capital`\nlast. The industry classified once in Step 1.2 is handed to both the revenue\nrouter and the costs router, so the two sections are always built for the same\ncompany profile; neither router re-derives it.\nThe build order deliberately differs from the sheet order: the renderer places every\nsection under its scaffold header regardless of when it was built, so a section's\nposition on the sheet never changes.\n\nEach sub-skill is responsible for its own deepKPI pulls, period columns,\nformulas, and styling (all of them also follow\n`../_common/revelata-excel-styling-rules.md` and\n`../_common/revelata-excel-units-and-scale.md`). Build the whole model **end to\nend** by default; pause after the scaffold and confirm between sections only when\nthe user asks to review the build section by section.\n\n### 4.1 — Vocabulary for the two loops below\n\nA **stage** is one unit of the build that lays rows: the location build, a revenue\nsub-build, the franchise block, the depreciation schedule, a cost build, the\nconsolidated section, net working capital. A build is the ordered list of stages actually\nrun, in the Step 4 order. A **router** (`revenue/revenue.md`, `costs/costs.md`, the\nindustry routers beneath `revenue/`) picks which stage file runs in a slot and runs its\nsection's stages in order; it lays nothing. This orchestrator runs the sections in order,\nkeeps the build's one log, and is the only thing that ever re-runs a stage. A stage or\nrouter returns an **outcome** by finishing its own hand-back section — `COMPLETE` with its\nhand-back report, or one of the fixed strings below.\n\n### 4.2 — A row missing upstream: the correction loop\n\nThe routers' `ABORTED` loop (their Step 4.1) handles a stage that cannot be built. This\nstep handles the other case: a stage finds that **a row it is entitled to expect from an\nearlier stage does not exist**. No stage ever lays, edits or plugs another stage's row;\nit reports, and the owner is re-run.\n\n**What a stage may report, and how it knows.** A stage may report only a row its own file\ndeclares in its **Dependencies** table: the row as that file names it, the stage that owns\nit, the **existence condition** under which the owner lays it, and the **fallback** when\nthe condition is false (the net-working-capital driver maps are the model). Contract rows\nare declared once in the table above with a fixed key and condition. Diagnosis is three\nmechanical steps: the row is in the stage's Dependencies table; its existence condition\nevaluates **true** on evidence the stage may read (the shared inventory, a hand-back\nreport, or the filing where the stage's own text already reads it); and no row in the\nowner's module matches it — the renderer reports the key unresolved, or the stage's own\ncheck finds none. Condition **false** is not a finding: the stage takes its declared\nfallback. A reference that is in no Dependencies table and does not resolve is not a\nfinding either: the build stops with `RE-ENTRY FAILURE — undeclared dependency: <stage>,\n<row>` and the pair is a skill defect to report, not something to work around.\n\n**Outcomes.**\n\n| Outcome | Returned by | Meaning |\n|---|---|---|\n| `DEFECT UPSTREAM — <owner>: no <row> for <scope>, <columns>; <evidence>` | any stage; returned **unchanged** by every router it passes through | a declared row whose condition is true does not exist. `owner` = the section and, where relevant, the stage within it, as the Dependencies table names it; `scope` = a brand / banner / segment as the owner's hand-back report spells it, or `consolidated`; `evidence` = the series or filing citation, informational only |\n| `RE-ENTRY FAILURE — <reason>` | the re-run owner, or this orchestrator | the row could not be laid; or the finding repeats one already acted on; or the dependency is undeclared |\n| `OUT OF ORDER — <section>` | a stage's prerequisite guard | this orchestrator's own error: build that section, then resume |\n\n**The loop.**\n\n1. **Report.** The stage stops at the check that found the row missing and returns the\n record to the file that invoked it, keeping its module as laid so far. A router\n returns the record unchanged as its own outcome, so every finding reaches this\n orchestrator by one or two hops; no file decides a level.\n2. **Repeat check.** Keep one **ledger** in `BUILD_LOG.md`, keyed by (owner, row,\n scope). A record whose key is already there is **not** re-run — the owner would\n produce the same module from the same text — and the stage that reported it receives\n `RE-ENTRY FAILURE — unresolvable` (step 5). This is the only termination guard and it\n is sufficient: findings travel backward in build order, re-runs forward, the possible\n keys are finite, and a re-run is deterministic. Log the record.\n3. **Re-run the owner.** Tell the owner's section router to re-run its section **from the\n owner stage forward** (re-run a cross-section builder directly). The owner reopens its\n own file — permitted under Golden Rule 1, the workflow now routes there — applies its\n own text to the finding, trying its own paths in its own order and testing after each\n whether a row matching the record now exists in its module, and commits the first path\n that satisfies it. **Satisfy or leave untouched:** if none does, it changes nothing and\n returns `RE-ENTRY FAILURE — <reason>` in its own terms (\"gross split disclosed at the\n consolidated level only\"). It re-pulls at most the series the finding needs; the\n inventory is never re-listed. It re-issues its hand-back report.\n4. **Re-run everything after the owner, in build order.** The router finishes its section\n from the owner forward — its route selection runs again as part of that, so routing\n re-evaluates itself — and this orchestrator then re-runs every later section. Each\n stage runs again from its own file against the rows that now exist, so every\n row-presence test is re-evaluated. Stages between the owner and the one that reported\n never see the finding; they are simply run again. There is no partial re-render: a\n forward re-run is always correct and is one to a few stages.\n5. **On `RE-ENTRY FAILURE`**, re-run the stage that reported with the reason. It does one\n of three things, in this order and nothing else: its declared fallback for that\n situation; its own `ABORTED` to its router, if it is a revenue sub-build that cannot\n build without the row; otherwise the build stops naming the row and the reason.\n6. **New information is a new finding.** A stage may report against the same owner again\n only with a different row or scope; the identical record is what step 2 refuses.\n7. **Log, not Notes.** Every event goes to `BUILD_LOG.md`. The workbook's Notes block\n carries only the **resulting modeling facts**, stated exactly as they would be had no\n loop occurred (\"Company Openings for <banner> are 10-K overrides, store activity table\n FY<n>\"). A resolved loop leaves no trace in the workbook. The loop never asks the user.\n\n**Two cases this loop does not cover.** A *wrong value* upstream is the owner's own\npre-delivery checklist's job — a downstream stage has no independent evidence about an\nupstream cell — and is never a finding. A customer roll-forward built on the *wrong\npopulation* is caught by the software router before it dispatches the ARPU build\n(`revenue/software/software.md`, Step 4), not downstream.\n\n## Step 5 — Final QC and correction pass\n\nAfter all five sections are built, run the **unit audit** defined in **Rule 6** of\n`../_common/revelata-excel-units-and-scale.md` across the finished workbook. Run it **in\ncode**, not by reading the sheet: all of checks 1–5 are mechanically computable, and\na by-eye pass is how unit defects reach delivery in the first place.\n\nThis step runs **once, at the end**, because the checks that matter most are\ncross-section: a sub-skill cannot see what display scale a sibling section chose.\n\n### 5.1 — Run the audit\n\nRun `scripts/audit.py` against the recalculated workbook, naming every stage file the\nbuild ran (the files `BUILD_LOG.md` records, in build order):\n\n```\npython3 scripts/audit.py <workbook> --last-hist-col <letter of N> --stages <stage file> <stage file> …\n```\n\nIt evaluates Rule 6 checks 1–5 over every row of the data region (Col E onward), for\nevery section, and prints the stored and displayed `Total Revenue` for check 6, which\nneeds one lookup against the cited filing. With `--stages` it also runs three checks\nagainst the stage files' own row tables:\n\n- **7 row presence** — every row a stage specifies with a `Lays when` that holds on this\n sheet (the vocabulary above) exists in that stage's section, and a required row whose\n historical cells are all dashes counts as missing unless its value is\n `ALWAYS_DASHES_OK`. The audit prints the stage list and the required set it derived,\n so an omitted stage file is visible in the output.\n- **8 memo content** — every row whose label ends `(must = 0)` reads zero within\n rounding in every historical column, and every `(must ≈ 0)` row within half a\n percent of that column's `Total Revenue`.\n- **9 margin reads** — `Gross margin` equals gross profit over revenue and\n `Operating margin` equals operating income over revenue in the last historical column.\n- **10 vocabulary** — no Notes row and no cell comment contains a section number, a\n route, case, mode, tier, layout or approach name, a driver color, or skill vocabulary\n such as contract row, spine or hand-back (Build mechanics, \"Three places\"). Runs with\n or without `--stages`.\n- **11 header rows** — a row with a label, no Col D tag and no value or formula in any\n period cell is a header: its period cells must be empty, never dashes, and its label\n bold and underlined (styling contract). A data row that is empty in a period shows a\n dash and carries a tag. Runs with or without `--stages`.\n\n### 5.2 — Report findings before changing anything\n\nEmit a findings table:\n\n| Row | Col C label | Check | Observed | Expected |\n|---|---|---|---|---|\n\nIf the audit is clean, say so explicitly — do not pass over it in silence.\n\n### 5.3 — Correct, within scope\n\n**Fix only:** missing or malformed Col D tags; wrong or missing number formats;\n`General`-format cells in the data region; display scales inconsistent within a\nfamily; and scale constants in formulas — fixed by correcting the **stored value**\nper Rule 1 and then deleting the constant, never by adjusting the constant.\n\n**Do not:** restructure rows, add or remove line items, change modeling drivers, or\nrevisit any routing or classification decision. If a finding cannot be corrected\nwithout making a modeling judgment, leave it in place and surface it in 5.4.\n\nA **row-presence** or **memo-content** finding (checks 7 and 8) is never corrected\nhere: it means a stage did not lay a row its own text specifies, or laid one that does\nnot foot. Re-run the owning stage from its file against the rows that now exist, as\nStep 4.2 re-runs an owner, then re-run every later stage in build order and render\nagain. A stage that cannot lay the row returns `RE-ENTRY FAILURE` naming it and its\nreason. The build does **not** stop: record the finding and the reason in\n`BUILD_LOG.md`, carry both into the report (5.4) as an unresolved finding, and finish.\nA reason of the form \"my own text omits this row for this case\" is a `Lays when`\ndefect in that file's row table — report it as a skill-text issue, not as a model\ndefect.\n\n**Never edit a stored value to make a check pass.** A stored number that disagrees\nwith the filing is a data problem, not a formatting one — report it.\n\n### 5.4 — Re-run, then report\n\nRe-run the audit until checks 1–11 return zero findings, or only the findings recorded\nas unresolved under 5.3. Then report to the user: what was corrected, any unresolved\nfinding with the owner's reason, and any judgment items needing their call — for example a bare\n`(%)` whose denominator is not clear from its row label, or a family whose\nconventional display scale is genuinely debatable.\n\n## Notes\n\n- **Derived cells must be live `=` formulas** wherever sub-skills compute values\n (margins, totals, imputed quarters) — never hardcoded results. This is enforced\n per section but the orchestrator should remind the user the model is built to\n recalc.\n- If the user only wants **one** section (e.g. just a revenue build), you may\n skip the **workbook scaffolding** (Step 2) — but **still do Step 1 (resolve the\n company and classify its industry) and Step 3 (discover the full KPI inventory\n via `list_kpis`)** before routing. The KPI discovery always runs first so the single sub-skill receives\n the same shared KPI inventory; only the scaffold is skipped. Then route straight\n to that section's sub-skill, passing it the `company_id`, company name, and the\n shared inventory (or use the `kpi` skill for a raw pull).\n- **Supported industries are restaurant, retail and software; there is no generic\n build.** Adding an industry means four things, all of them: a criterion in\n `industry-classification/`, a revenue build under `revenue/`, a cost build under\n `costs/`, and a net-working-capital driver map under `net-working-capital/`.\n"
}SHA-256 of public snapshot: ba81875dc3f72b0e69b0b569e9782a5a5ecf8e6f07fd833f281bad5f2b8360ae