"""WHICH STORE THIS DEPLOYMENT IS ALLOWED TO WRITE — the fail-closed binding (D-315 / D-298). ⛔⛔ THE SENTENCE THIS FILE EXISTS TO MAKE IMPOSSIBLE. Owner, 2026-08-18, verbatim: *"this is so critical that whenever we do staging, we don't fuck up anyone's data. EVER."* It had already happened once: `fsanyoto/loopable` became STAGING on 2026-08-14 having never been given a store of its own, so two different builds wrote tenant #0's real business data. Compose that with D-305 (the store is last-write-wins at whole-document granularity) and a routine staging deploy does not merely add test rows — it can erase a real user's views, fields and typed cell values. ⛔ A DEPLOY FLAG IS NOT THE FIX; THE FLAG IS THE THING THAT ALREADY FAILED. The isolation that existed was bound to a ROLE ("the staging Space"), and a guard bound to a role stops guarding the moment the role moves — which these two Spaces have done twice. So the binding here is on the container's OWN IDENTITY, which no deploy can forget to pass and no role swap can invalidate. ⭐⭐ THE RULE, AND IT CLASSIFIES THE DEPLOYMENT RATHER THAN THE REPO: 1. the PRODUCTION deployment (identity in `PRODUCTION_SPACES`) -> may write anything 2. any other deployment writing a KNOWN production store -> REFUSED 3. any other deployment writing a repo on its OWN allowlist -> allowed 4. anything else -> REFUSED ⛔ WHY NOT CLASSIFY THE REPO, which is the design everybody reaches for first. A DENYLIST of production stores fails OPEN for the next tenant nobody remembered to add. A SUFFIX RULE (`*-staging-data`) pins a SPELLING rather than a claim — see [[gate-pins-a-spelling-not-a-claim]] — and a store named without the suffix is unprotected while reading as protected. Rule 4 is the one that survives a tenant nobody has provisioned yet: an unknown repo is refused, so a store this deployment was never handed cannot be written by accident. ⭐⭐ AND RULE 4 IS NOT THEORETICAL — IT IS THE HALF OF D-315 THE REGISTER ROW DID NOT KNOW ABOUT. Measured 2026-08-18 by reading both control planes: `royal-imports/cfo-os-staging-data`'s own `tenants.json` is byte-identical to live's and names **`royal-imports/aios-nurilab-data`, `aios-gtmlab-data` and `aios-loopable-data`** — the three other tenants' REAL stores. So `--data-repo=` only ever isolated tenant #0; `harness/runtime.py`'s `store.for_repo(repo)` path resolved three PRODUCTION repos out of the staging store and wrote them, and no flag has ever touched that path. The exposure is FOUR production stores, not one. ⚠ READS ARE NOT REFUSED, AND THAT IS A DELIBERATE, STATED SCOPE DECISION. `Store.get` is lenient by contract: a refused read would hand back `{}`, a caller would paint an empty grid, and the whole Space would read as "no data" rather than as "refused" — the exact [[empty-answer-vs-unfinished-answer]] shape this codebase has shipped before. A refused WRITE is loud (503, with the reason). So staging still SEES production data when pointed at it; it can no longer CHANGE it. Narrowing the read is a separate decision and is booked, not smuggled in here. ⚠ ABSENT IDENTITY FAILS CLOSED, AND THE FAILURE LOOKS LIKE AN OUTAGE. If a container exposes none of the identity variables, it is treated as "not the production deployment" and every write to a production store refuses. That is the safe direction, but on a live Space it would read as a total product outage — which is why `describe()` reports the RAW observations and not just the verdict: per D-160 the Space environment cannot be read from outside, so the container has to say what it saw. One deploy then answers "does SPACE_ID exist here", instead of three. """ import os #: The deployment that OWNS production data. A frozenset rather than a string because the product #: has had two public addresses before and will again. #: #: ⚠ THIS SET IS DUPLICATED IN `aios-web/deploy_web.py` AS `PUBLIC_LIVE`, on purpose and with a #: gate: `deploy_web` is a standalone CLI that must run without the platform package importable, so #: it cannot import this. `verify_store_binding.py::section_constants` asserts the two literals #: agree — a constant two features share is a constant that drifts ([[constant-two-features-share]]). PRODUCTION_SPACES = frozenset({'fsanyoto/runloopable'}) #: The stores that hold REAL customer business data. Enumerated 2026-08-18 from the live control #: plane (`royal-imports/cfo-os-data::tenants.json`), not guessed. #: #: ⛔ THIS LIST IS RULE 2, NOT THE WHOLE GUARD. It exists to make a DELIBERATE mis-pointing loud — #: `OS_DATA_REPO=royal-imports/cfo-os-data` typed on a laptop, or a production repo added to a #: sandbox allowlist by hand. Rule 4 is what covers a tenant provisioned after this line was #: written, which is why the file does not depend on this staying complete. PRODUCTION_STORES = frozenset({ 'royal-imports/cfo-os-data', # tenant #0 — Royal Imports 'royal-imports/aios-nurilab-data', # Nurilab 'royal-imports/aios-gtmlab-data', # GTM Lab 'royal-imports/aios-loopable-data', # Loopable }) #: The historical default of `OS_DATA_REPO`. Kept as a name so the resolution below can say what it #: is refusing to assume, rather than repeating a literal. PRODUCTION_DEFAULT_STORE = 'royal-imports/cfo-os-data' #: The env vars a Hugging Face Space container sets to describe itself, in the order they are #: trusted. `SPACE_ID` is the canonical one; the pair is the documented fallback. Read as a LIST so #: `describe()` can report every one of them and what it held. _IDENTITY_VARS = ('SPACE_ID', 'SPACE_AUTHOR_NAME', 'SPACE_REPO_NAME', 'SPACE_HOST') #: The env a NON-production deployment uses to name the stores it may write, beyond `OS_DATA_REPO`. #: Comma-separated. #: #: ⭐ THE POLARITY IS THE POINT, and it is what keeps trap 1 satisfied. Forgetting to set this #: makes a deployment write LESS, never more — so an omitted deploy argument is a refusal, not a #: silent grant. That is the exact inverse of `--data-repo`, whose omission printed #: "OS_DATA_REPO unchanged" and left a Space on production. _SANDBOX_STORES_VAR = 'AIOS_SANDBOX_STORES' #: The local (no-identity) escape hatch. Present ⇒ writes to production stores are permitted from a #: machine with no Space identity, AND every commit this process makes is stamped distinguishably #: (see `local_commit_suffix`). Deliberately does NOT widen a Space: a container that HAS an #: identity and is not production is refused with no override, because that is the case the owner #: said "EVER" about. _LOCAL_OPT_IN_VAR = 'AIOS_ALLOW_PRODUCTION_DATA' class StoreWriteRefused(RuntimeError): """A write this deployment is not allowed to make. ⛔ DELIBERATELY NOT A SUBCLASS OF `grid_events.StoreUnavailable`, and the reason is the routes. Several of them carry `except StoreUnavailable:` blocks that DEGRADE to a session-scoped fallback workspace — correct for an outage, catastrophic for a refusal, because the user would be told the change was saved somewhere. A distinct type falls through all of them to the app-level handler, which answers 503 with the reason and never claims a save. """ def _env(name): return str(os.environ.get(name) or '').strip() def deployment_id(): """This container's own identity, or `''` when it is not a Space (i.e. local dev). ⚠ NOT DERIVED FROM ANY DEPLOY ARGUMENT. That is the whole design: `SPACE_ID` is set by the platform inside the container, so it cannot be forgotten, mistyped, or left behind by a Space that changed role without being redeployed. """ sid = _env('SPACE_ID') if sid: return sid author, repo = _env('SPACE_AUTHOR_NAME'), _env('SPACE_REPO_NAME') if author and repo: return f'{author}/{repo}' return '' def is_production_deployment(): """True only on the deployment that owns production data. Unknown ⇒ False (fail closed).""" return deployment_id() in PRODUCTION_SPACES def is_space(): """True when this process is running inside a Space at all. The distinction matters exactly once: a Space that is not production gets NO override, while a laptop does. `deployment_id()` conflates them into `''`, so ask separately. """ return bool(deployment_id()) def sandbox_allowlist(): """The repos a non-production deployment may write: `OS_DATA_REPO` + `AIOS_SANDBOX_STORES`.""" allowed = {r.strip() for r in _env(_SANDBOX_STORES_VAR).split(',') if r.strip()} own = _env('OS_DATA_REPO') if own: allowed.add(own) return frozenset(allowed) def local_override(): """True when a machine with no Space identity has explicitly opted in to production data.""" return (not is_space()) and _env(_LOCAL_OPT_IN_VAR) == '1' def default_store(): """What `OS_DATA_REPO` resolves to when it is unset. ⛔⛔ FACT (1) OF D-315 DIES HERE: `core/store.py` used to read `os.environ.get('OS_DATA_REPO', 'royal-imports/cfo-os-data')`, so a Space that was never given the key — every NEW Space, by construction — came up bound to tenant #0's real business data. The default now exists ONLY on the deployment that owns it. ⚠ IT STILL RETURNS THE PRODUCTION ID ELSEWHERE, RATHER THAN `None` OR `''`, AND THAT IS DELIBERATE. A `None` repo would make `Store.__init__` — which runs at IMPORT time via `_DEFAULT = for_repo(REPO)` — raise or bind something nonsensical, killing the app and every gate on any non-production machine. Returning the real id keeps binding total and lets `write_refusal` refuse the WRITE with a message that names the actual problem. Reads still work, so a developer sees a populated app that will not let them damage it. """ return PRODUCTION_DEFAULT_STORE def write_refusal(repo): """`None` if this deployment may write `repo`, else the sentence explaining why not. ⭐ RETURNS A REASON RATHER THAN A BOOL, because [[report-the-cause-before-you-fix-it]]: a silent refusal makes every theory about it unfalsifiable, and this one fires on a path where the operator cannot read the container's environment (D-160). """ rid = str(repo or '').strip() if not rid: return ('no store repo is bound. Refusing to guess: an unnamed store is how a deployment ' 'ends up on somebody else\'s data.') if is_production_deployment(): return None # rule 1 — the live Space owns its data if rid in PRODUCTION_STORES: # rule 2 — never, from anywhere else if local_override(): return None who = deployment_id() or 'this machine (no Space identity)' if is_space(): return (f'{who} is not the production deployment, so it may not write {rid}, which ' f'holds real customer data. Point this Space at its own store with ' f'--data-repo=, or add it to {_SANDBOX_STORES_VAR}. There is no override for ' f'a Space: a build that is not live never writes live data.') return (f'{who} may not write {rid}, which holds real customer data. Set OS_DATA_REPO to a ' f'sandbox store, or set {_LOCAL_OPT_IN_VAR}=1 to opt in deliberately (every commit ' f'is then stamped as a local write so it can be told apart afterwards).') allow = sandbox_allowlist() # rule 3 — what it was explicitly handed if rid in allow: return None who = deployment_id() or 'this machine (no Space identity)' listed = ', '.join(sorted(allow)) or '(nothing)' return (f'{who} was not given {rid}. A non-production deployment may write only the stores it ' f'was handed: {listed}. Add it to {_SANDBOX_STORES_VAR} if that is intended.') def check_write(repo, operation='write'): """Raise `StoreWriteRefused` unless this deployment may write `repo`. The one enforcement door.""" reason = write_refusal(repo) if reason: raise StoreWriteRefused(f'{operation} to {repo!r} refused: {reason}') def local_commit_suffix(): """A marker appended to commit messages made under the local override, else `''`. ⭐ THIS IS THE SECOND HALF OF D-298's EXIT CONDITION, satisfied rather than argued around: *"a local run either cannot reach the live store without an explicit opt-in, OR stamps its commits distinguishably"*. The measured complaint was that a laptop's commits were titled `update user_tables` — byte-identical to what the live Space writes every few minutes — so a local run and production were indistinguishable in the store's git history, which is the ONLY audit trail this product has. Both clauses now hold: the opt-in is required AND it stamps. """ if not local_override(): return '' import getpass # noqa: PLC0415 — only on the opt-in path import socket # noqa: PLC0415 try: who = getpass.getuser() except Exception: # noqa: BLE001 who = 'unknown' try: host = socket.gethostname() except Exception: # noqa: BLE001 host = 'unknown' return f' [LOCAL DEV {who}@{host}]' def describe(repo=None): """What this container sees about itself — the payload behind the status field. ⛔ IT REPORTS THE RAW OBSERVATIONS, NOT ONLY THE VERDICT, and that is the point rather than debug noise. D-160 established that a Space's environment cannot be read from outside, so "is staging on the right store?" is a question only the container can answer. A verdict alone ("production: false") cannot distinguish "SPACE_ID says staging" from "SPACE_ID does not exist on this platform at all" — two states with the same verdict and completely different fixes. Reporting the variables makes ONE deploy answer it. ⚠ Carries no secret: a Space id and a dataset repo id are public names. The DATA is not, and none of it is here. The field is session-gated anyway (see `routes_admin.settings`). """ rid = str(repo or '').strip() return { 'deployment': deployment_id(), 'production': is_production_deployment(), 'repo': rid, 'writable': write_refusal(rid) is None if rid else False, 'refusal': write_refusal(rid) if rid else None, 'localOverride': local_override(), 'allowlist': sorted(sandbox_allowlist()), # The raw half. `''` means "the variable is absent", which is itself the answer on a # platform that does not set it. 'observed': {name: _env(name) for name in _IDENTITY_VARS}, }