@rehearsal-db/core 0.1.0-beta.1 → 0.1.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CHANGELOG.md +244 -1
  2. package/COMPATIBILITY.md +17 -0
  3. package/README.md +139 -346
  4. package/SECURITY.md +2 -1
  5. package/SUPPORT.md +5 -0
  6. package/docs/README.md +29 -0
  7. package/docs/adapters.md +20 -6
  8. package/docs/architecture.md +58 -0
  9. package/docs/baselines.md +102 -22
  10. package/docs/commands.md +196 -33
  11. package/docs/configuration.md +258 -13
  12. package/docs/getting-started.md +106 -182
  13. package/docs/glossary.md +11 -8
  14. package/docs/production-source.md +176 -33
  15. package/docs/releasing.md +28 -38
  16. package/docs/roadmap.md +41 -0
  17. package/docs/runtime-policies.md +193 -0
  18. package/docs/sanitization.md +43 -8
  19. package/docs/security-model.md +34 -9
  20. package/docs/standalone-workflow.md +107 -0
  21. package/docs/troubleshooting.md +102 -2
  22. package/docs/tutorial.md +70 -59
  23. package/package.json +30 -22
  24. package/scripts/runtime/manage_database.mjs +18 -0
  25. package/src/README.md +17 -0
  26. package/src/application/session.mjs +435 -0
  27. package/{scripts/lib/rehearsal/baseline_artifact.mjs → src/baseline/artifact.mjs} +142 -17
  28. package/{scripts/lib/rehearsal/baseline_builder.mjs → src/baseline/builder.mjs} +19 -10
  29. package/src/baseline/input_discovery.mjs +155 -0
  30. package/src/baseline/policy_review.mjs +92 -0
  31. package/src/baseline/preparation.mjs +323 -0
  32. package/src/baseline/privacy_engine.mjs +413 -0
  33. package/{scripts/lib/rehearsal → src/baseline}/sanitization_policy.mjs +133 -3
  34. package/{scripts/lib/rehearsal → src/baseline}/schema_snapshot.mjs +1 -1
  35. package/src/cli/arguments.mjs +123 -0
  36. package/src/cli/guided.mjs +812 -0
  37. package/src/cli/rehearsal.mjs +997 -0
  38. package/src/cli/renderers.mjs +584 -0
  39. package/src/cli/runtime_commands.mjs +624 -0
  40. package/src/cli/source_commands.mjs +326 -0
  41. package/src/cli/terminal.mjs +275 -0
  42. package/src/identity/claim.mjs +975 -0
  43. package/src/identity/storage.mjs +165 -0
  44. package/{scripts/lib/rehearsal → src/project}/configuration.d.mts +72 -4
  45. package/src/project/configuration.mjs +1199 -0
  46. package/src/project/setup.mjs +379 -0
  47. package/src/project/support_report.mjs +105 -0
  48. package/src/runtime/cleanup.mjs +381 -0
  49. package/{scripts/lib/rehearsal → src/runtime}/plan.mjs +118 -20
  50. package/src/runtime/policy.mjs +438 -0
  51. package/{scripts/lib/rehearsal/runtime_restore.mjs → src/runtime/restore.mjs} +46 -27
  52. package/src/runtime/topology.mjs +177 -0
  53. package/{scripts/lib/rehearsal → src/shared}/diagnostics.mjs +10 -3
  54. package/src/shared/human_output.mjs +4 -0
  55. package/src/shared/operation_guard.mjs +162 -0
  56. package/{scripts/lib/rehearsal → src/shared}/process_environment.mjs +5 -1
  57. package/src/source/access.mjs +578 -0
  58. package/src/source/asset_transfer.mjs +177 -0
  59. package/src/source/baseline.mjs +446 -0
  60. package/src/source/postgresql_access.mjs +480 -0
  61. package/src/targets/postgresql.mjs +808 -0
  62. package/{scripts/operations/database/manage_rehearsal_database.mjs → src/targets/supabase.mjs} +66 -20
  63. package/{scripts/lib/environment/local_supabase.mjs → src/targets/supabase_environment.mjs} +60 -28
  64. package/src/targets/target.mjs +66 -0
  65. package/scripts/lib/rehearsal/configuration.mjs +0 -559
  66. package/scripts/operations/rehearsal/rehearsal_cli.mjs +0 -565
  67. /package/{scripts/lib/rehearsal → src/runtime}/migration_history.mjs +0 -0
  68. /package/{scripts/lib/rehearsal → src/runtime}/service_environment.mjs +0 -0
@@ -1,247 +1,171 @@
1
1
  # Getting started
2
2
 
3
- This guide creates a safe local Rehearsal project from synthetic data. It does not
4
- connect to production, request hosted credentials, or require an existing baseline.
3
+ This guide sets up Rehearsal in an existing project. It creates a disposable database on
4
+ your computer. Normal setup and rehearsal commands never connect to a hosted database.
5
5
 
6
- ## Prerequisites
6
+ Want to experiment first? Use the [safe hands-on tutorial](tutorial.md).
7
7
 
8
- - Node.js 24
9
- - npm
10
- - Supabase CLI 2.117.0 (the version proved by package CI)
11
- - Docker Desktop, Colima, or another Docker-compatible engine
12
- - a Supabase project with timestamped SQL migrations
8
+ ## 1. Check the required tools
13
9
 
14
- Confirm the tools first:
10
+ You need Node.js 24, npm, and a running Docker-compatible engine:
15
11
 
16
12
  ```bash
17
13
  node --version
18
14
  npm --version
19
- supabase --version
20
15
  docker info
21
16
  ```
22
17
 
23
- If you want to see the complete lifecycle before touching your own project, clone the
24
- Rehearsal repository and run:
18
+ `node --version` must begin with `v24`. If `docker info` fails, start Docker Desktop,
19
+ Colima, or your usual Docker engine.
25
20
 
26
- ```bash
27
- npm ci --ignore-scripts
28
- npm run test:fixture
29
- ```
21
+ Choose the extra requirement for your project:
30
22
 
31
- That proof installs the packed package into a disposable fictional project, restores a
32
- row and Storage object, applies a valid migration, rejects invalid SQL, and removes only
33
- its labeled local runtime. It does not need a hosted Supabase project or credentials.
23
+ - **Supabase:** install Supabase CLI 2.117.0 and run `supabase --version`.
24
+ - **PostgreSQL:** download the local database image once:
34
25
 
35
- ## 1. Install and initialize
26
+ ```bash
27
+ docker pull postgres:17-alpine
28
+ ```
36
29
 
37
- ```bash
38
- npm install --save-dev @rehearsal-db/core
39
- npx rehearsal init
40
- ```
30
+ Rehearsal will use that image with downloads disabled.
31
+
32
+ ## 2. Install and open the guide
41
33
 
42
- `init` is a preview. Read the generated configuration, then explicitly write it:
34
+ Run these commands from the directory containing your project's `package.json`:
43
35
 
44
36
  ```bash
45
- npx rehearsal init --write
37
+ npm install --save-dev @rehearsal-db/core@beta
38
+ npx rehearsal
46
39
  ```
47
40
 
48
- Rehearsal never overwrites an existing configuration.
41
+ Choose **Set the stage**, then choose Supabase or PostgreSQL. Rehearsal previews every file
42
+ before asking to create it. It will not replace an existing file.
49
43
 
50
- The generated configuration is intentionally incomplete until you review its ports,
51
- project ID, application commands, and project-owned input paths. Do not run `doctor`
52
- until the next section's files exist.
44
+ Review the generated `rehearsal.config.mjs`, especially:
53
45
 
54
- ## 2. Add the project-owned inputs
46
+ - the migration directory;
47
+ - the application start and proof commands;
48
+ - the local ports.
55
49
 
56
- Create the paths named by `rehearsal.config.ts`:
50
+ The proof command should check behavior changed by the migration. A test that only checks
51
+ whether the home page loads is usually too weak.
57
52
 
58
- - a dedicated local Supabase `config.toml`;
59
- - a sanitization policy describing every exported field;
60
- - an active baseline below `.rehearsal/`;
61
- - an application proof command that exits nonzero when the restored app is wrong.
62
-
63
- For the generated default paths:
64
-
65
- ```bash
66
- mkdir -p infrastructure/rehearsal/supabase infrastructure/rehearsal rehearsal
67
- cp supabase/config.toml infrastructure/rehearsal/supabase/config.toml
68
- ```
53
+ ## 3. Prepare safe baseline inputs
69
54
 
70
- Edit the copied Supabase config. Give it the same unique `project_id`, API port, database
71
- port, and Studio port used by `rehearsal.config.ts`. Disable services your proof does
72
- not need. This must remain an unlinked local config; never run `supabase link` from it.
55
+ A **baseline** is the locked starting point restored before each rehearsal. Start with a
56
+ small synthetic dataset. Do not use raw production data.
73
57
 
74
- Also replace the generated `application.startCommand`, `application.proofCommand`, and
75
- `verification.commands` with real commands from your project. The proof should check a
76
- restored relationship and the candidate schema—not merely that `/` returns 200.
58
+ Rehearsal needs:
77
59
 
78
- Start with synthetic rows shaped like your schema. Do not start onboarding with
79
- production data. The following SQL, policy, row, and ledger form one matched example;
80
- do not mix them with differently shaped snippets.
60
+ | Input | What it contains |
61
+ | ------------------- | ---------------------------------------------------- |
62
+ | Records | Safe rows in NDJSON format: one JSON object per line |
63
+ | Migration ledger | The historical migrations represented by those rows |
64
+ | Sanitization policy | A decision for every included table and column |
65
+ | Storage manifest | Optional Supabase Storage files only |
81
66
 
82
- Historical migration `supabase/migrations/20260101000000_create_widgets.sql`:
67
+ A record looks like this:
83
68
 
84
- ```sql
85
- create table public.widgets (
86
- id bigint generated by default as identity primary key,
87
- name text not null,
88
- created_at timestamptz not null default now()
89
- );
90
-
91
- insert into storage.buckets (id, name, public)
92
- values ('fixture-assets', 'fixture-assets', false);
69
+ ```json
70
+ { "table": "widgets", "row": { "id": 1, "name": "Synthetic Widget" } }
93
71
  ```
94
72
 
95
- Sanitization policy `infrastructure/rehearsal/sanitization-policy.json`:
73
+ Put your safe records and ledger inside the project. Conventional names such as
74
+ `rehearsal/sanitized-data.ndjson` and `rehearsal/migration-ledger.json` are discovered
75
+ automatically. The guide inspects their structure but does not print row values.
96
76
 
97
- ```json
98
- {
99
- "policyVersion": 1,
100
- "migrationCutoff": "20260101000000",
101
- "tables": [
102
- {
103
- "name": "widgets",
104
- "group": "synthetic",
105
- "sourceRows": "STREAM AND SANITIZE",
106
- "columns": [
107
- {
108
- "name": "id",
109
- "action": "KEEP EXACTLY",
110
- "generated": "NEVER",
111
- "identity": "YES",
112
- "foreignKey": null
113
- },
114
- {
115
- "name": "name",
116
- "action": "REPLACE WITH SYNTHETIC",
117
- "generated": "NEVER",
118
- "identity": "NO",
119
- "foreignKey": null
120
- },
121
- {
122
- "name": "created_at",
123
- "action": "DERIVE",
124
- "generated": "NEVER",
125
- "identity": "NO",
126
- "foreignKey": null
127
- }
128
- ]
129
- }
130
- ]
131
- }
132
- ```
77
+ Follow the guide's recommended actions:
133
78
 
134
- Safe row `rehearsal/synthetic-data.ndjson` (one JSON object per physical line):
79
+ 1. **Prepare the script** creates a draft sanitization policy.
80
+ 2. **Review the script** asks you to classify every table and column.
81
+ 3. **Create the baseline** validates and activates the reviewed inputs.
135
82
 
136
- ```json
137
- {
138
- "table": "widgets",
139
- "row": {
140
- "id": 1,
141
- "name": "Synthetic Widget",
142
- "created_at": "2026-01-01T00:00:00.000Z"
143
- }
144
- }
145
- ```
83
+ Rehearsal will not activate a policy containing undecided fields.
146
84
 
147
- Migration ledger `rehearsal/migration-ledger.json`:
85
+ The ledger must describe the exact historical SQL included in the baseline. Do not type
86
+ years of migration history by hand for a real project. Generate it through reviewed
87
+ project tooling. The [tutorial](tutorial.md) contains a complete synthetic example, and
88
+ [Baselines](baselines.md) explains the file formats.
148
89
 
149
- ```json
150
- [
151
- {
152
- "version": "20260101000000",
153
- "name": "create_widgets",
154
- "statements": [
155
- "create table public.widgets (\n\tid bigint generated by default as identity primary key,\n\tname text not null,\n\tcreated_at timestamptz not null default now()\n)",
156
- "insert into storage.buckets (id, name, public)\nvalues ('fixture-assets', 'fixture-assets', false)"
157
- ]
158
- }
159
- ]
160
- ```
90
+ ## 4. Reach READY
161
91
 
162
- The ledger is evidence, not a second migration language. Its version, name, order, and
163
- statements must exactly represent the historical migration bytes in the baseline. SQL
164
- that is merely equivalent is rejected. For a production-shaped baseline, generate this
165
- ledger through the project's reviewed source/export tooling; do not reconstruct years of
166
- history by hand.
92
+ The guide displays four setup stages. Continue with its recommended action until all
93
+ checks are complete and the project reports `READY`.
167
94
 
168
- Then activate the safe input:
95
+ You can run the same check directly:
169
96
 
170
97
  ```bash
171
- npx rehearsal baseline create \
172
- --records=rehearsal/synthetic-data.ndjson \
173
- --ledger=rehearsal/migration-ledger.json
98
+ npx rehearsal doctor
174
99
  ```
175
100
 
176
- The independent fixture in this repository is the executable reference example.
101
+ If it reports `NOT READY`, fix the listed item and run it again. Do not bypass a check or
102
+ add a hosted connection string.
177
103
 
178
- Expected result:
104
+ ## 5. Run the rehearsal
179
105
 
180
- ```text
181
- Activated synthetic baseline ...: 1 rows across 1 tables; 1 migrations through 20260101000000.
182
- ```
106
+ Choose **Run a rehearsal**. Rehearsal shows the exact candidate migrations and asks for
107
+ confirmation before it changes the disposable runtime.
183
108
 
184
- ## 3. Check readiness
109
+ A successful run:
185
110
 
186
- ```bash
187
- npx rehearsal doctor
188
- ```
111
+ 1. restores the baseline;
112
+ 2. applies only the migrations you approved;
113
+ 3. verifies the local database;
114
+ 4. launches the ordinary application when readiness is configured;
115
+ 5. runs the ordinary test command and declared positive/negative HTTP proofs;
116
+ 6. stops only the application process it launched.
117
+
118
+ Your original baseline remains unchanged.
189
119
 
190
- Do not continue until it ends with `READY`. Doctor checks the local-only boundary,
191
- dependencies, artifact integrity, migration lineage, ports, and project commands.
120
+ If a source owner later approves a production-shaped copy, use the separate workflow in
121
+ [Optional production-shaped preparation](production-source.md). Do not add source
122
+ credentials to the normal config or runtime environment.
192
123
 
193
- If it reports `NOT READY`, fix each named prerequisite and rerun it. Do not bypass a
194
- check or copy a hosted connection string into the generated runtime environment.
124
+ Once temporary source access is ready, `npx rehearsal refresh` previews the safe
125
+ replacement workflow. It means “get a newly verified copy.” By contrast, `reset` means
126
+ “discard local edits and restore the copy I already have.”
195
127
 
196
- ## 4. Review pending work
128
+ ## 6. Use the sandbox and clean up
129
+
130
+ Choose **Open the sandbox app**, or run:
197
131
 
198
132
  ```bash
199
- npx rehearsal explain
200
- npx rehearsal candidates
201
- npx rehearsal inspect baseline
202
- npx rehearsal inspect migrations
133
+ npx rehearsal open
203
134
  ```
204
135
 
205
- The plan prints an exact candidate digest. It does not start services or change data.
136
+ Open the local URL printed by Rehearsal. The app stays available for hands-on testing
137
+ until you press `Ctrl+C`. Only the app stops; your local database and Storage changes are
138
+ kept. Run `npx rehearsal open` again to continue where you left off.
206
139
 
207
- ## 5. Run the rehearsal
140
+ Use the guide for normal runtime tasks:
208
141
 
209
- ```bash
210
- npx rehearsal run --confirm-candidates=<sha256>
211
- ```
142
+ - **Verify** checks the current runtime.
143
+ - **Reset** discards runtime edits and restores the baseline.
144
+ - **Stop** stops the runtime but keeps its local state.
145
+ - **Discard** removes this project's disposable runtime and volume.
146
+
147
+ Press `Ctrl+Z` at any prompt to exit the entire guide. It will not leave a suspended
148
+ process behind.
212
149
 
213
- Rehearsal restores the immutable baseline, applies only the confirmed migration suffix,
214
- verifies the runtime, and runs the project-owned application proof. The resulting local
215
- database is writable, so you can test real application changes without mutating the
216
- baseline.
150
+ ## Command-line setup
217
151
 
218
- ## 6. Work, verify, and reset
152
+ The guide is recommended for people. Scripts and CI can use explicit commands:
219
153
 
220
154
  ```bash
221
- npx rehearsal status
222
- npx rehearsal start
223
- npx rehearsal verify
224
- npx rehearsal reset
225
- npx rehearsal stop
155
+ npx rehearsal setup --target=postgresql --write
156
+ npx rehearsal doctor
157
+ npx rehearsal candidates
158
+ npx rehearsal run --confirm-candidates=PASTE_DIGEST_HERE
226
159
  ```
227
160
 
228
- Changes persist in the disposable runtime until `reset` or runtime removal. `start`
229
- resumes that runtime without resetting it. `reset` restores the exact baseline. `stop`
230
- stops only this project's runtime.
231
-
232
- ## Next steps
233
-
234
- - Follow [the full tutorial](tutorial.md).
235
- - Read [the security model](security-model.md) before designing a production export.
236
- - Define an exhaustive [sanitization policy](sanitization.md).
237
- - Learn the [baseline lifecycle](baselines.md).
161
+ Replace `postgresql` with `supabase` when needed. See [CLI commands](commands.md) for the
162
+ complete reference and [Troubleshooting](troubleshooting.md) when a check fails.
238
163
 
239
- ## Generated files
164
+ ## Files Rehearsal creates
240
165
 
241
- - `rehearsal.config.ts` is written only by `init --write`.
242
- - `.rehearsal/generations/<id>/` contains one immutable baseline generation.
243
- - `.rehearsal/current` selects the active generation atomically.
244
- - `.rehearsal/runtime/` contains the disposable local Supabase project and receipts.
245
- - `.rehearsal/runtime.env` contains generated loopback-only application credentials.
166
+ - `rehearsal.config.mjs` — reviewed project configuration
167
+ - `.rehearsal/` — ignored baselines, runtime files, and receipts
168
+ - `.rehearsal/runtime.env` — generated local-only application variables
169
+ - `infrastructure/rehearsal/supabase/config.toml` — Supabase-only local configuration
246
170
 
247
- Ignore all of `.rehearsal/`. Do not commit it even when its inputs were synthetic.
171
+ Keep `.rehearsal/` out of source control, even when its data is synthetic.
package/docs/glossary.md CHANGED
@@ -1,4 +1,4 @@
1
- # Glossary and architecture
1
+ # Glossary
2
2
 
3
3
  **Baseline** — immutable sanitized starting artifact.
4
4
 
@@ -6,6 +6,10 @@
6
6
 
7
7
  **Candidate digest** — checksum binding the exact candidate filenames and bytes.
8
8
 
9
+ **Dependent target** — another isolated local database managed with the primary runtime.
10
+
11
+ **Combined digest** — one checksum binding candidate or cleanup sets across every target.
12
+
9
13
  **Project-owned** — application-specific policy or code that remains outside the package.
10
14
 
11
15
  **Represented migration** — historical migration whose exact bytes are bound into the
@@ -19,13 +23,12 @@ baseline.
19
23
 
20
24
  ```mermaid
21
25
  flowchart LR
22
- A[Project-owned approved source] --> B[Project-owned sanitization]
23
- B --> C[Immutable baseline]
24
- D[Project migrations] --> E[Digest planner]
25
- C --> F[Disposable local Supabase]
26
- E --> F
27
- F --> G[Project application proof]
28
- G --> H[Verified local receipt]
26
+ A[Safe rows] --> B[Locked baseline]
27
+ C[Migration files] --> D[Reviewed plan]
28
+ B --> E[Disposable local database]
29
+ D --> E
30
+ E --> F[Application proof]
31
+ F --> G[Verified result]
29
32
  ```
30
33
 
31
34
  The reusable package owns the path from a completed baseline plus migration directory to
@@ -1,33 +1,176 @@
1
- # Designing a production source boundary
2
-
3
- The npm package does not connect to production and does not ship an extraction command.
4
- That separation is a security boundary: each project must authorize, sanitize, and
5
- audit its own source.
6
-
7
- ## Recommended flow
8
-
9
- 1. Define versioned read-only export views containing only approved columns.
10
- 2. Grant a temporary role `SELECT` on those views and nothing else.
11
- 3. Use a short-lived credential outside shell history and source control.
12
- 4. Stream records through the project-owned sanitization policy.
13
- 5. Write into a private building generation below `.rehearsal`.
14
- 6. Verify counts, checksums, policy coverage, migration history, and secret canaries.
15
- 7. Atomically activate the completed generation.
16
- 8. Revoke and verify removal of the temporary credential.
17
- 9. Delete raw intermediate files and retain only the sanitized artifact.
18
-
19
- Use server-side cursors or another bounded streaming mechanism. A full in-memory dump
20
- is not acceptable for large sources. Extraction logs should contain counts and hashes,
21
- never row bodies.
22
-
23
- ## What not to do
24
-
25
- - Do not point `rehearsal.config.ts` at a hosted URL.
26
- - Do not put a production connection string in `.rehearsal/runtime.env`.
27
- - Do not grant table-wide access merely because a view is inconvenient.
28
- - Do not commit sanitized baselines; sanitized data is still data.
29
- - Do not let the reusable package infer which fields are safe.
30
- - Do not leave the export role provisioned after refresh.
31
-
32
- The local execution engine remains useful with synthetic or manually approved baselines.
33
- Production-shaped onboarding is a separate project security exercise.
1
+ # Optional production-shaped preparation
2
+
3
+ Start with synthetic data. Use this workflow only when the source owner has approved the
4
+ exact tables, columns, owner scope, assets, and privacy policy.
5
+
6
+ Ordinary Rehearsal commands remain local-only. Source preparation is separate and cannot
7
+ be triggered by `run`, `reset`, `migrate`, `verify`, or application launch.
8
+
9
+ ## 1. Add the config paths
10
+
11
+ ```js
12
+ preparation: {
13
+ sourcePolicy: "infrastructure/rehearsal/source-access-policy.json",
14
+ privacyKey: ".rehearsal/secrets/privacy.key",
15
+ batchRows: 500,
16
+ maximumRows: 1000000,
17
+ maximumBytes: 2147483648,
18
+ diskHeadroomBytes: 67108864,
19
+ },
20
+ ```
21
+
22
+ The privacy key stays ignored under `.rehearsal`. The policy is safe to review in source
23
+ control because it contains hashes and environment-variable names, not credentials,
24
+ URLs, or raw owner identifiers.
25
+
26
+ ## 2. Declare the source boundary
27
+
28
+ `source-access-policy.json` uses this shape:
29
+
30
+ ```json
31
+ {
32
+ "accessVersion": 1,
33
+ "targetFingerprint": "<sha256 of the approved PostgreSQL host, port, and database>",
34
+ "administratorEnvironmentVariable": "REHEARSAL_SOURCE_ADMIN_URL",
35
+ "reader": {
36
+ "role": "rehearsal_example_reader",
37
+ "ownerRole": "rehearsal_example_owner",
38
+ "credentialFile": ".rehearsal/secrets/source-reader.env",
39
+ "validForMinutes": 30
40
+ },
41
+ "exportSchema": "rehearsal_export_example",
42
+ "migrationLedger": {
43
+ "schema": "supabase_migrations",
44
+ "table": "schema_migrations",
45
+ "versionColumn": "version",
46
+ "nameColumn": "name",
47
+ "statementsColumn": "statements"
48
+ },
49
+ "relations": [
50
+ {
51
+ "source": { "schema": "public", "table": "widgets" },
52
+ "view": "widgets",
53
+ "targetSchema": "public",
54
+ "targetTable": "widgets",
55
+ "columns": ["id", "owner_id", "name"],
56
+ "orderBy": ["id"],
57
+ "rowScope": { "kind": "approved-public" }
58
+ },
59
+ {
60
+ "source": { "schema": "public", "table": "profiles" },
61
+ "view": "approved_owner_profile",
62
+ "targetSchema": "app_api",
63
+ "targetTable": "profiles",
64
+ "columns": ["id", "email"],
65
+ "orderBy": ["id"],
66
+ "rowScope": {
67
+ "kind": "approved-owner",
68
+ "column": "id",
69
+ "valueEnvironmentVariable": "REHEARSAL_APPROVED_OWNER_ID"
70
+ }
71
+ }
72
+ ],
73
+ "assets": []
74
+ }
75
+ ```
76
+
77
+ Calculate fingerprints with the exported helpers from `@rehearsal-db/core/source-access`
78
+ or a reviewed local script. A fingerprint binds the destination without recording its
79
+ address. Changing the host, port, or database invalidates the plan.
80
+
81
+ `approved-public` means every selected row is licensed or otherwise approved for this
82
+ use. `approved-owner` requires one explicit owner value from the named environment
83
+ variable. Rehearsal never chooses an owner by finding an administrator.
84
+
85
+ `targetSchema` is optional and defaults to `public`. Set it when the restored relation
86
+ belongs elsewhere, and use the same schema in privacy policy version 2. This is relation
87
+ identity, not a request to search every schema.
88
+
89
+ For Storage, add an `assetReader` block and approved `assets` entries. The reader URL and
90
+ token come from named environment variables. Objects outside the exact bucket/prefix are
91
+ not listed or downloaded. Size, object-count, path, ETag, and exact-byte checks apply.
92
+
93
+ ## 3. Use executable privacy policy version 2
94
+
95
+ Every selected column has one action and, where required, a bounded recipe:
96
+
97
+ ```json
98
+ {
99
+ "policyVersion": 2,
100
+ "migrationCutoff": "20260101000000",
101
+ "tables": [
102
+ {
103
+ "schema": "app_api",
104
+ "name": "profiles",
105
+ "sourceRows": "STREAM AND SANITIZE",
106
+ "columns": [
107
+ {
108
+ "name": "id",
109
+ "action": "PSEUDONYMIZE",
110
+ "recipe": { "format": "uuid", "namespace": "account-id" },
111
+ "generated": "NEVER",
112
+ "identity": "NO",
113
+ "foreignKey": null
114
+ },
115
+ {
116
+ "name": "email",
117
+ "action": "PSEUDONYMIZE",
118
+ "recipe": { "format": "email", "namespace": "account-email" },
119
+ "generated": "NEVER",
120
+ "identity": "NO",
121
+ "foreignKey": null
122
+ }
123
+ ]
124
+ }
125
+ ]
126
+ }
127
+ ```
128
+
129
+ Supported recipes are intentionally small: keyed UUID/email/text/integer pseudonyms,
130
+ explicit constants, bounded date shifts, and fully classified JSON objects. Unknown
131
+ tables, columns, JSON keys, formats, and recipes stop the refresh. There is no JavaScript
132
+ or SQL escape hatch.
133
+
134
+ ## 4. Preview, apply, refresh, and retire
135
+
136
+ Keep credentials out of shell history by loading them from an owner-only environment
137
+ manager or file, then run:
138
+
139
+ ```bash
140
+ npx rehearsal privacy key --write
141
+ npx rehearsal source plan
142
+ npx rehearsal source apply --confirm-source-access=<full-sha256>
143
+ npx rehearsal refresh
144
+ npx rehearsal refresh --confirm-refresh=<full-sha256>
145
+ npx rehearsal source retire
146
+ npx rehearsal source retire --confirm-source-retirement=<full-sha256>
147
+ ```
148
+
149
+ `source apply` creates new time-limited roles and export views only when every exact name
150
+ is unused. It verifies the reader cannot read raw tables, write, escalate roles, or call
151
+ an exposed security-definer network function. Externally provisioned readers are not yet
152
+ supported; use the managed reader so Rehearsal can prove its scope and retirement.
153
+
154
+ `refresh` previews the complete replacement first. After exact confirmation, its baseline
155
+ step uses one read-only repeatable-read transaction for the schema shape,
156
+ migration ledger, and rows. It streams in bounded batches, records only counts and
157
+ hashes, stages privately, rechecks schema/ledger drift, and activates atomically. It then
158
+ resets the local runtime stack and applies configured baseline retention. A failed new
159
+ runtime is rolled back to the previous baseline and runtime. The lower-level `baseline
160
+ refresh` command remains available when automation should activate a baseline without
161
+ resetting the runtime or pruning old generations.
162
+
163
+ Storage cannot share PostgreSQL's transaction snapshot. Rehearsal instead verifies each
164
+ object's inventory version and byte count during transfer, then records its SHA-256 in
165
+ the immutable baseline.
166
+
167
+ `source retire` inventories the exact recorded views before removal, then removes only
168
+ those views, the two recorded roles, and local credential/receipt files. Unrelated roles,
169
+ grants, objects, baselines, runtimes, and Docker resources are preserved.
170
+
171
+ ## Limits
172
+
173
+ Rehearsal does not decide consent, licensing, retention rights, privileged-role meaning,
174
+ or which owner is yours. It does not provide an OS firewall, backup, disaster recovery,
175
+ or universal database support. Real Google account selection and provider callbacks
176
+ still require direct human observation; a synthetic redirect cannot prove them.