|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +**THIS REPOSITORY IS PUBLIC.** Every file, commit message, branch name, issue, |
| 4 | +pull request and review comment in it is visible to anyone on the internet, and |
| 5 | +the methods page on flowmatrixai.com links here. Read this section before doing |
| 6 | +anything else. |
| 7 | + |
| 8 | +## Hard rules for a public repo |
| 9 | + |
| 10 | +The test for anything you are about to add: **if it would not be fine on the |
| 11 | +front page of the site, it does not belong here.** Concretely: |
| 12 | + |
| 13 | +1. **Never name or link a private repository.** Not in code, comments, |
| 14 | + docstrings, commit messages, issues or PR bodies. "Moved from the internal |
| 15 | + research repo" is fine; the repo's name and URL are not. If a private repo |
| 16 | + is the origin of a figure, describe the public source the figure was |
| 17 | + computed from instead. |
| 18 | +2. **Never reference internal tooling, portals, infrastructure or operations.** |
| 19 | + No internal hostnames, dashboards, deploy targets, CRM or ticketing systems, |
| 20 | + session or workflow identifiers, or filesystem paths from a particular |
| 21 | + machine. The only hosts that may appear are the public data sources and |
| 22 | + flowmatrixai.com. |
| 23 | +3. **Never name a client, a prospect, or an individual.** Utilities, agencies |
| 24 | + and counties appear here as rows in public datasets and may be named as |
| 25 | + such. A commercial relationship with anyone is never disclosed. No personal |
| 26 | + names paired with a title or employer, no email addresses, no phone numbers, |
| 27 | + no personal profile URLs. The one exception is the maintainer's own GitHub |
| 28 | + handle in `CODEOWNERS`. |
| 29 | +4. **Never include commercial terms, pricing, revenue, pipeline, funnel figures |
| 30 | + or internal strategy.** This repo explains how published numbers were |
| 31 | + computed, nothing about how the business runs. |
| 32 | +5. **Every dataset comes from a public source with its URL recorded.** A raw |
| 33 | + input is added by registering it in `src/article_data/fetch.py` with its |
| 34 | + URL, SHA-256 and licence; a pinned input under `outputs/inputs/` records |
| 35 | + where and when it was pulled. Nothing arrives by hand-copy from a private |
| 36 | + file. If a source is not public, the analysis that needs it does not go |
| 37 | + here. |
| 38 | +6. **No credentials, and no pointers to where a credential is stored.** The |
| 39 | + pipeline needs no API key by design (ACS is read from the keyless summary |
| 40 | + files); keep it that way rather than adding a keyed endpoint. |
| 41 | +7. **Commit messages, branch names and issues are public too.** Write them as |
| 42 | + if they were part of the README. No internal ticket references, no client |
| 43 | + or project codenames, no "per the call with X". |
| 44 | + |
| 45 | +When in doubt, leave it out and ask. A leak here is permanent: history is |
| 46 | +public and a force-push does not remove what has already been cloned. |
| 47 | + |
| 48 | +## Project |
| 49 | + |
| 50 | +The data and code behind the articles on flowmatrixai.com. Every published |
| 51 | +figure is produced from a public source that is fetched by recorded URL, |
| 52 | +verified against a recorded SHA-256, and reduced by code in this repository. |
| 53 | +The computed outputs and the article exhibits are committed so a reader can |
| 54 | +check a number without running anything. |
| 55 | + |
| 56 | +## Commands |
| 57 | + |
| 58 | +```bash |
| 59 | +just setup # uv sync --frozen |
| 60 | +just check # ruff format --check, ruff check, pyright (what CI runs) |
| 61 | +just test # pytest; reproduction tests skip until sources are fetched |
| 62 | +just fetch-sources eia861 acs # verified downloads of the small sources into outputs/raw/ |
| 63 | +just pipeline --stream # every analysis; streams the 11.6 GB EAGLE-I archive year by year |
| 64 | +just exhibits # redraw the article SVGs from the committed CSVs |
| 65 | +``` |
| 66 | + |
| 67 | +## Layout |
| 68 | + |
| 69 | +``` |
| 70 | +pyproject.toml, uv.lock project + locked environment (Python 3.12, uv) |
| 71 | +src/article_data/ |
| 72 | + fetch.py source registry (URL, SHA-256, licence) and downloader |
| 73 | + storm_multiplier.py EIA-861 SAIDI with / without major event days |
| 74 | + eaglei.py EAGLE-I county-month and 2025 county-week aggregates |
| 75 | + penetration_gap.py ACS qualifying homes x EAGLE-I exposure |
| 76 | + trends.py Google Trends decay after the 2024 hurricanes |
| 77 | + exhibits/ the article SVGs; figstyle.py holds brand tokens and determinism |
| 78 | + cli.py the `article-data` command |
| 79 | +tests/ pytest suite; reference.py holds the published figures |
| 80 | +outputs/ |
| 81 | + METHODS.md per-analysis source, licence, method, known limits |
| 82 | + raw/ fetched sources (gitignored, restored by `article-data fetch`) |
| 83 | + inputs/ pinned inputs that cannot be re-fetched byte-for-byte; brand tokens; fonts |
| 84 | + computed/ outputs; small ones committed as fixtures |
| 85 | + exhibits/ the article SVGs, committed and regenerated by the tests |
| 86 | +``` |
| 87 | + |
| 88 | +## Rules specific to the pipeline |
| 89 | + |
| 90 | +- **Do not commit anything under `outputs/raw/`.** Raw sources are fetched by |
| 91 | + script and verified by checksum; committed outputs are small aggregates only. |
| 92 | +- **Do not hand-edit a committed CSV under `outputs/computed/`.** Regenerate |
| 93 | + it. If a number changes, change `tests/reference.py` and the article in the |
| 94 | + same PR, with the reason in the PR body. |
| 95 | +- **Do not hand-edit an SVG under `outputs/exhibits/`.** The tests regenerate |
| 96 | + every exhibit and assert it is byte-identical to the committed file. Change |
| 97 | + the drawing code, run `just exhibits`, commit the result. |
| 98 | +- **Do not change `HASH_SALT` in `exhibits/figstyle.py`.** It seeds |
| 99 | + matplotlib's element ids; changing it rewrites every committed SVG for no |
| 100 | + visible gain. |
| 101 | +- **Do not re-pull the Google Trends series casually.** The pinned series under |
| 102 | + `outputs/inputs/` is the published one; a re-pull is a re-baseline of the |
| 103 | + shipped numbers, done deliberately with the tests and the article updated |
| 104 | + together. |
| 105 | +- **Do not switch the ACS step to the Census API.** The API redirects to an |
| 106 | + HTML page with HTTP 200 when the key is missing, so a naive fetch looks like |
| 107 | + it worked. The pipeline reads the keyless table-based summary files for that |
| 108 | + reason, and it keeps this repo free of any credential. |
| 109 | +- **A checksum mismatch is an error, not a warning.** If an upstream file |
| 110 | + changes, record the new SHA-256 in the same PR that re-verifies the figures |
| 111 | + against it; never loosen the check. |
| 112 | +- **Licences travel with the data.** EAGLE-I is CC BY 4.0, which is why the |
| 113 | + committed outputs carry attribution and are released under `LICENSE-DATA`. |
| 114 | + A new source's licence is recorded in `fetch.py` and, if it constrains |
| 115 | + redistribution, in `outputs/METHODS.md` and the README. |
| 116 | + |
| 117 | +## Conventions |
| 118 | + |
| 119 | +- Conventional Commits (`type(scope): description`), one logical change per |
| 120 | + commit, no AI attribution trailers. |
| 121 | +- `just check && just test` before every commit; CI runs the same gates plus |
| 122 | + a secret scan, and `ok` must be green to merge. |
| 123 | +- Squash merge; delete the head branch on merge. |
0 commit comments