risk-judgment-shape — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited risk-judgment-shape (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
The bwmacro/RiskModels stack centralizes risk interpretation (turning raw ERM3 outputs into qualified, PM-readable language) into a single engine that lives privately in BWMACRO. RiskModels_API is the public layer — data, math, chart primitives — and must not contain the editorial vocabulary that the engine produces.
If you are about to write a string like:
"Strong Residual Alpha", "Solid Residual Quality", "Muted", …"performance is beta-driven", "returns are driven by idiosyncratic exposure", …"ranks near the top of the cohort", "sits near the cohort median", …"High Systematic Exposure", "Underperforming SMH", …… STOP. That is editorial vocabulary. It belongs in BWMACRO, not here.
sdk/riskmodels/snapshots/*.py).app/api/ that surfacenatural-language descriptions of risk.
(driver = systematic / balanced / idiosyncratic, quality = strong / solid / muted, etc.).
The single public surface for interpretation in this repo is sdk/riskmodels/interpretation.py. It exports:
| Symbol | Purpose |
|---|---|
Judgment | Frozen dataclass — the contract every consumer reads. Fields: version, as_of, ticker, features, text, states, flags. |
INTERPRETER_VERSION | Schema version. Bumped when the public feature dictionary changes shape. |
compute_features(data) -> dict | Pure numeric extraction from a DDData. No qualifiers, no thresholds. Both the bland stub and the BWMACRO engine consume this. |
derive_default_judgment(data) -> Judgment | Bland public stub. text fields are raw numerics only ("AAPL — systematic 39%, residual +1.9%, peer rank 78") — no qualifiers, no editorial. |
Snapshot render entry points accept an optional judgment parameter:
def render_dd_to_pdf(data, output_path, *, judgment: Judgment | None = None): ...
def render_dd_to_png(data, output_path, *, judgment: Judgment | None = None): ...
def render_dd_to_png_bytes(data, *, judgment: Judgment | None = None): ...When judgment is None, the legacy in-SDK editorial generator runs (temporarily, until Phase 1B replaces it with a BWMACRO call site). When provided, the renderer reads judgment.text for headline + insight strings.
The editorial engine lives at:
BWMACRO/bwmacro/risk_interpretation/
├── dd.py # derive_judgment(data) for DD snapshots
├── states.py # threshold tables → discrete states
├── flags.py # predicate flags
├── renderers.py # qualifier vocabulary + PM phrasing
└── tests/ # eval casesIt imports Judgment, compute_features, and INTERPRETER_VERSION from riskmodels.interpretation and produces a fully-populated Judgment (with states, flags, and editorial text) that the API route layer injects into render_dd_to_* calls.
"Muted", "beta-driven", "ranks above the median" — all of those go to BWMACRO.
if residual_share > 0.5: to decide on language, that logic belongs in BWMACRO/bwmacro/risk_interpretation/states.py.
"industry_tailwind", etc. live in BWMACRO.
re-implement feature extraction inside snapshot renderers. Call compute_features(data) and read from the returned dict.
responses, chat agents, snapshot renderers — all consume the same shape. Do not invent parallel structures.
green-with-stripes, not red. (See the v9 waterfall fix for context.)
Judgment shape, compute_features, blandstub, render-entry-point seam. Behavior preserved when judgment=None via the legacy _generate_dd_insights function in sdk/riskmodels/snapshots/stock_deep_dive.py.
_generate_dd_insights to bwmacro/risk_interpretation/dd.py. Add the engine-owner SKILL in BWMACRO. Wire API route handlers to call BWMACRO and inject the result.
full-deployment render of top-N tickers, push to GCS at gs://rm_api_data/snapshots/dd/{YYYY-MM}/{ticker}.pdf. API serves from GCS with on-demand fallback for tickers not in the latest batch.
judgment=Nonedefault path to call derive_default_judgment (the bland stub) instead of _generate_dd_insights. Delete the legacy function. SDK community gets bland numeric output; BWMACRO callers get the rich editorial version.
When real data is missing for a chart panel, API response, or chat output: look in Funds_DAG/data/sync/funds/*.json, the per-fund ds_*.zarr stores, and the RiskModels SDK / API endpoints (use riskmodels-api-discovery first). If the fetcher genuinely isn't wired yet, render an explicit "data unavailable" placeholder and add a backlog entry. Do not synthesize plausible values — even with a watermark; screenshots crop watermarks. Cross-repo full directive: BWMACRO/.cursor/skills/no-mock-data/SKILL.md.
The MASTER_BACKLOG entry for this initiative is at BWMACRO/docs/ceo/MASTER_BACKLOG.md under "Risk Interpretation Engine".
A second cross-repo split governs which snapshot layouts ship public vs private. Same shape as the interpretation boundary above, different axis:
| Public (this repo) | Private (BWMACRO) |
|---|---|
riskmodels.snapshots.canonical.CanonicalStockSnapshot — semantic schema | bwmacro.snapshots.stock.r1_risk_profile |
riskmodels.snapshots.canonical.from_components(p1, peer_comparison=…) | bwmacro.snapshots.stock.p1_stock_performance |
riskmodels.snapshots.canonical.from_dd_data(dd) (structurally typed) | bwmacro.snapshots.stock.stock_deep_dive (DDData class) |
riskmodels.snapshots.reference_renderer — clean, less-opinionated PDF/PNG | bwmacro.snapshots.stock.{s1_forensic,s2_waterfall,product_tear_sheet} |
riskmodels.snapshots._stock_data.P1Data — data dataclass | All curated layout / chart composition for the institutional 1-page PDFs |
riskmodels.visuals.{cascade,l3_decomposition,waterfall,components} | riskmodels.visuals._mag7, gallery, mag7_l3_*, smart_subheader |
Hard rule: the rm_api_public GCS bucket pipeline (bulk_dd_render.py + app/api/snapshot/[ticker]) *never imports `bwmacro.`**. It must stay self-sufficient on the public canonical pipeline. User confirmed this directly during PR 2 and PR 3.
If you need to add a new institutional renderer, put it in BWMACRO and write an adapter in bwmacro/snapshots/stock/adapters.py that maps the private data class onto CanonicalStockSnapshot via riskmodels.snapshots.canonical.from_components.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.