Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
f839aee
G5A real POST: stable provider operating identity across wider source…
HKcode22 Nov 3, 2026
a562935
Regression: G5A stable provider identity persists when late retime ex…
HKcode22 Nov 3, 2026
07426f4
Stamp exact reserved G5A POST ledger UUID into reconstructed FIDS ori…
HKcode22 Nov 3, 2026
4fd48d1
G5A POST: one exact baseline REST attempt ledger SELECT/INSERT role g…
HKcode22 Nov 3, 2026
5213199
Check PostgreSQL PUBLIC ledger privilege through ACL grantee zero, no…
HKcode22 Nov 3, 2026
da62e47
G5A real prospective WSSS POST: 3 irrevocable 2-unit source reservati…
HKcode22 Nov 3, 2026
39b0e73
Allow measured missed earlier POST slots while refusing repeated/fore…
HKcode22 Nov 3, 2026
66b3feb
Expose genuine G5A POST PG16 reservation boundary for disposable ledg…
HKcode22 Nov 3, 2026
36c65af
Schedule real 2026 WSSS 3×2-unit GitHub POST FIDS source with frozen …
HKcode22 Nov 3, 2026
6257efa
Test G5A POST stable retime identity across 4h source frame, immutabl…
HKcode22 Nov 3, 2026
f0aef27
PG16 test of exact three POST ledger reservations after source spend,…
HKcode22 Nov 3, 2026
af96328
Keep PG16 test cohort-budget inserts privileged, mirror restricted re…
HKcode22 Nov 3, 2026
784eb8c
Test real G5A POST exactly-scoped grant and 24-unit durable ledger on…
HKcode22 Nov 3, 2026
9e358c7
Use actual Plan f.8 pinned OpenAPI document SHA-256, not protocol mar…
HKcode22 Nov 3, 2026
49a76e7
Isolated PG16 POST test role: allow existing source readback tables a…
HKcode22 Nov 3, 2026
fe3597c
Checkpoint real 3×2-unit WSSS G5A POST sources, immutable budget ledg…
HKcode22 Nov 3, 2026
bd523a9
Fix disposable POST PG16 fixture: each manifest has unique cohort ID …
HKcode22 Nov 3, 2026
4e6b444
Match unique manifest and cohort IDs in real disposable PG16 POST res…
HKcode22 Nov 3, 2026
5842155
Fix isolated PG16 runtime role fixture: permit clean schema USAGE for…
HKcode22 Nov 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions .github/workflows/phase4-gate5-g5a-post-disposable-pg16.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
name: Phase4 Gate5 G5A POST Ledger Disposable PG16
on:
pull_request:
branches: [main]
paths:
- ".github/workflows/phase4-gate5-g5a-post-disposable-pg16.yml"
- "scripts/v39_phase4_gate5_g5a_prospective_post_schedule_observation.ts"
- "scripts/v39_phase4_gate5_g5a_post_ledger_exact_grant_once.ts"
- "tests/phase4_gate5_g5a_post_ledger_pg16.test.ts"
push:
branches: [main]
paths:
- ".github/workflows/phase4-gate5-g5a-post-disposable-pg16.yml"
- "scripts/v39_phase4_gate5_g5a_prospective_post_schedule_observation.ts"
- "scripts/v39_phase4_gate5_g5a_post_ledger_exact_grant_once.ts"
- "tests/phase4_gate5_g5a_post_ledger_pg16.test.ts"
permissions:
contents: read
env:
ADB_AUTO_COLLECT: "0"
V39_PHASE6_PROCESS_ARMED: "0"
AERODATABOX_API_KEY: ""
DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/v39_ci?sslmode=disable"
V39_DATABASE_RUNTIME_URL: "postgresql://g5_ci_runtime:g5_disposable_only@localhost:5432/v39_ci?sslmode=disable"
G5A_POST_TEST_WRITER_URL: "postgresql://p4_g5_g5a_owner_20261103:g5_post_disposable_only@localhost:5432/v39_ci?sslmode=disable"
G5A_POST_TEST_PG16: "1"
jobs:
post-ledger-pg16:
runs-on: ubuntu-latest
timeout-minutes: 12
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: v39_ci
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres -d v39_ci"
--health-interval 5s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
- run: npm ci --include=dev --no-audit --no-fund
- name: Boot only disposable PG16 baseline and staged V0076
run: |
set -Eeuo pipefail
node --import tsx scripts/apply_boot_migrations_v39.ts
psql "$DATABASE_URL" -X -v ON_ERROR_STOP=1 -f migrations/staged/V0076__phase4_gate5_logged_physical_fids_attempt_owner_v39.sql >/dev/null
- name: Prepare only disposable non-admin source writer and restricted app role
run: |
set -Eeuo pipefail
psql "$DATABASE_URL" -X -v ON_ERROR_STOP=1 <<'SQL'
CREATE ROLE g5_ci_runtime LOGIN PASSWORD 'g5_disposable_only';
GRANT USAGE ON SCHEMA clean TO g5_ci_runtime;
CREATE ROLE p4_g5_g5a_owner_20261103 LOGIN
NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS
PASSWORD 'g5_post_disposable_only';
GRANT USAGE ON SCHEMA clean TO p4_g5_g5a_owner_20261103;
GRANT SELECT,UPDATE ON TABLE clean.phase4_g5_fids_cohort_budget_v39
TO p4_g5_g5a_owner_20261103;
GRANT SELECT ON TABLE clean.fids_query_response,
clean.flight_population,clean.flight_snapshots
TO p4_g5_g5a_owner_20261103;
INSERT INTO clean.phase4_g5_fids_cohort_budget_v39
(manifest_sha256,cohort_id,project_unit_ceiling,reserved_units)
VALUES
(repeat('a',64),'WSSS_G5A_20261105_0200Z',24,18),
(repeat('b',64),'WSSS_G5A_20261105_0200Z_N',24,18),
(repeat('c',64),'WSSS_G5A_20261105_0200Z_K',24,24);
SQL
- name: Test actual one-time baseline attempt ledger GRANT (no other tables)
run: |
set -Eeuo pipefail
set +x
GITHUB_ACTIONS=false \
P4_G5_G5A_POST_GRANT_INTENT=EXACT_G5A_POST_IMMUTABLE_LEDGER_INSERT_SELECT_NO_OTHER_PRIVILEGES \
node --import tsx scripts/v39_phase4_gate5_g5a_post_ledger_exact_grant_once.ts
- name: Verify real immutable POST reservation, 24-unit cap and replay failure
run: |
set -Eeuo pipefail
npx vitest run tests/phase4_gate5_g5a_post_ledger_pg16.test.ts
echo 'POST_PROVIDER_CALLS=0'
echo 'PRODUCTION_DATABASE_WRITES=0'
echo 'GITHUB_PROVIDER_SECRETS_AVAILABLE=FALSE'
83 changes: 83 additions & 0 deletions .github/workflows/phase4-gate5-g5a-wsss-real-post.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: Phase4 Gate5 G5A WSSS Real Prospective POST
on:
pull_request:
branches: [main]
paths:
- ".github/workflows/phase4-gate5-g5a-wsss-real-post.yml"
- "scripts/v39_phase4_gate5_g5a_prospective_post_schedule_observation.ts"
- "scripts/v39_phase4_gate5_g5a_post_ledger_exact_grant_once.ts"
- "server/lib/disruption/fidsCensus_v3.ts"
- "tests/phase4_gate5_g5a_post_source_v39.test.ts"
push:
branches: [main]
paths:
- ".github/workflows/phase4-gate5-g5a-wsss-real-post.yml"
- "scripts/v39_phase4_gate5_g5a_prospective_post_schedule_observation.ts"
- "scripts/v39_phase4_gate5_g5a_post_ledger_exact_grant_once.ts"
- "server/lib/disruption/fidsCensus_v3.ts"
- "tests/phase4_gate5_g5a_post_source_v39.test.ts"
schedule:
# Actual UTC date must be 2026-11-05; code refuses replay in future years
- cron: "10 2 5 11 *"
permissions:
contents: read
actions: read
concurrency:
group: gate5-g5a-wsss-20261105-post-real
cancel-in-progress: false
jobs:
offline-post:
if: ${{ github.event_name == 'pull_request' || github.event_name == 'push' }}
runs-on: ubuntu-latest
timeout-minutes: 9
env:
AERODATABOX_API_KEY: ""
P4_G5_SOURCE_OWNER_DATABASE_URL: ""
V39_DATABASE_RUNTIME_URL: ""
DATABASE_URL: ""
GATE05_AUTOMATION_DATABASE_URL: ""
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
- run: npm ci --include=dev --no-audit --no-fund
- name: Frozen G5A POST and source reservation guard tests, no provider
run: |
set -Eeuo pipefail
npx vitest run tests/phase4_gate5_g5a_post_source_v39.test.ts
echo 'PROVIDER_CALLS=0 DATABASE_CONTENT_WRITES=0 PAID_DISPATCH_DISABLED_ON_PR_PUSH'
post-source:
name: post-source
if: ${{ github.event_name == 'schedule' && github.event.schedule == '10 2 5 11 *' }}
runs-on: ubuntu-latest
timeout-minutes: 240
environment: phase2g-paid
env:
ADB_AUTO_COLLECT: "0"
V39_PHASE6_PROCESS_ARMED: "0"
G5A_POST_SCHEDULE: "10 2 5 11 *"
G5A_POST_PAID_INTENT: G5A_NOV05_POST_THREE_2_UNIT_REQUESTS_MAX
AERODATABOX_API_KEY: ${{ secrets.AERODATABOX_API_KEY }}
P4_G5_SOURCE_OWNER_DATABASE_URL: ${{ secrets.P4_G5_SOURCE_OWNER_DATABASE_URL }}
V39_DATABASE_RUNTIME_URL: ${{ secrets.P4_G5_SOURCE_OWNER_DATABASE_URL }}
GITHUB_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
- run: npm ci --include=dev --no-audit --no-fund
- name: Actual GitHub scheduled 3× bounded POST originals and T+2h label counts
run: |
set -Eeuo pipefail
set +x
test -z "${DATABASE_URL:-}${GATE05_AUTOMATION_DATABASE_URL:-}${RAPIDAPI_KEY:-}"
test "$(git rev-parse HEAD)" = "${GITHUB_SHA}"
node --import tsx scripts/v39_phase4_gate5_g5a_prospective_post_schedule_observation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Gate 5 G5A — separate real POST observation and provider-schedule revision label

**Engineering checkpoint, 2026-11-03.** The binding owner's direction is rapid scientific measurement, not repeated vendor email/runway investigations. See first two links in Phase4 README. **This checkpoint does NOT declare source collection, actual POST, scientific PASS, or Phase5/Phase6 authorized.**

The 2026-11-05 WSSS source cohort (main-merged #372) has 9 prospective PRE source slots at T−24h/T−6h/T−90m, 2 REST units/slot, 18-unit ceiling under **one 24-unit project cap**. This POST extension uses the remaining **maximum 6 units**, 3 one-attempt prospective FIDS GETs. It reobserves provider schedule changes and never calls them actual departure or runway delay. It does not add new DDL, and does not reinstall any phase schema.

**Frozen POST source plan**: UTC 2026-11-05 **03:40, 04:10, 04:40**, corresponding to Nov4 **7:40, 8:10, 8:40 PM Pacific**. Source range WSSS UTC Nov5 **01:00–05:00** (Singapore local Nov5 09:00–13:00) is **four hours**, wider than the first one-hour cohort because retimed flights can move out of the original hour. This increases bias/coverage uncertainty but avoids conflating an absent row with an on-time flight. Frozen label watermark per physical flight: `W=first_native_schedule_T+2h`. Post-source availability must be prospectively recorded `A_post<=W` to count; source absent or after W is **UNKNOWN**. The provider's native ID + confirmed operating flight and route, **not mutable schedule or query window**, join reobservations.

**GitHub-only prearm**: `Phase4 Gate5 G5A WSSS Real Prospective POST` scheduled 2026-11-05 **02:10 UTC** (Nov4 6:10pm Pacific), then sources above; result audit after 2026-11-05 **05:01 UTC** (Nov4 9:01pm Pacific). If GH schedule starts late, it must hold or mark missed slots, not retroactively make a response available before W. No PR/push manual/Cloudflare/Replit paid path.

**Immutable budget accounting**: before *each* physical GET, PostgreSQL SERIALIZABLE transaction locks the existing `phase4_g5_fids_cohort_budget_v39` row, verifies frozen manifest 24-unit ceiling and sufficient balance, atomically increases its reserved-unit count by 2 and writes deterministic unique UUID to existing B0062 `clean.adb_rest_attempt_ledger` category `g5a_post_schedule_fids`, then **commits before GET**. Failed/ambiguous HTTP is never refunded/replayed. A failed earlier slot is **UNOBSERVED**, later POST can still proceed; no backfill. POST original decoded source, normalized rows and source hash are persisted via the reviewed `fidsCensus_v3.ts` path, with this exact reservation UUID included in its canonical reconstructed source envelope and batch ID. No source Content/flight ID printed in Actions.

**One extra exact-privilege owner action, no extra secret**: the existing restricted source role `p4_g5_g5a_owner_20261103` was created successfully using #371. To use the existing baseline POST attempt ledger, **only** `GRANT SELECT, INSERT ON clean.adb_rest_attempt_ledger` is required. Reviewed one-time no-provider installer `scripts/v39_phase4_gate5_g5a_post_ledger_exact_grant_once.ts` is tested with disposable PG16, preserves existing no-DELETE/no-DDL and checks PUBLIC has no INSERT. It does not change the GitHub environment secret or the runtime role. Run exactly once only after reviewed PR merge and hash pin, never run source schema migrations again.

**Measured outcome**: at W+1min, aggregate PRE snapshot source baseline and the latest qualified persisted POST observation as of W, by `horizon`: number of persisted PRE candidates, valid baseline, valid post, observed schedule revisions of absolute ≥15min, observed changes below threshold, **unknown/no qualified post**. No negative label is inferred from a missing reobservation. The audit uses fixed cohort manifest hash, source query UUID, immutable post reservation UUID and server `available_at`, stable physical ID, and exact 2h clock watermark. This is a **reported schedule-revision classification** with coverage/selection bias, not original strict actual wheels-off target.

**Independent post-measurement work**: source+PRE audit from independent reader, callback inside/outside/unresolved, AIRBORNE coverage, source Content 23h/24h retention cleanup and actual billed units still require verification. The original strict runway-defined Gate5 remains HOLD, and G5A PASS_WITH_MEASURED_LIMITATIONS requires real independent measured evidence and a separately reviewed scientific verdict; do not infer it from CI or schedule existence.

**OpenAPI source provenance**: use the actual Plan f.8 §5.1 pinned v1.15.3.0 document SHA `735620f2d2132c5bf51768f50caa767b7f0b25be8b128679641402666696890a` explicitly as historical documentation, *not* G5A protocol Markdown SHA or an unverified live provider schema version; source owner equivalent repair in #373.
115 changes: 115 additions & 0 deletions scripts/v39_phase4_gate5_g5a_post_ledger_exact_grant_once.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/**
* Optional one-time *metadata permission only* for the 3 G5A POST FIDS GETs.
* No provider HTTP, role creation, flight Content, new schema, or secret read.
* The source role already exists from merged #371, approved by the owner.
*/
import pg from "pg";
import {execFileSync} from "node:child_process";
const ROLE="p4_g5_g5a_owner_20261103";
const TABLE="clean.adb_rest_attempt_ledger";
const INTENT="EXACT_G5A_POST_IMMUTABLE_LEDGER_INSERT_SELECT_NO_OTHER_PRIVILEGES";
const SHA=/^[a-f0-9]{40}$/;
function hold(msg:string):never{throw Error("P4_G5_G5A_POST_GRANT_"+msg+"_HOLD")}
export async function main(){
const e=process.env;
if(e.P4_G5_G5A_POST_GRANT_INTENT!==INTENT||
!e.DATABASE_URL||!e.V39_DATABASE_RUNTIME_URL||
e.DATABASE_URL===e.V39_DATABASE_RUNTIME_URL||
e.ADB_AUTO_COLLECT!=="0"||e.V39_PHASE6_PROCESS_ARMED!=="0"||
e.GITHUB_ACTIONS==="true")
hold("OPERATOR_INTENT_OR_DB_URL");
const commit=execFileSync("git",["rev-parse","HEAD"],
{encoding:"utf8",timeout:4000}).trim();
if(!SHA.test(commit))hold("SOURCE_PIN");
const admin=new pg.Client({connectionString:e.DATABASE_URL,
connectionTimeoutMillis:8500,query_timeout:12000,
application_name:"g5a_post_ledger_exact_grant_once"});
const runtime=new pg.Client({connectionString:e.V39_DATABASE_RUNTIME_URL,
connectionTimeoutMillis:8500,query_timeout:12000,
application_name:"g5a_post_ledger_runtime_restricted_ro"});
await admin.connect();await runtime.connect();
try{
const [a,w]=await Promise.all([
admin.query(`SELECT current_database() AS db,current_user AS role,
current_setting('server_version_num')::int>=160000 AS pg16,
(SELECT rolsuper OR rolcreaterole FROM pg_roles WHERE rolname=current_user) AS can_grant`),
runtime.query(`SELECT current_database() AS db,current_user AS role,
has_table_privilege(current_user,$1,'DELETE') AS can_delete_source`,[TABLE])
]);
const ar=a.rows[0],wr=w.rows[0];
if(a.rows.length!==1||w.rows.length!==1||
ar.pg16!==true||ar.can_grant!==true||
ar.db!==wr.db||ar.role===wr.role)
hold("ROLE_SEPARATION_OR_PG16");
const target=await admin.query(`SELECT COUNT(*)::int n FROM pg_roles
WHERE rolname=$1 AND NOT rolsuper AND NOT rolcreatedb
AND NOT rolcreaterole AND NOT rolreplication AND NOT rolbypassrls`,[ROLE]);
if(Number(target.rows[0]?.n)!==1)hold("SOURCE_OWNER_MISSING_OR_PRIVILEGED");
const rel=await admin.query("SELECT to_regclass($1::text) AS found",[TABLE]);
if(rel.rows.length!==1||!rel.rows[0].found)hold("BASELINE_LEDGER_NOT_PRESENT");
const old=await admin.query(`SELECT
has_table_privilege($1,$2,'SELECT') can_select,
has_table_privilege($1,$2,'INSERT') can_insert,
has_table_privilege($1,$2,'UPDATE') can_update,
has_table_privilege($1,$2,'DELETE') can_delete,
has_table_privilege($1,$2,'TRUNCATE') can_truncate,
has_table_privilege($1,$2,'REFERENCES') can_ref,
has_table_privilege($1,$2,'TRIGGER') can_trigger`,[ROLE,TABLE]);
if(old.rows.length!==1)hold("ORIGINAL_TABLE_ACL_UNVERIFIABLE");
const prior=old.rows[0];
if(prior.can_update||prior.can_delete||prior.can_truncate||prior.can_ref||prior.can_trigger)
hold("UNEXPECTED_EXISTING_DANGEROUS_GRANTS");
let changed=false;
if(!(prior.can_select&&prior.can_insert)){
await admin.query("BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE READ WRITE");
let tx=true;
try{
await admin.query("SET LOCAL statement_timeout='10000ms'");
await admin.query("SET LOCAL lock_timeout='1500ms'");
const lock=await admin.query("SELECT pg_try_advisory_xact_lock(76,97) AS ok");
if(lock.rows[0]?.ok!==true)hold("CONCURRENT_GRANT");
await admin.query("GRANT SELECT,INSERT ON TABLE "+TABLE+" TO "+ROLE);
await admin.query("COMMIT");tx=false;changed=true;
}finally{if(tx)await admin.query("ROLLBACK").catch(()=>undefined)}
}
const post=await admin.query(`SELECT
has_table_privilege($1,$2,'SELECT') s,
has_table_privilege($1,$2,'INSERT') i,
has_table_privilege($1,$2,'UPDATE') u,
has_table_privilege($1,$2,'DELETE') d,
has_table_privilege($1,$2,'TRUNCATE') t,
has_table_privilege($1,$2,'REFERENCES') r,
has_table_privilege($1,$2,'TRIGGER') g`,[ROLE,TABLE]);
const x=post.rows[0];
if(post.rows.length!==1||!x.s||!x.i||x.u||x.d||x.t||x.r||x.g)
hold("POSTCOMMIT_TABLE_ACL");
const pub=await admin.query(`SELECT EXISTS(
SELECT 1 FROM pg_class c
JOIN pg_namespace n ON n.oid=c.relnamespace
CROSS JOIN LATERAL aclexplode(
COALESCE(c.relacl,acldefault('r',c.relowner))) p
WHERE n.nspname='clean' AND c.relname='adb_rest_attempt_ledger'
AND p.grantee=0 AND p.privilege_type='INSERT'
) AS public_insert`);
if(pub.rows[0]?.public_insert===true)hold("PUBLIC_INSERT_ALREADY_ALLOWED");
console.log(JSON.stringify({
status:changed?
"G5A_POST_BASELINE_LEDGER_EXACT_SELECT_INSERT_GRANTED_ONCE":
"G5A_POST_BASELINE_LEDGER_GRANT_ALREADY_PRESENT_NO_REINSTALL",
sourceRoleNonAdmin:true,sourceRoleNoDelete:true,
sourceRoleNoSchemaDdlGranted:true,
publicInsertNotEnabled:true,providerCalls:0,
databaseContentWrites:0,phase5FreezeAuthorized:false
}));
}finally{
await runtime.end().catch(()=>undefined);
await admin.end().catch(()=>undefined);
}
}
if(process.argv[1]?.endsWith("v39_phase4_gate5_g5a_post_ledger_exact_grant_once.ts"))
void main().catch(e=>{
const msg=e instanceof Error?e.message:"";
console.error(/^P4_G5_G5A_POST_GRANT_[A-Z0-9_]+_HOLD$/.test(msg)?
msg:"P4_G5_G5A_POST_GRANT_UNKNOWN_NO_SECRETS_HOLD");
process.exitCode=2;
});
Loading
Loading