git:20260908.8b8c750 to git:20260908.1bafa29

5 added, 112 removed. Audit A to A.

---
name: captable_analysis
- description: Compute conversion scenarios, stamp duty and red-flag findings over a stored cap-table snapshot, plus a deterministic HTML one-pager. Use after captable_build.
+ description: Compatibility alias for captable; use the canonical captable skill for capitalization reports.
---
# captable_analysis
- Analyzes a cap-table snapshot stored by `captable_build` (issue #17,
- skill 2). All numbers are computed deterministically in
- `lib/captable/model.py` and `lib/captable/rubric.py`; the LLM's only job is
- to phrase a narrative over the computed JSON — it may not compute or invent
- any figure.
-
- ## Usage
-
- ```bash
- # via the command harness (agents; returns the narrative). All options are
- # optional; round parameters default from the data and are recorded as
- # assumptions:
- python -m skills.harness /captable_analysis synthcap
- python -m skills.harness -- /captable_analysis synthcap --as-of 2026-06-30 --pre-money 8000000 --investment 2000000 --fx-rate USD=0.88 --currency CHF
- # or the CLI (also writes analysis_scenarios.json):
- python -m skills.captable_analysis run --startup synthcap
- python -m skills.captable_analysis run --startup synthcap --as-of 2026-06-30 --pre-money 8000000 --investment 2000000 --fx-rate USD=0.88 --currency CHF
- ```
-
- `synthcap` is the synthetic fixture dataset; substitute your startup's
- dataset slug.
-
- Reads `insights/captable/latest.json` (or the named snapshot), then:
-
- - accrues each executed CLA's loan balance to the analysis date under its
- extracted day-count and compounding (unstated → act/365 simple, recorded
- as an assumption; the accrual date vs the snapshot's as-of date is always
- disclosed); safe-harbor-capped loans accrue at the documented safe-harbor
- rate rather than the stated ceiling — an unquantified cap falls back to
- the ceiling with a loud overstatement disclosure,
- - reports a `maturity_conversion_at_fixed_price` block whenever a CLA
- fixes a per-share price for post-maturity conversion (implied shares at
- the accrued balance, and the company value that price implies over the
- current fully-diluted count — the discount/cap scenario prices apply to
- round conversions only),
- - keeps every loan in its own currency (`note_currencies`) and expresses
- the scenarios in ONE currency (`currency`: the loans' common currency,
- else CHF, or `--currency`). A loan in another currency needs
- `--fx-rate CUR=RATE` (units of the scenario currency per 1 CUR; balance,
- cap and floor convert at that rate, recorded as an assumption). Without
- a rate the scenarios and the stamp-duty estimate are **not computed**
- and a high-severity `mixed_currencies` scenario flag names the loans —
- a CHF and a USD loan are never summed into one figure,
- - computes conversion scenarios for a hypothetical round under all three
- market methods (`pre_money` / `percentage_ownership` /
- `dollars_invested`), side by side — CLAs are usually silent on the
- method, so no method is ever silently chosen; round parameters default
- from the data (largest cap, QEFR minimum) and are always recorded as
- assumptions,
- - reports `founders_post_round_pct` per scenario and raises a structured
- `scenario_flags` entry (`founder_majority_post_round`) when founders fall
- below 50% in every modelled scenario,
- - estimates the 1% issuance stamp duty as a structured `stamp_duty` block
- (estimate, CHF 1M lifetime exemption, remaining exemption) — only when
- the scenario currency is CHF; otherwise `estimate_chf` is null with a
- note,
- - applies the red-flag rubric (founder majority, investor dominance, dead
- equity, fully-diluted-definition ambiguity) — explicitly scoped to the
- snapshot date via `rubric_scope_note`, never to the post-round state,
- - labels reserved positions as `[reserved pool] …` in scenario ownership so
- pools are never listed as shareholders.
-
- ## Rendering (`render`)
-
- ```bash
- python -m skills.captable_analysis render --startup synthcap
- python -m skills.captable_analysis render --startup synthcap --as-of 2026-06-30
- ```
-
- Renders the snapshot as a self-contained HTML one-pager — **no LLM
- call**: every number is copied verbatim from the validated snapshot
- (ownership bar by role, holder table with classification badges, share
- classes, pools, CLA overhang with maturity/e-sign status, validation
- traffic lights), so the visual a reviewer looks at can never drift from
- the stored data. Percentages use the same denominator as
- `rubric.ownership_by_role`. When `analysis_scenarios.json` exists AND was
- computed over the same snapshot state — same as-of date AND same content
- fingerprint (`snapshot_fingerprint`, a hash of the snapshot minus its
- generation timestamp) — the conversion-scenario table is included.
- Scenarios from another as-of, or from an earlier build of the same as-of
- whose content has since changed, are skipped and the page says so
- (re-run the analysis to refresh them). Written to
- `insights/captable/captable.html` (or `snapshots/<as_of>.html`);
- `captable_build` also writes it automatically on every build.
-
- ## Outputs
-
- - `insights/captable/analysis_scenarios.json` — the computed JSON
- (prices rounded to 4 decimals, percentages to 2).
- - The narrative, stored through the repository's `InsightFile` convention
- (`captable-analysis-<dataset>-<model-slug>.md`, manifest-tracked) since
- it is model-dependent.
-
- Requires a snapshot: run `python -m skills.captable_build build` first.
-
- ## Reuse and contracts
-
- `captable_analysis` returns `list[InsightFile]`. The explicit `analyze` adapter
- also returns computed data, narrative, insight path and the selected insight;
- for a manual narrative its computed data is `None` and no snapshot is read.
- Manual narratives win first. Generated reuse uses the shared insight lifecycle,
- indexed startup revision and a key covering the computed scenarios (including
- snapshot fingerprint, accrual date and round/FX inputs), prompt and tool version.
- A new analysis date therefore invalidates accrued-interest results. The run CLI
- uses the same adapter; `--startup` is canonical and `--dataset`/`-d` remain aliases.
-
- Snapshots containing failed CLA extractions are rejected for analysis/rendering;
- rebuild them first. Conversion prices honor each loan's stated issued/outstanding
- or fully diluted cap/floor denominator. An unstated basis is disclosed as a fully
- diluted assumption. Dollars-invested scenarios fix post-money at pre-money plus
- new investment plus converting balances, including discount dilution in pricing.
+ Temporary command/Python alias for [captable](../captable/SKILL.md).
+ It forwards to the same implementation and creates no separate artifacts.
+ Use `/captable` or `python -m skills.captable run --startup example`.
+ The old `render` command and snapshot-selection `--as-of` are removed.