Context
0370 resolves one market per tenant. US law stacks federal, state and city rules (US-3:us → us-ca → us-ca-sf),
and one sale can owe two markets: a New York shop selling to a California buyer owes California’s sales-tax and
privacy rules on that sale while its tips and labour rules stay New York’s (US-4). The review (R3-SO-01, X2-18) found
three gaps: overlays deeper than two levels were not confirmed, a product section could not sit on an overlay (the
restaurant’s us-ca-sf rules, Juristra’s DIFC defaults), and MarketContext gave one pack per record. 0363 asked
whether the strictest pack or the legal entity’s pack wins. Alternatives weighed: the strictest value across both
markets (rejected: “strictest” has no meaning for a tax rate or a provider, and it applies a law that does not govern
the sale), and always the entity’s pack (rejected: it gives the buyer’s state no say over its own sales tax and
privacy law). 0370 also left where pack bytes are stored to the caller, so every service would invent its own fetch.
Decision
- No pack wins for a tenant; each rule kind names its subject. A pack carries
subjects: a key or key prefix mapped tolocation(where the work or sale happens),buyer(the ship-to or billing address),entity(where the legal entity is formed) ortenant(the tenant’s own market). The longest matching prefix wins; an overlay may restate one. With no match the tenant’s market answers, as before. The subjects are pack data; no rule kind is named in code. MarketContext.packFor(record, ruleKind). AMarketContextis built per tenant from the verified packs and the tenant’s resolve options.packForreads the rule kind’s subject from the tenant’s resolved market and returns the resolved market of the record’s market for that subject (MarketRecord:tenant,location,buyer,entity). A record without the subject’s market is refused (subject_market_missing); the caller supplies it, never a guess. Rules facts carry one resolved pack per subject.- Floors follow the subject. A legal floor is enforced from the pack the rule kind’s subject resolves to, and only from it. Nothing merges floors across markets; a tenant who wants a stricter value sets it above the floor in its settings.
- Overlays of any depth.
extendschains of any length resolve parent first, and a loop of any length is refused (overlay_cycle). 0370 decision 3 is read this way. - Product sections per overlay. A section is declared per market in the chain (
us-ca-sf/restaurant); each resolves beside its own base pack, so an overlay’s section overlays its parent’s section. A section still has noextendsof its own and its keys keep its prefix (0370 decision 7). - Storage and fetch by content hash. Signed packs are stored and fetched through the
PackStoreport, addressed by their content hash. The production driver keeps one file per pack atmarket-packs/<hash>.jsonon an injectedFileSystemdisk (@stackra/filesystem), refuses a pack whose hash does not match, and never rewrites a stored hash.fetchPacks(store, hashes, trustedKeys)loads the hashes a deployment names and verifies each; a hash the store lacks is refused (not_stored). Packs a module ships asdata/assets are read throughAssetLibrary(@stackra/assets) after the manifest hash check. Which hashes a deployment loads and its trusted keys are deployment configuration. - Seed packs ship as draft data. The
usbase pack and the overlays of the first launch list (us-ny,us-nj,us-ca,us-tx,us-il,us-mi,us-fl, US-2) ship asdraftdata assets of@stackra/market-packs, with acounsel_reviewchecklist item and no sign-offs. They carry the subjects of US-4, the federal and state holiday sets and the first calendar values (0387). Draft is never served outside authoring (0370 decision 4). - Bindings.
@stackra/fiscalanswersFiscalPackSourcefrom packs (fiscal.invoice,fiscal.till). The payments binding (MarketPaymentDefaults) follows in its own package.
Consequences
- A cross-state or cross-border sale reads each rule from the market that governs it; the subject table is reviewed data, so counsel can change it without a release.
- Every caller of
packFormust fill the record’s markets from its addresses; a missing buyer address on a taxable sale now fails loudly. - Pack bytes have one home and one address; a tampered or misfiled pack stops start-up.
@stackra/market-packsnow depends on@stackra/assets,@stackra/containerand@stackra/filesystem, and ships data assets (drafts only; base packs remain owned by the platform).
Enforcement
planned — the package tests fix the behaviour (packages/foundation/market-packs/src/core/values/__tests__/market-context.value.test.ts,
src/core/functions/__tests__/resolve-pack.function.test.ts, src/core/drivers/__tests__/,
src/core/__tests__/us-packs.test.ts); nothing runs them in CI yet. A publish check that a section declared on an
overlay keeps its parent’s subjects is not built.
Supersedes and sources
Supersedes: none. Amends 0370 decisions 3, 7 and 9; settles 0363 open question 3. Sources:notes/handover/review-round-3/stackra-os.md (R3-SO-01); notes/handover/us/default-applied.md (US-2, US-3, US-4);
notes/handover/stackra-package-needs.md (market-pack loader row); notes/handover/review-round-2/cross.md (X2-18,
X2-19); STA-666.