Repository navigation
Company fixtures: small_co (Wrenfield Labs) and big_co (Ostrander Systems) - #16
Merged
Merged
Conversation
Proposes two company fixtures to replace the deferred small/large: Wrenfield Labs (small prosumer SaaS) and Ostrander Systems (B2B vertical SaaS at scale). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
…ld specs left as-is Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
…se; mark complete Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
…king unchanged Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
…gh the world's code, declare gaps Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
…workarounds Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
…o charge count Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
…and implementation plan Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
…x account
- schema/006_account.sql: one-row STRICT account table (id, livemode, object, settings),
seeded with the sandbox account and no mode; the first open stamps the creation-time mode.
- startup.open_account: validates the row, applies the mode rule (an explicit livemode that
differs from a stored mode raises WorldBug), merges ledger/dunning settings.
- tests/golden/sandbox_account.json and tests/test_account_table.py; the empty fixture is
rebuilt (its row is stamped live); version 0.1.0 -> 0.2.0; table count 24 -> 25 in docs.
- Deviations: the seed is written via json('<indented text>') (same stored bytes); the
account object now comes back from the DB with sorted keys.
Committed without the code-review round at the user's request (demo branch).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
fixtures_src/ becomes a package. replay/ holds the clock swap, the timeline, the dispatch client (each call in a savepoint, as the HTTP handler does), the four engine wrappers, the test-card catalogue, the people pools, the subscription and payout drivers, the finishing writes (balance-status refresh, 30-day event trim) and check_fixture. accounts.py defines WRENFIELD and OSTRANDER and install_account; generate.py wires STARTUP and builds small_co and big_co lazily. docs/fixtures.md skeleton. 17 tests in tests/replay/. Nothing under src/ changed. Simplified: smaller name pools; retries follow only the latest invoice; trimmed tests. Benchmark: 200 customers over 12 months builds in 4.9s at 9.1 MB; projected for big_co's 3,000 customers that is far above the 25 MB budget (decision pending). Committed without the code-review round at the user's request (demo branch). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
fixtures/small_co: a 45-customer seed-stage SaaS in test mode, replayed through the world's dispatcher from the 2025-08-25 beta to NOW (2026-09-01T14:00Z). 42 subscriptions (29 active, 3 trialing, 1 past_due, 1 paused, 7 canceled, 1 incomplete_expired), 109 charges, 119 invoices, 2 refunds, 1 open dispute, 19 payouts, 145 events; 1.74 MB. fixtures_src/small_co/ (catalog, cast, story, build), tests/test_small_co.py (expectations, invariants, named characters, byte-identical rebuild), docs/fixtures.md small_co section. Deviations: the dispute is opened with disputes.maybe_create_dispute (subscription payments open none); setup fees are billed on their own invoice (pending items are never swept); replay/checks.py skips the trial-end invoice in the overlap check; the LAUNCH coupon's 3-month limit is not enforced; guide tooling and the web name check skipped; payouts expected 15-40. test_empty_fixture/test_fixtures no longer assert that empty is the only fixture. Committed without the code-review round at the user's request (demo branch). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
fixtures/big_co: the test-mode account of Ostrander Systems, a Denver field-service SaaS company, replayed through the world's dispatcher and engine functions from the 2025-03-03 migration week to NOW (2026-09-01T14:00Z). 379 customers (167 migrated), 378 subscriptions (all eight statuses), 2,917 invoices, 2,650 charges, 19 disputes (all six stages), 81 credit notes (SLA batch included), 378 payouts (one pending); 23.0 MB; builds in about 23 s and rebuilds byte-identical. - fixtures_src/big_co/: shape.py (knobs, catalog, tax rates, one-off services), population.py (pure draw: migration cohort, organic and sales-led signups, exempt public buyers, CS notes, variant-name duplicates), simulate.py (catalog steps, Lives hooks: boundary draws, ramps, scheduled downgrades, concessions, SLA batch, invoice payment), loose_ends.py (the scripted loose ends of big_co.md §5), __init__.py (build, EXPECTATIONS). - fixtures_src/guide.py: `python -m fixtures_src.guide [--write]` checks or rewrites the landmark rows in docs/fixtures.md; the big_co half of the guide has 13 checked landmarks. - Tests: test_population.py, test_big_co.py (identity, live refused, expectations, every loose end, tools carry on), the big_co determinism case in test_fixtures.py, test_fork_cost.py, test_guide.py. conftest's api_* helpers take stripe_context/livemode keywords. - Docs: docs/fixtures.md big_co section; AGENTS.md fixture line; README ready-made fixtures line; docs/technical.md fixtures section and layout. - Web check: no real company named "Ostrander Systems" or "Ostrander FieldOps", and nothing at ostranderfieldops.com (searches found only Ostrander, Ohio and unrelated Ostrander-named businesses). - Fork cost (30 opens): small_co median 7 ms, max 14 ms; big_co median 15 ms, max 80 ms (the checksum-verifying first open). Ceilings: 70 ms / 150 ms median, 1 s max. Deviations the user decided: - Population: the spec said about 3,000 customers; the build has about 380 (SCALE 0.115 on every count knob, rounded up; every rate as specified), because the Phase 2 benchmark put 3,000 at 135-250 MB and the file must be 25 MB or less. Draws at 0.12 and 0.125 came to 25.9 and 25.1 MB. - Disputes: the spec said a dispute card is swapped in for a renewal; the code opens every dispute on a one-off services payment (training day, data import, report build, app rollout) confirmed through POST /v1/payment_intents on a dispute test card, because the world opens a card's dispute only on that confirm path and the build calls no world function beyond dispatch and the four engine functions. Same rate per card-paid period, mix and course by age; the scripted queue, inquiries and review are made at the spec's August renewal instants, so their due dates are unchanged. - Expectation ranges: the spec's §8 ranges scaled, except active subscriptions 190-260 (the specified rates leave under 60% of customers active, not 70%) and disputes 10-22 (the spec's 110 at SCALE plus the nine scripted; 0.3% of a few thousand periods is single digits). Other deviations: - Ramps: the spec said the schedule creates the subscription; the code creates the send_invoice subscription, then a schedule from_subscription updated to the three phases, because the world's schedule routes declare no days_until_due. - SLA credit notes: the spec said 10% of the invoice total; the code caps it at the invoice's remaining creditable amount, because the world refuses more (a balance applied to the invoice). - Added: ordinary one-off services payments (3% per card-paid period) so disputed ones are not the account's only PaymentIntents; two scripted settled disputes (one won, one lost) so every stage is present at this population; scheduled downgrades picked by a 5% draw at an eligible last boundary, exactly two; concessions a 2% draw per boundary; schedule-governed subscriptions skip random changes; immediate downgrades wait for a good card. - Tax-exempt buyers use invented place names (the pool's generic geography includes real places). - Guide tooling (Phase 3's, skipped there) lands here; the small_co section is not converted to landmarks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
… 4 items Phases 1-3 were committed without code review. This commit does every item the triage of the three reviews marked DO. Under src/, only startup.py changes, and it belongs to the account-table change. All three fixtures are rebuilt: empty is still 0.6 MB, small_co is 1.8 MB and big_co is 23.7 MB. The user's decisions - World bugs are filed, not fixed. #12 to #15 are avoided or declared in a new "Known gaps" section of docs/fixtures.md. - #12, a renewal bills the period that just ended. The spec says no two cycle invoices overlap. The overlap check now allows one exception only: an identical span on a trial-end invoice and the cycle invoice right after it. Before, it left every trial-end invoice out of the comparison. The exception carries a comment linking the issue. - #13, repeating coupons never end and times_redeemed stays 0. Only once and forever coupons are used. - The spec has LAUNCH at 50% off for 3 months; it is now 50% off once, the first invoice. - The spec has SWITCH25 at 25% off for 3 months; it is now 25% off once. - The guide no longer claims redemption counts (the spec said LAUNCH 10, TEACHWELL25 5) or that discounts have ended. - #14, pending invoice items are never swept. Anika's setup fee is still billed on its own invoice (the BillPending beat, not in small_co.md's beat vocabulary). Elena's $49 item stays pending, and the guide no longer says her 09-10 renewal will pick it up. - #15, canceled_at is null on a cancel-at-period-end request. Declared in the guide. - Disputes come only from one-off payments confirmed through POST /v1/payment_intents on a dispute test card. The spec (small_co.md row 45) has Grace buy Studio annual on the dispute card. Now she buys it with her own card, then pays $49 for "Done-for-you setup" at 15:25 on a dispute card added for that payment. That payment is disputed as fraudulent, evidence due 2026-09-07T23:59:59Z. The story no longer calls disputes.maybe_create_dispute. OneOffPayment gains an optional card. - The Wrenfield name stays, and the collision is accepted. Functional spec §3.2 asks for no real company. The web check found: - wrenfield.app is a live "Wrenfield" puzzle and word games site; - Wrenfield Finance, Wrenfield Capital and Wrenfield Media exist; - no "Wrenfield Labs". The user kept the name, domain, emails and account id. Other deviations from the spec (all recorded in phase_plans/catchup.md) - Accounts: architecture §2.3 has CompanyAccount(id, object, settings). It now holds only the company's fields, settings and bank suffix. install_account sets them over the seeded row's object, so the SQL seed is the only copy of the sandbox account; the hand-kept _SANDBOX is gone. It refuses a field the sandbox lacks, and refuses a row other than the seeded sandbox. - "Nothing after NOW" (§3.4, replay.md §7): - It covers every timestamp-shaped column: canonical ISO text, and time-named Unix integers inside JSON. Before, it checked 8 column names. - The forward fields are listed in one _FORWARD set. Beyond the spec's list it adds billing_cycle_anchor, cancel_at, period ends (an invoice's, an invoice item's, a line's or a discount's), end_date, and every date inside a schedule's phases. - It reports offenders by id, and skips only the FTS virtual and shadow tables. - Retries (replay.md §5): a scheduled retry is tied to its invoice. If that invoice is still open but no longer its subscription's latest, the build raises FixtureBuildError instead of silently dropping the remaining retries. - n (replay.md §5) counts only boundaries that ran. The Hooks.before_boundary docstring says so. - open_account raises a WorldBug naming the field when the object lacks settings.dashboard.display_name, country or default_currency. Before, it raised a bare KeyError. - empty's description says what it holds: the schema and the sandbox account, in live mode. - big_co: - TRADE_WORDS keeps only HVAC, plumbing, electrical, drain and sewer, and mechanical (§5). Roofing, pest control, garage doors and home services are gone. - _trade_coupon matches whole words, so "Prairie" is no longer "air". - CRM ids are 006 plus 12 digits everywhere; the scripted loose ends used 10. - People pools grow to the spec's sizes: 210 first names, 200 last names, 151 real cities, and the state weights of replay.md §4. - Corrections to components/small_co.md, recorded in the phase plan rather than the spec: - row 13: Anika's setup fee is billed on its own invoice; - row 34: Victor expires at 15:40, 23 hours after 16:40 the day before, not at 16:40; - row 45: Grace's dispute, as above; - §6: 5 products and 8 prices, not 3 and 6, because each setup item mints a one-off price and product; - §6: payouts 15 to 40, not 20 to 40, because a quiet Monday makes no payout. - Dropped by the triage: - test_benchmark; - renaming the replay test files to architecture §3.3's names; - rewriting small_co.md's tables; - the three "Done-for-you setup" products; - big_co's _card_step/_swap duplication; - the exclusive refund and credit-note draws (big_co.md §4.1 makes them independent). Guide - docs/fixtures.md gives small_co 14 checked landmarks: counts, status counts, the cast, and one per loose end of small_co.md §7. Before, small_co had one unchecked query. - Coupon text is corrected in both sections. - `python -m fixtures_src.guide` reports 27 landmarks, 0 differences. Tests - One planted violation per invariant and guard, each required to trip only its own check. The two the schema enforces (net = amount - fee, refunded <= captured) are tested as refused by the schema. - Tests for the narrowed overlap rule (including a trial-end span repeated by a renewal that is not the next one), forward fields, reporting by id, the test cards' behaviour, and a pi_ id carrying its instant. - Driver tests: - no payout overdraws; - a draft finalized automatically carries no request; - the instant a trial pauses; - mark_unpaid; - a superseded retry stops the build; - an abandoned boundary uses no number. - tests/replay/test_accounts.py: a company differs from the seeded sandbox only in its own fields. - test_small_co.py: - opens the fixture with the row's own mode; - checks the account identity exactly; - adds test_opening_live_is_refused, test_new_ids_carry_wrenfield and test_tools_carry_on (a payout of available + 1 is refused); - has one test per named character of §4.4. - A test requires small_co's landmarks. - test_fixtures checks that the imported world holds exactly its three fixtures. - Population tests: the market's trades, whole-word coupons, one CRM id format, the pool sizes. - The account-table quick fixes are in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
scosman
added a commit
to scosman/OpenEnv
that referenced
this pull request
Oct 17, 2026
Stripe World now ships three fixtures (Kiln-AI/stripe_world#16). Add a Fixtures section listing empty, small_co (Wrenfield Labs, 45 customers) and big_co (Ostrander Systems, about 380 customers), how to select one with reset(fixture=...), and that a fixture keeps the mode it was saved in. Scope the livemode note to resets without a fixture, link the fixtures guide, and update the table count to 25. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uxf3k6Fcyfm5Jmt8d4HDfA
scosman
added a commit
to scosman/OpenEnv
that referenced
this pull request
Oct 17, 2026
The main README isn't the right place for a Seahaven pointer, so restore README.md to match main. The tutorial and its toctree entry stay. Stripe World added an account table (Kiln-AI/stripe_world#16), so the tutorial's Stripe World paragraph now says 25 tables instead of 24. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uxf3k6Fcyfm5Jmt8d4HDfA
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds two company fixtures in test mode,
small_coandbig_co, and the account table they need.Summary
emptysmall_cobig_coAll three are frozen at
2026-09-01T14:00:00.000Z. Each company fixture is built by replaying its history through the world's owndispatchand the four engine functions billing_engine.md §7 provides for fixture generators. The build never writes SQL straight to the tables.python fixtures_src/generate.pyrebuilds every fixture byte-for-byte.The only world change: an account table
schema/006_account.sqlis a one-rowaccounttable. It replaces the hardcoded account instartup.py, so a fixture carries its own account identity and mode.livemoderaisesWorldBug.tests/test_account_table.pycovers the table.src/is touched. Runninggit diff main -- src/shows onlyschema/006_account.sql,startup.pyand the version string inworld.py.Fixture generator (
fixtures_src/)replay/: the clock swap, the timeline, the dispatch client (one savepoint per call), the subscription and payout drivers, the finishing writes, andcheck_fixture.check_fixturechecks the consistency invariants and every expectation, and each check has its own planted-violation test.small_co/: the catalog, the 45-member cast and the story.big_co/: the shape, the population draw, the simulation and the scripted loose ends.guide.pychecks thesql landmark=blocks indocs/fixtures.mdagainst the committed fixtures. There are 27 landmarks, and none differ.Deviations from the spec, decided along the way
POST /v1/payment_intentson a dispute test card. The world opens no dispute from a renewal charge, and the generator calls no engine function to force one.once/forevercoupons and bill setup fees on their own invoice. The rest are declared under "Known gaps" indocs/fixtures.md.specs/projects/company_fixtures/phase_plans/phase_4.mdandphase_plans/catchup.md.Test plan
uv run ruff format --check && uv run ruff checkuv run ty checkuv run seahaven checkuv run pytest. The full suite passes, including:python -m fixtures_src.guidereports 27 landmarks and 0 differences.🤖 Generated with Claude Code
https://claude.ai/code/session_01T4ry4bFLC4jJqmCF5aowCN
Generated by Claude Code