{
  "manifest_version": "0.1",
  "work_slug": "leverage-profitability-polish-firms",
  "protocol": "protocol:secondary-analysis 0.1",
  "module": "agent/tools.py",
  "analysis_unit": "analysis.py",
  "published_results": "results.json",
  "source_dataset_doi": "10.6084/m9.figshare.92633.v1",
  "environment": {
    "language": "python",
    "tested_version": "3.13",
    "requirements": "requirements-reproduction.txt",
    "network": "deny-except-pinned-inputs"
  },
  "execution": {
    "boundary": "docs/72-reproduction-contract.md",
    "live_invocation": "not connected; the sandboxed runner gates execution over MCP",
    "input_fetch": "one pinned 3.4 MB workbook through scripts/fetch_pinned.py, md5-asserted; analysis.acquire_data is not used because its urlretrieve does not survive a truncated transfer and its fallback is a path on the author's machine",
    "cost_note": "a bootstrap block of 10,000 Spearman resamples takes about 7 s at n = 3,500. The acceptance suite runs the eight published blocks at 10,000 (one of them, the 2009 block, reached by two calls and computed once) plus the 99% interval on the published stream; every other off-reference call draws 2,000 resamples. About 100 s in all on the authoring machine, against about 225 s when every call drew 10,000"
  },
  "surface_note": "Two design choices a caller should know. First, the published run draws every bootstrap CI from one generator in a fixed order (primary 2010; 2008, 2009, 2010; 2009b; winsorized 2010; trimmed 2010; firm means), so reproducing any CI after the first means replaying that stream. Each bootstrapping tool therefore takes stream_offset, the number of published blocks replayed before its own resamples; defaults are each unit's published position, and 0 starts a fresh stream from seed. It moves only the Monte Carlo draw, never rho, p or n. Second, the profit numerator, profit scale and debt components are exposed on every statistical tool because the object's own Usage notes name the shared-Assets-denominator threat and net profit is struck after interest; both are testable from columns the workbook already carries. The profit codes name what each column holds, not its label: the workbook's column labelled EBIT equals its column labelled 'Profit before income tax' less Financial Costs in 97.5% of rows, so the former is struck after financial costs (before_tax) and the latter before them (before_financial_costs); dataset_summary reports the arithmetic. Only before_financial_costs tests whether the interest charge produces the association. One candidate knob was drafted and dropped: a median firm aggregation equals the mean for the 4,706 of 5,710 firms that contribute one or two rows, so it would be a near-duplicate of the published check rather than a distinct one.",
  "tools": [
    {
      "name": "dataset_summary",
      "summary": "Provenance of the pinned workbook, the per-year sample profile (tbl-1), the registry overlap between year labels, and what the two gross-profit columns hold.",
      "unit": "analysis.build_frame and analysis.cross_section, re-implementing the tbl-1 loop in analysis.main; krs_overlap is added here to make the narrative's stated basis for the 2009b batch checkable, and profit_columns to establish what the gross-profit columns hold before any tool uses them",
      "parameters": [],
      "returns": "sheet, expected and observed md5, md5_verified, observed_size_bytes, total_rows, nan_year_rows, per_year (rows, exclusions, ROA and Leverage medians and IQRs), krs_overlap (distinct KRS numbers shared by each pair of year labels), profit_columns (share of rows where the column labelled EBIT equals the column labelled 'Profit before income tax' less Financial Costs, share satisfying the identity the labels imply, and the median ratio of net profit to each column, overall and where net financial costs are at least half the column)",
      "supports_claims": [1, 2, 3, 4, 5],
      "deterministic": true
    },
    {
      "name": "spearman_cross_section",
      "summary": "Spearman rho of Leverage against ROA in one cross-section, with a bootstrap percentile CI.",
      "unit": "analysis.spearman_with_ci over analysis.cross_section and analysis.build_frame (the primary block of analysis.main)",
      "parameters": [
        {
          "name": "year",
          "type": "number | string",
          "default": 2010,
          "range": "2008 | 2009 | '2009b' | 2010",
          "published_values": [2010],
          "notes": "The other three labels are published by temporal_replication at later stream positions; with the matching stream_offset this tool reproduces those CIs too."
        },
        {
          "name": "alternative",
          "type": "string",
          "default": "two-sided",
          "range": "two-sided | less | greater",
          "published_values": ["two-sided"],
          "notes": "H1 is directional (rho < 0), but the pre-registered and reported test is two-sided; 'less' gives the one-sided p in H1's direction, half the reported p. The CI does not depend on it."
        },
        {
          "name": "profit",
          "type": "string",
          "default": "net_profit",
          "range": "net_profit (Net profit (loss)) | before_tax (the column labelled EBIT, which the workbook's arithmetic shows is struck after financial costs) | before_financial_costs (the column labelled 'Profit before income tax', which equals the former plus Financial Costs in 97.5% of rows)",
          "notes": "Coded by content, not label; see dataset_summary profit_columns. before_financial_costs is the check on the interest channel.",
          "published_values": ["net_profit"]
        },
        {
          "name": "scale",
          "type": "string",
          "default": "assets",
          "range": "assets | revenues (net margin; rows with non-positive revenues excluded)",
          "published_values": ["assets"],
          "notes": "revenues gives a profitability measure that shares no denominator with Leverage."
        },
        {
          "name": "debt",
          "type": "string",
          "default": "total",
          "range": "total (Long-term debt (Dl) + Short-term debt (Ds)) | long_term (Dl) | short_term (Ds)",
          "published_values": ["total"]
        },
        {"name": "n_boot", "type": "number", "default": 10000, "range": "positive integer", "published_values": [10000]},
        {"name": "ci", "type": "number", "default": 95, "range": "0 < ci < 100", "published_values": [95]},
        {"name": "seed", "type": "number", "default": 20240517, "range": "any integer", "published_values": [20240517]},
        {
          "name": "stream_offset",
          "type": "number",
          "default": 0,
          "range": "integer 0..8: published bootstrap blocks replayed before this call's resamples",
          "published_values": [0],
          "notes": "The primary block was the first draw of the published generator."
        }
      ],
      "returns": "test, year, rho, p, n, ci_low, ci_high, ci_level, effect_size, effect_size_name -- the shape of results.json /primary",
      "supports_claims": [1, 2],
      "deterministic": true
    },
    {
      "name": "temporal_replication",
      "summary": "Spearman per year with Holm-Bonferroni across the family, plus an uncorrected separate batch.",
      "unit": "analysis.spearman_with_ci per analysis.cross_section with analysis.holm_bonferroni (robustness A of analysis.main)",
      "parameters": [
        {
          "name": "family_years",
          "type": "array of (number | string) | null",
          "default": null,
          "range": "a non-empty list of distinct labels from 2008, 2009, '2009b', 2010; null is the published family [2008, 2009, 2010]",
          "published_values": [null]
        },
        {
          "name": "batch_year",
          "type": "number | string | null",
          "default": "2009b",
          "range": "a label outside family_years, reported uncorrected; null reports no batch",
          "published_values": ["2009b"],
          "notes": "By registry number 2009b is the 2008 firms observed again, not a stray batch; see dataset_summary krs_overlap."
        },
        {"name": "profit", "type": "string", "default": "net_profit", "range": "net_profit | before_tax | before_financial_costs", "published_values": ["net_profit"]},
        {"name": "scale", "type": "string", "default": "assets", "range": "assets | revenues", "published_values": ["assets"]},
        {"name": "debt", "type": "string", "default": "total", "range": "total | long_term | short_term", "published_values": ["total"]},
        {"name": "n_boot", "type": "number", "default": 10000, "range": "positive integer", "published_values": [10000]},
        {"name": "ci", "type": "number", "default": 95, "range": "0 < ci < 100", "published_values": [95]},
        {"name": "seed", "type": "number", "default": 20240517, "range": "any integer", "published_values": [20240517]},
        {"name": "stream_offset", "type": "number", "default": 1, "range": "integer 0..8", "published_values": [1], "notes": "The family blocks followed the primary block; the batch block continues the same stream."}
      ],
      "returns": "correction, per_year (rho, p, n, CI, p_holm for each family year), and batch_<label>_separate with p_holm null -- the shape of results.json /robustness/temporal",
      "supports_claims": [3],
      "deterministic": true
    },
    {
      "name": "outlier_sensitivity",
      "summary": "One cross-section raw, winsorized, and trimmed at [lower, upper] quantiles of both ratios.",
      "unit": "analysis.winsorize and the trimming step of analysis.main, each through analysis.spearman_with_ci (robustness B); Raw is the primary result, as analysis.main reuses it",
      "parameters": [
        {"name": "year", "type": "number | string", "default": 2010, "range": "2008 | 2009 | '2009b' | 2010", "published_values": [2010]},
        {
          "name": "lower",
          "type": "number",
          "default": 0.01,
          "range": "0 <= lower < upper",
          "published_values": [0.01]
        },
        {
          "name": "upper",
          "type": "number",
          "default": 0.99,
          "range": "lower < upper <= 1",
          "published_values": [0.99],
          "notes": "Winsorizing only ties the clipped tail, so for a rank statistic it is close to a no-op at any level; trimming is the check that can fail."
        },
        {"name": "profit", "type": "string", "default": "net_profit", "range": "net_profit | before_tax | before_financial_costs", "published_values": ["net_profit"]},
        {"name": "scale", "type": "string", "default": "assets", "range": "assets | revenues", "published_values": ["assets"]},
        {"name": "debt", "type": "string", "default": "total", "range": "total | long_term | short_term", "published_values": ["total"]},
        {"name": "n_boot", "type": "number", "default": 10000, "range": "positive integer", "published_values": [10000]},
        {"name": "ci", "type": "number", "default": 95, "range": "0 < ci < 100", "published_values": [95]},
        {"name": "seed", "type": "number", "default": 20240517, "range": "any integer", "published_values": [20240517]},
        {"name": "stream_offset", "type": "number", "default": 5, "range": "integer 0..8", "published_values": [5], "notes": "Positions the winsorized block; the trimmed block continues the stream, and Raw always comes from position 0."}
      ],
      "returns": "Raw, 'Winsorized <lower>/<upper>%' and 'Trimmed <lower>/<upper>%', each rho, p, n, CI -- the shape of results.json /robustness/winsorization",
      "supports_claims": [4],
      "deterministic": true
    },
    {
      "name": "firm_level_association",
      "summary": "Spearman on one mean observation per registry-identified firm.",
      "unit": "the firm aggregation of analysis.main (robustness C) through analysis.spearman_with_ci",
      "parameters": [
        {
          "name": "years",
          "type": "array of (number | string) | null",
          "default": null,
          "range": "null pools every year label, as published; otherwise a list of labels from 2008, 2009, '2009b', 2010",
          "published_values": [null],
          "notes": "The published aggregation pools 2009b although the methods say it is never pooled with the family. [2008, '2009b'] and [2009, 2010] are the two firm panels."
        },
        {"name": "profit", "type": "string", "default": "net_profit", "range": "net_profit | before_tax | before_financial_costs", "published_values": ["net_profit"]},
        {"name": "scale", "type": "string", "default": "assets", "range": "assets | revenues", "published_values": ["assets"]},
        {"name": "debt", "type": "string", "default": "total", "range": "total | long_term | short_term", "published_values": ["total"]},
        {"name": "n_boot", "type": "number", "default": 10000, "range": "positive integer", "published_values": [10000]},
        {"name": "ci", "type": "number", "default": 95, "range": "0 < ci < 100", "published_values": [95]},
        {"name": "seed", "type": "number", "default": 20240517, "range": "any integer", "published_values": [20240517]},
        {"name": "stream_offset", "type": "number", "default": 7, "range": "integer 0..8", "published_values": [7], "notes": "The firm-level block was the published generator's last draw."}
      ],
      "returns": "note, rho, p, n, ci_low, ci_high, ci_level, n_firms -- the shape of results.json /robustness/firm_level",
      "supports_claims": [5],
      "deterministic": true
    },
    {
      "name": "holm",
      "summary": "Holm-Bonferroni correction over a family of p-values, in input order.",
      "unit": "analysis.holm_bonferroni",
      "parameters": [
        {
          "name": "p_values",
          "type": "array of number | null",
          "default": null,
          "range": "any non-empty list of p-values in [0, 1]; null uses the two-sided p of the published family [2008, 2009, 2010]",
          "published_values": [null]
        }
      ],
      "returns": "the corrected p-values, in input order",
      "supports_claims": [3],
      "deterministic": true
    }
  ]
}
