Skip to content

Commit 26a8355

Browse files
wip v28
1 parent 9d2edfa commit 26a8355

9 files changed

Lines changed: 98 additions & 18 deletions

BITCODE_SPEC_V28_NOTES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ This recalibration means the QA document, parity matrix, and implementation work
6666

6767
Supabase/PostgreSQL data-health checks are part of the V28 acceptance apparatus, not a separate operator convenience. The ORM package now owns reusable schema, identity, Terminal, ledger, and operational check manifests plus live runners for daily staging/production validation, CI E2E validation, local QA reports, and generated schema-type coverage. These checks must preserve the core boundary: Supabase rows are ledger-derived or Bitcode-canonical projections, while ledger anchors, signed wallet proofs, Terminal journal receipts, and canonical receipts remain the source of cryptographic truth.
6868

69+
May 14 staging-testnet verification added the first repository-owned RLS repairs after the dashboard-origin RLS bootstrap. `20260514173000_enable_pipeline_runs_rls.sql` enables RLS on `public.pipeline_runs`, and `20260514175000_enable_pipeline_runtime_rls.sql` enables RLS on server-managed pipeline runtime tables reported by Supabase Security Advisor. These preserve existing service-role pipeline posture and move runtime internals to deny-by-default for browser roles unless a narrower policy is later specified. The live daily data-health suite now passes 24/24 checks against the staging Supabase project, live ORM E2E tests can load `.env.local` directly for local QA parity with the CLI runner, and the advisory-style RLS probe returns no public tables with policies/browser grants while RLS is disabled.
70+
6971
### Deterministic Model Boundary
7072

7173
V28 must remove the idea that a user can choose ledgerized Bitcode synthesis models.

BITCODE_SPEC_V28_PARITY_MATRIX.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ It links manual screenshots, console logs, server logs, Supabase SQL checks, and
113113
| --- | --- | --- | --- |
114114
| BTC/D identity and wallet-backed session | `uapi/app/api/wallet/_shared.ts`, `uapi/app/api/wallet/authenticate/route.ts`, `uapi/app/api/wallet/oauth/authorization-code/route.ts`, `uapi/app/api/wallet/oauth/token/route.ts`, `uapi/app/api/wallet/oauth/userinfo/route.ts`, `uapi/lib/bitcoin-wallet-client.ts`, `uapi/lib/bitcode-wallet-local.ts`, `packages/btd/src/wallet.ts`, `packages/btd/src/bitcoin-provider.ts`, `supabase/migrations/003_user_connections_provider_scope.sql`, `uapi/tests/bitcoinWalletClient.test.ts` | partial | Live staging-testnet wallet connect with Xverse or Leather, signed challenge proof, top-chrome identity hydration, Wallet pane provider/address/balance readout, Supabase auth/session projection, sign-out clearing, and SQL evidence in `auth.users`, `user_connections`, and `user_profiles`. Leather parity additionally requires documented `getAddresses`, `open`, `signMessage`, hex `signPsbt`, and `sendTransfer` request shapes to stay covered by tests before Terminal BTC fee usage depends on them. |
115115
| GitHub App and repository source scope | `uapi/app/api/vcs/_shared.ts`, `uapi/app/api/vcs/[provider]/callback/route.ts`, `uapi/app/api/vcs/[provider]/setup/route.ts`, `uapi/app/api/vcs/[provider]/repositories/route.ts`, `packages/api/src/vcs/github-service.ts`, Auxillaries Externals pane, `supabase/migrations/001_v26_production.sql` `user_connections` and `vcs_repositories` | partial | GitHub App install/callback returns to Externals, installation/user state is stored under provider-scoped connection data, repositories appear for Give/Need source scope, and SQL evidence confirms `user_connections.provider='github'` plus `vcs_repositories` rows. |
116-
| PSQL/Supabase data reality | `supabase/migrations/001_v26_production.sql`, `002_v27_btd_crypto_registry.sql`, `003_user_connections_provider_scope.sql`, `packages/orm/src/data-health/*`, `packages/orm/scripts/run-data-health.ts`, `packages/orm/scripts/check-schema-types.ts`, `supabase/DATA_HEALTH.md`, `supabase/queries/*` | partial | Staging database has all required auth/profile/connection/repository/BTD registry/journal/telemetry tables, RLS posture does not hide required user-scoped reads, generated schema types cover canonical public tables, automated data-health checks pass, and QA SQL queries match Terminal/Wallet/Externals UI state. |
116+
| PSQL/Supabase data reality | `supabase/migrations/001_v26_production.sql`, `002_v27_btd_crypto_registry.sql`, `003_user_connections_provider_scope.sql`, `20260514173000_enable_pipeline_runs_rls.sql`, `20260514175000_enable_pipeline_runtime_rls.sql`, `packages/orm/src/data-health/*`, `packages/orm/scripts/run-data-health.ts`, `packages/orm/scripts/check-schema-types.ts`, `supabase/DATA_HEALTH.md`, `supabase/queries/*` | baseline pass; first-run QA evidence still pending | Staging database has all required auth/profile/connection/repository/BTD registry/journal/telemetry tables, RLS posture does not hide required user-scoped reads, generated schema types cover canonical public tables, automated data-health checks pass, and QA SQL queries match Terminal/Wallet/Externals UI state. Current baseline: `pnpm db:data-health:daily` passes 24/24 against staging, live data-health/schema E2E passes with `.env.local` loading, and direct advisory-style SQL returns zero public tables with policies/browser grants while RLS is disabled. |
117117
| Fit-finding | `uapi/app/terminal/TerminalGiveNeedWorkbench.tsx`, `TerminalNeedScenarioPanel.tsx`, `terminal-give-need-workbench.ts`, `terminal-need-scenarios.ts`, `packages/protocol/src/canonical/*`, `protocol-demonstration/src/*` reference witness | partial | Terminal simplest Need produces or reads Fit candidates, review decision, qualities, rejection/block reasons, source roots, proof/dedupe roots, and visible readiness state without relying on demonstration runtime imports. |
118118
| AssetPack synthesis and deterministic pipeline configuration | `internal-docs/ASSETPACK_EXECUTION.md`, `packages/protocol/src/canonical/run-artifacts.js`, `packages/btd/src/semantic-volume.ts`, `measuremint.ts`, `range.ts`, `receipts.ts`, `replay.ts`, `uapi/app/api/btd/mint-draft/route.ts`, Terminal AssetPack components | partial with blocker | Staging Need/Fit path creates or reads AssetPack evidence, semantic volume, measuremint/range or zero-cell receipt, and access-policy hash using protocol-specified model/pipeline configuration. Any broad user model-selection UI that can affect ledgerized synthesis must be removed or scoped to non-ledgerized conversation UX. |
119119
| Ledgerized journal and ledger anchors | `packages/btd/src/terminal-journal.ts`, `ledger-anchor.ts`, `reconciliation.ts`, `uapi/app/api/btd/terminal-journal/route.ts`, `asset-pack-ledger-anchor/route.ts`, `ledger-database-reconciliation/route.ts`, `supabase/migrations/002_v27_btd_crypto_registry.sql` | partial | Terminal shows journal rows for Need/Fit/AssetPack/BTC fee/anchor/reconciliation events, ledger anchor or blocked-readiness state is explicit, and SQL evidence in `btd_terminal_journal_entries`, `btd_asset_pack_ledger_anchors`, and reconciliation repair tables matches the UI. |

BITCODE_V28_QA.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -812,10 +812,12 @@ Automated checks passed:
812812
- `pnpm -C packages/protocol run typecheck`: pass.
813813
- `pnpm -C packages/orm test`: 19 passed, with live data-health E2E tests skipped unless enabled by env flags.
814814
- `pnpm -C packages/orm run test:data-health`: data-health contract tests passed; live DB and schema-type E2E tests are gated by env flags.
815+
- `BITCODE_RUN_DB_HEALTH_E2E=true BITCODE_RUN_SCHEMA_TYPES_E2E=true pnpm -C packages/orm run test:data-health:live`: 6 passed against the staging-testnet Supabase project.
815816
- `pnpm -C packages/orm run schema-types:check`: generated Supabase and ORM database types cover canonical public tables.
816817
- `pnpm -C packages/orm run build`: pass after generated type refresh.
817818
- `pnpm -C uapi run build` with the staging-testnet env block: Next.js production build passed.
818819
- `git diff --check`: pass.
820+
- Supabase Security Advisor RLS class probe: direct SQL returned zero public tables with policies or browser-role grants while RLS is disabled.
819821
820822
Build warnings and interpretation:
821823
@@ -825,8 +827,9 @@ Build warnings and interpretation:
825827
826828
External Supabase readiness check:
827829
828-
The staging Supabase migration history now contains the required V28 tables from local migrations `001`, `002`, and `003`, followed by dashboard-origin RLS migration `20260510223914`.
829-
`supabase db push --dry-run` reports the remote database is up to date.
830+
The staging Supabase migration history now contains the required V28 tables from local migrations `001`, `002`, and `003`, followed by dashboard-origin RLS migration `20260510223914` and repository RLS migrations `20260514173000_enable_pipeline_runs_rls.sql` and `20260514175000_enable_pipeline_runtime_rls.sql`.
831+
`scripts/supabase.sh migration list` reports local and remote migration history aligned.
832+
The added repository migrations enable RLS on `public.pipeline_runs`, `public.run_jobs`, `public.stream_logs`, and server-managed `public.deliverable_pipeline_*` runtime internals, closing the live data-health finding and the Supabase Security Advisor criticals shown during QA.
830833
831834
Data-health tooling added for repeatable Supabase/PostgreSQL validation:
832835
@@ -838,19 +841,17 @@ Data-health tooling added for repeatable Supabase/PostgreSQL validation:
838841
839842
Required next validation before live onboarding QA:
840843
841-
1. Run `SUPABASE_DB_URL='<postgres-connection-string>' pnpm db:data-health:daily` against staging-testnet.
842-
2. Run saved Supabase queries from `supabase/queries/` and paste result excerpts into this QA log.
843-
3. Run `pnpm db:schema-types:check` after generated Supabase types are refreshed from the staging database.
844-
4. Rebuild/redeploy if Vercel env changed after the build.
845-
5. Re-run Pass 1A from a fresh browser profile.
844+
1. Run saved Supabase queries from `supabase/queries/` and paste result excerpts into this QA log during first-run onboarding.
845+
2. Rebuild/redeploy if Vercel env changed after the build.
846+
3. Re-run Pass 1A from a fresh browser profile on `bitcode.exchange`.
846847
847848
Deployment judgment:
848849
849850
- Code/build readiness: pass.
850851
- Wallet/OAuth/GitHub source readiness in code: pass.
851852
- Formal protocol and ORM migration source readiness: pass.
852-
- Live staging data-plane readiness: migrations applied; pending saved-query verification and first-run onboarding QA.
853-
- Manual first-run onboarding may proceed after deployment env is confirmed and saved-query verification is captured.
853+
- Live staging data-plane readiness: pass baseline. `pnpm db:data-health:daily` checked 24 and passed 24 against `tkpyosihuouusyaxtbau`; the advisor-style RLS probe returned zero rows; saved-query verification still belongs in the first-run onboarding QA evidence.
854+
- Manual first-run onboarding may proceed after deployment env is confirmed; capture saved-query evidence during the pass.
854855
855856
## Issue Template
856857

packages/orm/scripts/run-data-health.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
} from '../src/data-health/checks';
99
import {
1010
createDataHealthClient,
11+
loadDataHealthEnvFiles,
1112
readDataHealthConnectionInfo,
1213
redactConnectionString,
1314
resolveDataHealthConnectionString,
@@ -34,6 +35,7 @@ const DEFAULT_OPTIONS: CliOptions = {
3435
};
3536

3637
async function main() {
38+
loadDataHealthEnvFiles();
3739
const options = parseArgs(process.argv.slice(2));
3840

3941
if (options.list) {

packages/orm/src/__tests__/data-health.e2e.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
createDataHealthClient,
3+
loadDataHealthEnvFiles,
34
resolveDataHealthConnectionString,
45
runDataHealthChecks,
56
} from '../data-health/runner';
@@ -9,6 +10,7 @@ const maybeDescribe =
910

1011
maybeDescribe('Supabase data-health live E2E', () => {
1112
it('runs the CI health suite against the configured database', async () => {
13+
loadDataHealthEnvFiles();
1214
const connectionString = resolveDataHealthConnectionString();
1315
expect(connectionString).toBeTruthy();
1416

packages/orm/src/data-health/checks.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,19 @@ export const CANONICAL_APPLICATION_TABLES = [
3434
'vcs_repositories',
3535
'notifications',
3636
'pipeline_runs',
37+
'run_jobs',
38+
'stream_logs',
3739
'deliverables',
3840
'deliverable_vectors',
41+
'deliverable_pipeline_runs',
42+
'deliverable_pipeline_events',
43+
'deliverable_pipeline_generated_assets',
44+
'deliverable_pipeline_phase_delegations',
45+
'deliverable_pipeline_agent_steps',
46+
'deliverable_pipeline_generations',
47+
'deliverable_pipeline_otf_instructions',
48+
'deliverable_pipeline_substeps',
49+
'deliverable_pipeline_tool_executions',
3950
'error_logs',
4051
'events',
4152
] as const;
@@ -607,7 +618,7 @@ export const DATA_HEALTH_CHECKS: DataHealthCheckDefinition[] = [
607618
count(*)::bigint AS range_count
608619
FROM public.btd_asset_pack_ranges
609620
),
610-
overlaps AS (
621+
range_overlaps AS (
611622
SELECT a.asset_pack_id AS left_asset_pack_id, b.asset_pack_id AS right_asset_pack_id
612623
FROM public.btd_asset_pack_ranges a
613624
JOIN public.btd_asset_pack_ranges b ON a.id < b.id
@@ -626,10 +637,10 @@ export const DATA_HEALTH_CHECKS: DataHealthCheckDefinition[] = [
626637
SELECT
627638
coalesce((SELECT total_minted FROM state), -1) = coalesce((SELECT summed_token_count FROM range_stats), 0)
628639
AND coalesce((SELECT next_token_id FROM state), -1) = coalesce((SELECT max_range_end FROM range_stats), 0)
629-
AND (SELECT count(*) FROM overlaps) = 0
640+
AND (SELECT count(*) FROM range_overlaps) = 0
630641
AND (SELECT count(*) FROM invalid_ranges) = 0 AS ok,
631642
(
632-
(SELECT count(*) FROM overlaps)
643+
(SELECT count(*) FROM range_overlaps)
633644
+ (SELECT count(*) FROM invalid_ranges)
634645
+ CASE
635646
WHEN coalesce((SELECT total_minted FROM state), -1) <> coalesce((SELECT summed_token_count FROM range_stats), 0)
@@ -641,7 +652,7 @@ export const DATA_HEALTH_CHECKS: DataHealthCheckDefinition[] = [
641652
'state_total_minted', (SELECT total_minted FROM state),
642653
'state_next_token_id', (SELECT next_token_id FROM state),
643654
'range_stats', (SELECT to_jsonb(range_stats) FROM range_stats),
644-
'overlaps', coalesce((SELECT jsonb_agg(to_jsonb(overlaps)) FROM overlaps), '[]'::jsonb),
655+
'overlaps', coalesce((SELECT jsonb_agg(to_jsonb(range_overlaps)) FROM range_overlaps), '[]'::jsonb),
645656
'invalid_ranges', coalesce((SELECT jsonb_agg(asset_pack_id ORDER BY asset_pack_id) FROM invalid_ranges), '[]'::jsonb)
646657
) AS details;
647658
`,

packages/orm/src/data-health/runner.ts

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { existsSync, readFileSync } from 'fs';
2+
import path from 'path';
13
import { Client, type QueryResultRow } from 'pg';
24

35
import {
@@ -82,14 +84,27 @@ export function resolveDataHealthConnectionString(env: NodeJS.ProcessEnv = proce
8284
);
8385
}
8486

87+
export function loadDataHealthEnvFiles(cwd: string = process.cwd()): void {
88+
const repoRoot = path.resolve(__dirname, '../../../..');
89+
const candidates = [
90+
path.join(repoRoot, '.env.local'),
91+
path.join(repoRoot, 'uapi/.env.local'),
92+
path.join(cwd, '.env.local'),
93+
];
94+
95+
for (const filePath of candidates) {
96+
loadEnvFile(filePath);
97+
}
98+
}
99+
85100
export function redactConnectionString(connectionString: string): string {
86101
try {
87102
const url = new URL(connectionString);
88103
if (url.password) {
89-
url.password = '[redacted]';
104+
url.password = 'redacted';
90105
}
91106
if (url.username) {
92-
url.username = url.username ? '[redacted]' : '';
107+
url.username = url.username ? 'redacted' : '';
93108
}
94109
return url.toString();
95110
} catch {
@@ -98,9 +113,10 @@ export function redactConnectionString(connectionString: string): string {
98113
}
99114

100115
export async function createDataHealthClient(connectionString: string): Promise<Client> {
116+
const normalizedConnectionString = normalizePgConnectionString(connectionString);
101117
const client = new Client({
102-
connectionString,
103-
ssl: shouldUseSsl(connectionString) ? { rejectUnauthorized: false } : undefined,
118+
connectionString: normalizedConnectionString,
119+
ssl: shouldUseSsl(normalizedConnectionString) ? { rejectUnauthorized: false } : undefined,
104120
});
105121
await client.connect();
106122
return client;
@@ -233,6 +249,44 @@ function shouldUseSsl(connectionString: string): boolean {
233249
}
234250
}
235251

252+
function normalizePgConnectionString(connectionString: string): string {
253+
try {
254+
const url = new URL(connectionString);
255+
url.searchParams.delete('sslmode');
256+
return url.toString();
257+
} catch {
258+
return connectionString;
259+
}
260+
}
261+
262+
function loadEnvFile(filePath: string): void {
263+
if (!existsSync(filePath)) return;
264+
265+
for (const line of readFileSync(filePath, 'utf8').split(/\r?\n/)) {
266+
const trimmed = line.trim();
267+
if (!trimmed || trimmed.startsWith('#')) continue;
268+
269+
const match = trimmed.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
270+
if (!match) continue;
271+
272+
const key = match[1];
273+
if (process.env[key] !== undefined) continue;
274+
275+
process.env[key] = stripEnvQuotes(match[2]);
276+
}
277+
}
278+
279+
function stripEnvQuotes(value: string): string {
280+
const trimmed = value.trim();
281+
if (
282+
(trimmed.startsWith('"') && trimmed.endsWith('"')) ||
283+
(trimmed.startsWith("'") && trimmed.endsWith("'"))
284+
) {
285+
return trimmed.slice(1, -1);
286+
}
287+
return trimmed;
288+
}
289+
236290
async function inspectAvailableRelations(client: Queryable): Promise<Set<string>> {
237291
const result = await client.query<{
238292
relation_name: string;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE "public"."pipeline_runs" ENABLE ROW LEVEL SECURITY;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
ALTER TABLE IF EXISTS "public"."deliverable_pipeline_agent_steps" ENABLE ROW LEVEL SECURITY;
2+
ALTER TABLE IF EXISTS "public"."deliverable_pipeline_generations" ENABLE ROW LEVEL SECURITY;
3+
ALTER TABLE IF EXISTS "public"."deliverable_pipeline_otf_instructions" ENABLE ROW LEVEL SECURITY;
4+
ALTER TABLE IF EXISTS "public"."deliverable_pipeline_substeps" ENABLE ROW LEVEL SECURITY;
5+
ALTER TABLE IF EXISTS "public"."deliverable_pipeline_tool_executions" ENABLE ROW LEVEL SECURITY;
6+
ALTER TABLE IF EXISTS "public"."run_jobs" ENABLE ROW LEVEL SECURITY;
7+
ALTER TABLE IF EXISTS "public"."stream_logs" ENABLE ROW LEVEL SECURITY;

0 commit comments

Comments
 (0)