The preview must not know production

R7K1 treated branch code as unaccepted code, using synthetic data, scoped credentials, separate networks, and generated identities instead of production copies.

R7K1's earliest preview looked most convincing when it connected to a copy of production data. Real names, long histories, unusual records, and familiar account states made the branch feel ready.

It also gave unaccepted code access to information and capabilities it did not need.

A branch can contain mistakes, debug logging, new dependencies, and code deliberately under review. Running it behind a password does not make it trusted. The preview environment should know enough to support a meaningful review and as little as possible about production.

R7K1 replaced copied data and shared credentials with synthetic fixtures, scoped identities, separate networks, and explicit integration stubs.

Review fidelity had been confused with data fidelity

The argument for production data was practical: invented fixtures rarely contained the difficult states that real systems accumulated.

The conclusion did not follow. Review needed representative shapes and consequences, not the identities of real people or a live connection to production services.

I inventoried the states reviewers needed:

empty account
ordinary active account
long names and translated content
large history
permission-limited role
expired invitation
partial import
failed external integration
conflicting edits

Each became a generated scenario with invented identities and documented purpose. The fixture schema evolved with the product model.

This shifted fidelity from “looks familiar” to “covers the behavior under review.” The result was more deliberate and safer to share.

I considered copying a database and replacing names and email addresses. Direct identifiers were only part of the risk.

Free-text notes, rare histories, filenames, addresses, timestamps, support messages, and relationships could reidentify a record. Referential integrity made replacement complex. A flawed scrub could leave the most sensitive field precisely because nobody remembered it existed.

The scrubbed copy would also become stale, requiring another export process and another place where production data persisted.

R7K1 rejected production-derived fixtures as the default. A narrowly controlled diagnostic environment for a specific incident would need separate authorization, isolation, retention, and audit—not an option available to every branch.

Synthetic data avoided making anonymization quality a prerequisite for ordinary review.

The preview system's safest production-data pipeline was no pipeline at all.

Fixture identity joined the environment receipt

A label such as “demo data” was too vague. R7K1 versioned fixtures and named scenarios:

fixture catalog: v7
scenario: crowded-workspace
seed: stable generated identity set 14
schema: application migration 93

The environment receipt stored these values. Reviewers could reset to the same scenario and compare generations. A fixture update created a meaningful environment difference even when the application artifact stayed the same.

Stable seeds helped visual comparison while every identity remained invented. Random edge-case generation ran in tests; review scenarios favored readable, repeatable stories.

The fixture builder validated that no reserved real domains, copied identifiers, or production endpoints entered output. Source lived in the repository and received review like application code.

Synthetic did not mean arbitrary. It meant deliberately constructed and reproducible.

Every environment received its own identity

The first previews shared one development API key. If one branch logged or leaked it, every preview inherited the exposure.

R7K1 issued environment-scoped credentials with the minimum operations and expiry needed. The identity included environment generation in its subject or metadata. Revocation happened during removal and independently during an incident.

principal: preview/env-271
audience: sandbox-catalog
capabilities: read fixtures, write own namespace
expires: environment deadline plus cleanup grace

Secrets arrived at runtime through a narrowly readable mechanism, not image layers or build arguments. The build environment did not receive runtime credentials.

The environment receipt recorded credential identity and policy version, never value. Logs could connect a sandbox action to one preview without exposing the secret.

Generated identities limited both blast radius and ambiguity.

Container names and credentials were insufficient if a branch could reach production addresses directly.

Preview runtimes joined networks with explicit egress. They could reach their fixture database, approved sandbox services, and required public endpoints. Production databases, management APIs, host metadata, and internal control services were not routable.

Build workers had a different network policy focused on dependency retrieval and artifact upload. A package install script could not inherit the preview application's sandbox credential or reach its database.

Exceptions were declared per project and reviewed with destination, protocol, purpose, and expiry. “Needs internet” was not a sufficient rule.

Network policy could fail or be misconfigured, so sandbox services still enforced scoped identity. Defense did not rely on one boundary.

The preview was treated as a small untrusted tenant, not a friendly process on an internal LAN.

Convenient Docker setups mounted the host container socket or broad source directories into build containers. That would let branch code control sibling environments or read controller state.

R7K1 prohibited management sockets and sensitive host mounts. Workers exposed a narrow job interface: receive source snapshot and declared inputs, produce an output directory, write logs, exit.

The trusted collector calculated artifact identity and uploaded it. Runtime containers received only their application artifact, scoped configuration, and environment volumes.

Debugging happened through controlled log and shell access under operator authorization. The application could not request arbitrary host paths as volumes.

Container isolation was one layer. Capability minimization kept a container escape or configuration mistake from beginning with unnecessary power.

The preview system did not need branch code to manage previews. Only R7K1 needed that privilege.

External integrations were contracts, not copies

Email, payments, webhooks, storage, search, and analytics each posed a question. Should a preview call the real service, a vendor sandbox, a local stub, or nothing?

R7K1 declared the answer per capability:

IntegrationPreview behavior
EmailCapture locally; never deliver externally
Payment-like flowVendor sandbox with environment-scoped identity
WebhooksGenerated receiver in preview namespace
Object storageIsolated bucket or prefix with expiry
SearchFixture index rebuilt per environment
AnalyticsDisabled or routed to discard sink

The preview header linked to captured email and webhook views where useful. Reviewers could experience the workflow without producing real-world side effects.

Stubs recorded the request and returned scenario-specific responses, including failures. They did not always say success and create false confidence.

Integration fidelity became an explicit contract with known differences from production.

One early branch used the shared development mail relay and sent a fixture invitation to an address that happened to be real. The data was synthetic; the side effect was not.

R7K1's preview mail service accepted messages only inside the environment and exposed them in a protected inbox. It rejected external delivery. Recipient addresses used reserved example domains generated by fixture policy.

The application still exercised templates, links, tokens, and multi-message flows. Links returned to the preview route and carried scoped synthetic tokens.

The environment page showed mail count and offered reset. Expiry removed captured content under the same lifecycle.

This was a useful reminder that privacy and isolation include outputs. Preventing production reads is insufficient if unaccepted code can send messages, charge accounts, or mutate external systems.

The safest preview side effect is one whose entire world is also a preview.

Logs were another data boundary

Branch code could log request bodies, headers, database rows, and environment variables. Centralized logs then retained that data beyond environment expiry.

Synthetic fixtures reduced exposure but did not justify indiscriminate logging. R7K1 redacted known secret fields at collection, bounded log retention, and restricted access by repository and review scope.

Runtime credentials never appeared in the environment page. Debug bundles included identity and configuration names, not complete environment dumps.

Application logs carried environment and artifact identity so operators did not need payload content to determine origin. A “download all logs” action recorded access.

The project documented that redaction is imperfect. The strongest protection remained not placing sensitive production information in a preview where branch code could print it.

Isolation policy followed data after execution, not only while it sat in a database.

Generated hostnames were not secrets. A branch label could be guessed, DNS records could be observed, and links could be forwarded.

R7K1 protected preview routes according to repository policy. Authentication occurred at the routing boundary before traffic reached the application. The branch could not accidentally remove it.

Authorization checked review membership or an explicit share policy. Public demonstrations used a separate environment class with data and capabilities suitable for public access.

The router stripped untrusted identity headers from incoming requests and added its own signed or protected context where the application needed a preview user. Applications still implemented their own role behavior through fixture identities.

Access logs followed a bounded policy. Protecting previews did not justify permanent surveillance of every review click.

A random hostname reduced collisions. It never replaced authorization.

Preview identity could not impersonate production

Cookies, OAuth redirect URIs, webhook origins, and CORS rules often rely on host identity. Giving previews subdomains too close to production could allow accidental credential sharing or overly broad domain cookies.

R7K1 used a separate preview domain and avoided production parent-domain cookies. Sandbox OAuth clients allowed only generated preview callbacks under controlled policy. Production clients did not accept preview origins.

The router set a clear preview marker and security headers. The application rendered a persistent environment banner outside the candidate where feasible.

DNS and certificate automation owned the preview domain as its own system. Removing an environment retired the route; it did not alter production DNS.

Separation reduced the chance that a browser carried production ambient authority into unaccepted code.

The preview should resemble production behavior without being able to become production identity.

Preview builds favored debugging and sometimes included source maps, unminified code, or build metadata unsuitable for public release.

R7K1 classified artifacts by environment. A preview artifact remained protected and expired under review policy. Production could reuse core compiled output only when its manifest and disclosure policy matched; it did not blindly promote a debug artifact.

Source maps referenced repository paths and potentially embedded source. Access followed review authorization. The router did not expose directory listings or build logs under predictable public paths.

Artifact storage separated metadata permissions from blob reuse. Identical public bundles could be shared while protected source maps remained scoped.

This was another place where “same code” did not mean “same release artifact.” Debugging capability is information and needs ownership.

Dependency installation was not passive file download. Package scripts could run arbitrary code under the build worker's identity.

R7K1 isolated dependency work, denied runtime and production secrets, restricted egress, and used locked dependency resolution. Cache contents were treated as untrusted input until verified by the package manager and build policy available to the project.

The artifact uploader lived outside the branch process. A malicious build could produce bad application output—that was what review was for—but it could not publish under another manifest or overwrite a verified artifact directly.

High-risk dependency changes could trigger stricter policy or manual approval. The system recorded lockfile digest in the build manifest so a review knew when dependency code changed.

Preview security began before the application container existed.

Reset was a destructive action with a small scope

Reviewers needed to restore fixtures after testing. The first reset button dropped and recreated a database selected by hostname. A routing mistake could point it at the wrong target.

The reset operation used environment and database receipt identity, verified ownership labels, detached active writes briefly, recreated from the declared synthetic fixture, and returned a new data generation.

It could affect only the caller's preview namespace. Production endpoints did not implement the preview reset capability. Credentials lacked permission outside their environment.

The UI named what would disappear: review-created changes and captured messages for this environment. It did not call reset harmless merely because data was synthetic.

Stable scope made destructive convenience safe enough to use frequently.

Expiry removed capabilities before bytes

When an environment expired, R7K1 detached its route and revoked runtime credentials before removing containers and data. A cleanup delay therefore left fewer usable capabilities.

Sandbox tokens had their own expiry close to the environment deadline. Network policy and provider namespaces tied resources to environment identity. Captured email, objects, and logs followed bounded retention.

Removal receipts verified that external sandbox resources were gone. An orphan scanner found buckets, databases, and credentials with no active environment.

The branch source and build manifest could remain for history without preserving live access. Evidence and capability had different retention needs.

Security improved when expiry was treated as revocation workflow, not only resource housekeeping.

A production-like incident had a separate path

Sometimes a bug depended on data shape no synthetic fixture represented. The response was not to connect the ordinary branch preview to production.

R7K1's design brief allowed a separate, rare diagnostic workflow:

explicit authorization and owner
minimum extracted or recreated data
additional transformation and review
stronger isolation and no general branch access
short expiry and access audit
no outbound side effects
documented destruction receipt

In many cases, creating a new synthetic regression fixture was better. It turned one incident into durable, shareable test coverage without retaining real data.

The exception path remained intentionally inconvenient. Convenience is what turns a rare sensitive operation into routine exposure.

Ordinary previews stayed safe because they did not accumulate production-shaped exceptions.

The environment page listed its policy class, fixture identity, allowed integrations, expiry, and any granted exception. It did not show one green shield implying complete safety.

Reviewers saw “synthetic data,” “email captured locally,” and “payment sandbox.” Developers saw network and secret policy versions in detail. An exception such as temporary access to a vendor test API was named with owner and deadline.

The page could not prove branch code was safe. It explained the capabilities R7K1 had granted it.

This language kept security scoped. A locked route proved access control. A sandbox token proved limited authority. A synthetic fixture reduced data consequence. None authenticated the code's intentions.

Clear boundaries were more useful than a universal secure status.

We tested escapes, not only happy reviews

Scenario tests attempted to:

  • reach a production hostname,
  • use a preview credential against another environment,
  • deliver email externally,
  • write outside the environment storage prefix,
  • read another preview's logs,
  • override trusted routing identity headers,
  • upload an artifact under another manifest,
  • reset a database with a forged identifier,
  • continue calling a sandbox after expiry.

The expected outcome combined denial and evidence. The action failed, and logs identified environment and policy boundary without exposing secrets.

Tests also verified intended capability. An environment too isolated to install declared dependencies or send mail to its capture service was not useful.

Security validation became a set of concrete reachability statements, not an assumption inherited from container use.

The fixture effort initially felt like a security tax. It became a design tool.

Long names, empty states, permission limits, delayed jobs, and conflicting histories were now one click away. Review no longer depended on whatever happened to exist in a copied database. Scenarios could be linked from a review and reproduced after the original environment expired.

Fixtures also revealed domain assumptions. If generating a valid “partially imported workspace” was difficult, the model or setup workflow was poorly understood. The fixture builder became a second client of the domain contract.

Production data had offered realism through accident. Synthetic scenarios offered coverage through intent.

The safer system became more useful because it made edge states first-class.

The preview learned only what it needed

R7K1's final boundary was not “preview is secure.” It was a capability inventory:

one immutable candidate artifact
one synthetic fixture namespace
one scoped runtime identity
declared sandbox integrations
bounded network reach
protected reviewer route
bounded logs and storage
one expiry and revocation lifecycle

Unaccepted code could still be wrong or hostile. The system reduced what that code could learn and affect, then made exceptions visible.

The central correction was abandoning production resemblance as the highest form of fidelity. A preview exists to support judgment before acceptance. Its world should be representative enough to evaluate and limited enough that mistakes remain previews.

The preview must not know production because its entire purpose is to run code that production has not yet learned to trust.