3.4 KiB
AwoooP RLS Canary Wave 1.3
This wave targets one outbound evidence table:
awooop_outbound_message
Status: applied in production on 2026-05-12.
Production state:
awooop_outbound_message:rls=true force=true policies=1- Operator Console Run detail smoke:
- run:
d385b7fe-8666-58ec-9072-9ac917adb6cf project_id=awoooi- HTTP 200
outbound_messages=1
- run:
Why This Table
awooop_outbound_message stores outbound notification evidence for Run
Timeline. It is less risky than awooop_run_state for this wave because it is
not the worker lease/state-machine source of truth.
Latest live evidence before staging:
project_id=awoooi rows=290
send_status=sent rows=290
null_project_id_rows=0
awooop_run_state remains blocked because it is used by worker lease,
state-machine transitions, approvals, and Operator Console list/detail paths.
It needs a separate query-path and cross-tenant Operator Console design pass.
Runtime Paths
Write paths:
TelegramGateway._mirror_outbound_message()opensget_db_context(project_id)and then callsrecord_outbound_message().ChannelHub._interim_feedback_task()opensget_db_context(project_id)and then callsrecord_outbound_message().record_outbound_message()creates a shadow run if needed and inserts the outbound row with the sameproject_id.
Read path:
platform_operator_service.get_run_detail()reads outbound rows for the selectedrun_id. Operator Console links from the runs list includeproject_id, so the DB context matches the selected tenant.
Apply
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 \
-f scripts/ops/awooop-rls-canary-wave1-3-outbound-message.sql
The SQL aborts if:
- table is missing,
project_idis missing,- any
project_idis NULL, - row count exceeds the reviewed canary cap of 1000 rows.
Verification
Expected after apply:
- no
app.project_id: direct reads return no rows. app.project_id='awoooi': current outbound rows remain visible.app.project_id='ewoooc': noawoooioutbound rows are visible.- rollback-only insert under
app.project_id='awoooi'is allowed and rolled back. - rollback-only insert under mismatched context is blocked by RLS.
/api/v1/platform/runs/{run_id}/detail?project_id=awoooistill returns the selected run timeline and outbound evidence.- global RLS preflight remains blocked only by later-wave tables.
Production verification from 2026-05-12:
/api/v1/healthfrom API pod: HTTP 200,status=healthy./api/v1/platform/runs/d385b7fe-8666-58ec-9072-9ac917adb6cf/detail?project_id=awoooi:- HTTP 200
counts.outbound_messages=1
scripts/ops/awooop-rls-preflight.sh --exact-counts:PASS=7 WARN=1 BLOCKED=1awooop_outbound_message rls=true force=true policies=1- remaining blocker tables:
audit_logs,awooop_run_state,incidents,knowledge_entries,playbooks.
- Direct app-role behavior:
outbound_no_context=0outbound_awoooi_context=290outbound_ewoooc_context=0insert_awoooi_context_awoooi_row=allowedinsert_ewoooc_context_awoooi_row=blocked:InsufficientPrivilegeErroroutbound_after_probe=290
Rollback
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 \
-f scripts/ops/awooop-rls-canary-wave1-3-outbound-message-rollback.sql
Rollback removes the Wave1.3 policy and disables RLS on
awooop_outbound_message. It does not modify data.