@opengeni/db 3.1.0-canary.0 → 3.2.0-canary.0

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 (57) hide show
  1. package/dist/canonical-human-identities.js +3 -3
  2. package/dist/{chunk-NMUBV7Z5.js → chunk-2EH4WRHL.js} +2 -2
  3. package/dist/{chunk-NJVZPWXY.js → chunk-2PRS4J5Q.js} +3 -3
  4. package/dist/{chunk-TIKF3KTI.js → chunk-6HMM2R5T.js} +11 -4
  5. package/dist/chunk-6HMM2R5T.js.map +1 -0
  6. package/dist/{chunk-SCPUJS53.js → chunk-AZHW7R5V.js} +17 -9
  7. package/dist/chunk-AZHW7R5V.js.map +1 -0
  8. package/dist/{chunk-EULAN2NP.js → chunk-E6CLMKEE.js} +2 -2
  9. package/dist/{chunk-PR2WMLOQ.js → chunk-KRLPEMLH.js} +12 -1
  10. package/dist/chunk-KRLPEMLH.js.map +1 -0
  11. package/dist/{chunk-ZZ5LJEFX.js → chunk-NAB6FKFN.js} +3 -3
  12. package/dist/{chunk-OF5OBB76.js → chunk-UZNXG44K.js} +56 -5
  13. package/dist/chunk-UZNXG44K.js.map +1 -0
  14. package/dist/connection-tenancy-backfill.d.ts +44 -0
  15. package/dist/database.d.ts +4 -4
  16. package/dist/editable-artifact-durable-export.js +2 -2
  17. package/dist/editable-artifacts.js +3 -3
  18. package/dist/index.d.ts +12 -1
  19. package/dist/index.js +1384 -1078
  20. package/dist/index.js.map +1 -1
  21. package/dist/provision-roles.js +1 -1
  22. package/dist/runtime-posture.d.ts +9 -2
  23. package/dist/schema.js +1 -1
  24. package/dist/session-background-commands.js +3 -3
  25. package/dist/session-queue-commands.d.ts +2 -0
  26. package/dist/session-tenancy.js +3 -3
  27. package/dist/slack-routing.d.ts +115 -0
  28. package/dist/slack-user-link-access.d.ts +27 -0
  29. package/dist/video-generation.js +3 -3
  30. package/drizzle/0342_slack_route_prompt_single_pending.sql +32 -0
  31. package/drizzle/0343_personal_document_force_rls_lock_repair.sql +146 -0
  32. package/drizzle/0344_private_session_visibility_transition_gate.sql +85 -0
  33. package/drizzle/0345_tenant_scoped_session_tenancy_fence.sql +2839 -0
  34. package/drizzle/0346_document_migration_audit_surface.sql +454 -0
  35. package/drizzle/0347_connection_authority_convergence_evidence.sql +396 -0
  36. package/package.json +6 -6
  37. package/src/connection-tenancy-backfill.ts +86 -0
  38. package/src/database.ts +12 -0
  39. package/src/index.ts +25 -2
  40. package/src/organization-membership-lifecycle.ts +15 -5
  41. package/src/provision-roles.ts +28 -0
  42. package/src/runtime-posture.ts +31 -1
  43. package/src/schema.ts +13 -0
  44. package/src/session-queue-commands.ts +4 -1
  45. package/src/session-realtime-context.ts +1 -3
  46. package/src/session-realtime-ledger.ts +6 -3
  47. package/src/session-tenancy.ts +7 -0
  48. package/src/slack-routing.ts +399 -1
  49. package/src/slack-user-link-access.ts +121 -10
  50. package/dist/chunk-OF5OBB76.js.map +0 -1
  51. package/dist/chunk-PR2WMLOQ.js.map +0 -1
  52. package/dist/chunk-SCPUJS53.js.map +0 -1
  53. package/dist/chunk-TIKF3KTI.js.map +0 -1
  54. /package/dist/{chunk-NMUBV7Z5.js.map → chunk-2EH4WRHL.js.map} +0 -0
  55. /package/dist/{chunk-NJVZPWXY.js.map → chunk-2PRS4J5Q.js.map} +0 -0
  56. /package/dist/{chunk-EULAN2NP.js.map → chunk-E6CLMKEE.js.map} +0 -0
  57. /package/dist/{chunk-ZZ5LJEFX.js.map → chunk-NAB6FKFN.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  provisionRoles
3
- } from "./chunk-OF5OBB76.js";
3
+ } from "./chunk-UZNXG44K.js";
4
4
  import "./chunk-PZ5AY32C.js";
5
5
  export {
6
6
  provisionRoles
@@ -1,7 +1,14 @@
1
1
  import type { Database, RlsStrategy } from "./database.js";
2
- export declare const RUNTIME_TARGET_SCHEMA_CAPABILITY_ROUTINES: readonly ["company_brain_inspect_context_receipts(uuid, uuid, text, uuid, timestamp with time zone, uuid, integer)", "company_brain_context_get_or_create_selection(uuid, uuid, uuid, uuid, uuid, integer)", "propose_company_profile_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid, text, text, text)", "confirm_company_profile_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid, uuid, uuid)", "evaluate_governed_learning_proposal(uuid, uuid, uuid, uuid, uuid, integer, uuid, uuid, uuid, uuid, uuid)", "activate_governed_learning_decision(uuid, uuid, uuid, uuid)", "activate_human_confirmed_learning_decision(uuid, uuid, uuid, uuid, uuid)", "confirm_remember_knowledge_claim(uuid, uuid, uuid, uuid, integer, uuid, uuid, uuid)", "undo_governed_learning_activation(uuid, uuid, uuid, uuid)", "inspect_governed_learning_decisions(uuid, uuid, text, integer)", "inspect_governed_learning_activations(uuid, uuid, text, integer)", "inspect_governed_learning_activation_undos(uuid, uuid, text, integer)", "fork_session_content(uuid, uuid, uuid, text, uuid, text, boolean, text, text, integer)", "fork_session_content(uuid, uuid, uuid, text, uuid, text, text, text, integer)", "replay_applied_session_fork(uuid, uuid, uuid, text, uuid, text, boolean, text, text, integer)", "session_tenancy_product_activated(uuid, integer)", "session_tenancy_any_product_activation()", "xai_subscription_authority_live(uuid, uuid, text, uuid, text, uuid, uuid, bigint)", "create_xai_subscription_credential(uuid, uuid, text, text, text, text, text, text, text, timestamp with time zone)", "disconnect_xai_subscription_credential(uuid, uuid, text, uuid, jsonb)", "google_drive_document_citation(uuid, uuid, text, uuid, uuid)", "google_drive_file_authorized(uuid, uuid, text, uuid)", "knowledge_source_sync_lock_authority(uuid, uuid, uuid)", "ensure_managed_human_personal_workspace(uuid, text, uuid)", "list_self_organization_memberships(text)", "list_self_organization_invitations(text)", "list_self_organization_invitations(text, uuid, integer)", "get_self_organization_invitation(text, uuid)", "list_organization_invitations(uuid, text, uuid, integer)", "list_organization_members(uuid, text)", "get_organization_administration_overview(uuid, text)", "create_managed_organization(text, text, text, uuid)", "assert_organization_shared_workspace_administrator(uuid, uuid, text)", "open_organization_shared_workspace_administration_capability(uuid, uuid, text)", "close_organization_shared_workspace_administration_capability(uuid)", "create_organization_shared_workspace(uuid, text, text, text, text, uuid)", "upsert_organization_shared_workspace_member(uuid, uuid, text, uuid, text, text, jsonb, boolean)", "update_organization_name(uuid, text, text, timestamp with time zone, uuid)", "create_organization_invitation_v2(jsonb)", "bind_pending_organization_invitations_for_verified_email(text, text)", "has_pending_organization_invitation_for_subject(text)", "accept_organization_invitation_v2(jsonb)", "organization_membership_command(jsonb)", "prepare_organization_membership_protocol_settlements(jsonb)", "assert_active_managed_human_organization_membership(uuid, text)", "resolve_workspace_writer_grant_identity(uuid, text)", "prepare_workspace_membership_removal_settlements(jsonb)", "workspace_membership_removal_command(jsonb)", "get_organization_retention_policy(uuid, text)", "preview_organization_retention_deletions(uuid, integer)", "claim_organization_retention_deletion(uuid, uuid, uuid[])", "list_organization_retention_deletion_objects(uuid, uuid, uuid, text, integer)", "record_organization_retention_object_deleted(uuid, uuid, uuid, text, text, text, text)", "fail_organization_retention_deletion(uuid, uuid, uuid, text)", "finalize_organization_retention_deletion(uuid, uuid, uuid, text)", "complete_organization_retention_deletion(uuid, uuid, uuid, text)", ...string[], "open_private_session_create_capability(uuid, uuid, uuid, text)", "open_private_child_session_create_capability(uuid, uuid, uuid, uuid, uuid, uuid, integer)", "close_private_session_create_capability(uuid)", "resolve_session_attempt_personal_resources(uuid, uuid, uuid)", "accept_turn_personal_resource_attachment(uuid, uuid, uuid, uuid, text, integer, boolean, integer)", "list_self_user_resource_authorities(uuid, uuid, text, uuid, integer)", "issue_self_user_resource_grant(uuid, uuid, uuid, text, text, text, uuid, integer, boolean)", "revoke_self_user_resource_grant(uuid, uuid, uuid)", "authorize_session_attempt_personal_resource_reads(uuid, uuid, uuid)", "preference_registry_create_knowledge_proposal_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid, text, uuid, text, text, text, text, integer, text, jsonb, timestamp with time zone, text)", "create_scoped_variable_set(uuid, uuid, text, text, text, jsonb, boolean)", "list_scoped_variable_sets(uuid, uuid, uuid, text, text)", "count_scoped_variable_sets(uuid, uuid, text)", "mutate_scoped_variable_set(uuid, uuid, uuid, text, text, boolean, text, boolean, text, text, boolean)", "read_scoped_variable_set_secret(uuid, uuid, uuid, text, text, text, uuid, uuid, uuid, integer)", "materialize_scoped_variable_set_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid)", "materialize_scoped_variable_set_for_session(uuid, uuid, uuid, uuid)", "resolve_personal_connection_authority_selection(uuid, uuid, text, uuid, jsonb)", "resolve_accepted_connection_use(uuid, uuid, uuid, uuid, uuid, integer, uuid, text, text, uuid, text, text, text, text)", "resolve_connection_use_authority(uuid, uuid, uuid, jsonb)", "get_self_personal_github_repository_selection(uuid, uuid, text, uuid)", "mutate_self_personal_github_repository_selection(uuid, uuid, text, uuid, bigint, bigint, text, jsonb, boolean)", "create_personal_document_authority(uuid, uuid, uuid)", "resolve_document_original_file(uuid, uuid, text, uuid)", "resolve_session_attempt_personal_document_reads(uuid, uuid, uuid, uuid)", "list_document_authority_reclassifications(uuid, uuid, text, uuid, integer, timestamp with time zone, uuid)", "reclassify_document_authority(jsonb)", "run_document_default_collection_backfill(jsonb)", "create_scoped_rig(uuid, uuid, text, text, text, text, jsonb, boolean)", "list_scoped_rigs(uuid, uuid, uuid, text, text)", "count_scoped_rigs(uuid, uuid, text)", "mutate_scoped_rig(uuid, uuid, uuid, text, text, boolean, text, boolean, boolean)", "finalize_scoped_enrollment(uuid, uuid, text, text, boolean, boolean, text, text, text, boolean)", "list_scoped_enrollments(uuid, uuid, uuid, text)", "get_scoped_sandbox(uuid, uuid, uuid)", "authorize_scoped_sandbox_attach(uuid, uuid, uuid)", "materialize_scoped_rig_version_for_attempt(uuid, uuid, uuid, uuid, uuid, integer)", "authorize_session_attempt_personal_machine(uuid, uuid, uuid, uuid, uuid, integer, uuid)", "assert_session_attempt_personal_machine(uuid, uuid, uuid, uuid, uuid, integer, uuid, boolean)", "list_scoped_machine_dependent_sessions(uuid, uuid, uuid)", "detach_scoped_machine_dependent_sessions(uuid, uuid, uuid)", "freeze_scheduled_task_personal_resources(uuid, uuid, uuid, bigint)", "clone_scheduled_task_personal_resource_authority(uuid, uuid, uuid, bigint, bigint)", "refresh_scheduled_task_personal_resources_clone_connections(uuid, uuid, uuid, bigint, bigint)", "create_scheduled_agent_run_with_admission(uuid, uuid, uuid, uuid, bigint, text, text, text, timestamp with time zone, timestamp with time zone, jsonb)", "materialize_scheduled_task_reusable_session_from_run(uuid, uuid, uuid, uuid, uuid, bigint, text)", "scheduled_task_run_personal_resource_authority(uuid, uuid, uuid)", "scheduled_task_run_connection_authority_subject(uuid, uuid, uuid)", "scheduled_task_personal_resource_authority_subject(uuid, uuid, uuid, bigint)", "record_scheduled_task_revision_authority(uuid, uuid, uuid, bigint)", "clone_scheduled_task_revision_authority(uuid, uuid, uuid, bigint, bigint)", "scheduled_task_revision_authority_subject(uuid, uuid, uuid, bigint)", "scheduled_task_revision_authority_snapshot(uuid, uuid, uuid, bigint)", "validate_scheduled_agent_run_live_authority(uuid, uuid, uuid)", "scheduled_scoped_rig_version_metadata(uuid, uuid, text, uuid, uuid)", "scheduled_variable_set_expected_generation_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid)", "bind_scheduled_task_run_session(uuid, uuid, uuid, uuid)", "transition_scheduled_agent_run(uuid, uuid, uuid, uuid, uuid, text, text)", "ensure_canonical_human_identity(text, text)", "validate_canonical_human_session(text, text, boolean)", "get_canonical_human_identity_projection(text)", "apply_canonical_human_identity_operation(uuid, text, bigint, text, uuid, text, text, text)", "create_task_note_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid, text, text, integer)", "archive_task_note_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid, uuid, integer, text)", "list_task_notes_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, boolean, integer)", "replace_task_note_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid, uuid, uuid, uuid, integer, text, text, integer, text)", "resolve_task_note_knowledge_promotion_source(uuid, uuid, uuid, uuid, uuid, integer, uuid, integer, text, text, text)", "session_private_actor_visible(uuid, uuid, uuid, text)", "session_reference_visible(uuid, uuid, uuid)", "session_visibility_lifecycle_capability_held()", "transition_session_visibility(uuid, uuid, uuid, text, text, integer, text, text, integer)", "xai_subscription_pool_visible(uuid, uuid, text, text, uuid)", "resolve_xai_authority_pool(uuid, uuid, text, jsonb)", "revalidate_xai_subscription_authority(uuid, text, uuid, jsonb)", "xai_provider_account_authority_snapshot_v1_valid(jsonb)"];
2
+ export declare const RUNTIME_TARGET_SCHEMA_CAPABILITY_ROUTINES: readonly ["company_brain_inspect_context_receipts(uuid, uuid, text, uuid, timestamp with time zone, uuid, integer)", "company_brain_context_get_or_create_selection(uuid, uuid, uuid, uuid, uuid, integer)", "propose_company_profile_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid, text, text, text)", "confirm_company_profile_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid, uuid, uuid)", "evaluate_governed_learning_proposal(uuid, uuid, uuid, uuid, uuid, integer, uuid, uuid, uuid, uuid, uuid)", "activate_governed_learning_decision(uuid, uuid, uuid, uuid)", "activate_human_confirmed_learning_decision(uuid, uuid, uuid, uuid, uuid)", "confirm_remember_knowledge_claim(uuid, uuid, uuid, uuid, integer, uuid, uuid, uuid)", "undo_governed_learning_activation(uuid, uuid, uuid, uuid)", "inspect_governed_learning_decisions(uuid, uuid, text, integer)", "inspect_governed_learning_activations(uuid, uuid, text, integer)", "inspect_governed_learning_activation_undos(uuid, uuid, text, integer)", "fork_session_content(uuid, uuid, uuid, text, uuid, text, boolean, text, text, integer)", "fork_session_content(uuid, uuid, uuid, text, uuid, text, text, text, integer)", "replay_applied_session_fork(uuid, uuid, uuid, text, uuid, text, boolean, text, text, integer)", "session_tenancy_product_activated(uuid, integer)", "session_tenancy_any_product_activation()", "xai_subscription_authority_live(uuid, uuid, text, uuid, text, uuid, uuid, bigint)", "create_xai_subscription_credential(uuid, uuid, text, text, text, text, text, text, text, timestamp with time zone)", "disconnect_xai_subscription_credential(uuid, uuid, text, uuid, jsonb)", "google_drive_document_citation(uuid, uuid, text, uuid, uuid)", "google_drive_file_authorized(uuid, uuid, text, uuid)", "knowledge_source_sync_lock_authority(uuid, uuid, uuid)", "ensure_managed_human_personal_workspace(uuid, text, uuid)", "list_self_organization_memberships(text)", "list_self_organization_invitations(text)", "list_self_organization_invitations(text, uuid, integer)", "get_self_organization_invitation(text, uuid)", "list_organization_invitations(uuid, text, uuid, integer)", "list_organization_members(uuid, text)", "get_organization_administration_overview(uuid, text)", "create_managed_organization(text, text, text, uuid)", "assert_organization_shared_workspace_administrator(uuid, uuid, text)", "open_organization_shared_workspace_administration_capability(uuid, uuid, text)", "close_organization_shared_workspace_administration_capability(uuid)", "create_organization_shared_workspace(uuid, text, text, text, text, uuid)", "upsert_organization_shared_workspace_member(uuid, uuid, text, uuid, text, text, jsonb, boolean)", "update_organization_name(uuid, text, text, timestamp with time zone, uuid)", "create_organization_invitation_v2(jsonb)", "bind_pending_organization_invitations_for_verified_email(text, text)", "has_pending_organization_invitation_for_subject(text)", "accept_organization_invitation_v2(jsonb)", "organization_membership_command(jsonb)", "prepare_organization_membership_protocol_settlements(jsonb)", "assert_active_managed_human_organization_membership(uuid, text)", "resolve_workspace_writer_grant_identity(uuid, text)", "prepare_workspace_membership_removal_settlements(jsonb)", "workspace_membership_removal_command(jsonb)", "get_organization_retention_policy(uuid, text)", "preview_organization_retention_deletions(uuid, integer)", "claim_organization_retention_deletion(uuid, uuid, uuid[])", "list_organization_retention_deletion_objects(uuid, uuid, uuid, text, integer)", "record_organization_retention_object_deleted(uuid, uuid, uuid, text, text, text, text)", "fail_organization_retention_deletion(uuid, uuid, uuid, text)", "finalize_organization_retention_deletion(uuid, uuid, uuid, text)", "complete_organization_retention_deletion(uuid, uuid, uuid, text)", ...string[], "open_private_session_create_capability(uuid, uuid, uuid, text)", "open_private_child_session_create_capability(uuid, uuid, uuid, uuid, uuid, uuid, integer)", "close_private_session_create_capability(uuid)", "resolve_session_attempt_personal_resources(uuid, uuid, uuid)", "accept_turn_personal_resource_attachment(uuid, uuid, uuid, uuid, text, integer, boolean, integer)", "list_self_user_resource_authorities(uuid, uuid, text, uuid, integer)", "issue_self_user_resource_grant(uuid, uuid, uuid, text, text, text, uuid, integer, boolean)", "revoke_self_user_resource_grant(uuid, uuid, uuid)", "authorize_session_attempt_personal_resource_reads(uuid, uuid, uuid)", "preference_registry_create_knowledge_proposal_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid, text, uuid, text, text, text, text, integer, text, jsonb, timestamp with time zone, text)", "create_scoped_variable_set(uuid, uuid, text, text, text, jsonb, boolean)", "list_scoped_variable_sets(uuid, uuid, uuid, text, text)", "count_scoped_variable_sets(uuid, uuid, text)", "mutate_scoped_variable_set(uuid, uuid, uuid, text, text, boolean, text, boolean, text, text, boolean)", "read_scoped_variable_set_secret(uuid, uuid, uuid, text, text, text, uuid, uuid, uuid, integer)", "materialize_scoped_variable_set_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid)", "materialize_scoped_variable_set_for_session(uuid, uuid, uuid, uuid)", "connection_authority_convergence_audit_capability_active(uuid)", "resolve_personal_connection_authority_selection(uuid, uuid, text, uuid, jsonb)", "resolve_accepted_connection_use(uuid, uuid, uuid, uuid, uuid, integer, uuid, text, text, uuid, text, text, text, text)", "resolve_connection_use_authority(uuid, uuid, uuid, jsonb)", "inspect_organization_connection_authority_convergence(uuid, integer, uuid)", "get_self_personal_github_repository_selection(uuid, uuid, text, uuid)", "mutate_self_personal_github_repository_selection(uuid, uuid, text, uuid, bigint, bigint, text, jsonb, boolean)", "create_personal_document_authority(uuid, uuid, uuid)", "resolve_document_original_file(uuid, uuid, text, uuid)", "resolve_session_attempt_personal_document_reads(uuid, uuid, uuid, uuid)", "list_document_authority_reclassifications(uuid, uuid, text, uuid, integer, timestamp with time zone, uuid)", "reclassify_document_authority(jsonb)", "run_document_default_collection_backfill(jsonb)", "list_document_default_collection_backfill_runs(jsonb)", "get_document_default_collection_backfill_audit(jsonb)", "list_organization_document_authority_reclassifications(jsonb)", "create_scoped_rig(uuid, uuid, text, text, text, text, jsonb, boolean)", "list_scoped_rigs(uuid, uuid, uuid, text, text)", "count_scoped_rigs(uuid, uuid, text)", "mutate_scoped_rig(uuid, uuid, uuid, text, text, boolean, text, boolean, boolean)", "finalize_scoped_enrollment(uuid, uuid, text, text, boolean, boolean, text, text, text, boolean)", "list_scoped_enrollments(uuid, uuid, uuid, text)", "get_scoped_sandbox(uuid, uuid, uuid)", "authorize_scoped_sandbox_attach(uuid, uuid, uuid)", "materialize_scoped_rig_version_for_attempt(uuid, uuid, uuid, uuid, uuid, integer)", "authorize_session_attempt_personal_machine(uuid, uuid, uuid, uuid, uuid, integer, uuid)", "assert_session_attempt_personal_machine(uuid, uuid, uuid, uuid, uuid, integer, uuid, boolean)", "list_scoped_machine_dependent_sessions(uuid, uuid, uuid)", "detach_scoped_machine_dependent_sessions(uuid, uuid, uuid)", "freeze_scheduled_task_personal_resources(uuid, uuid, uuid, bigint)", "clone_scheduled_task_personal_resource_authority(uuid, uuid, uuid, bigint, bigint)", "refresh_scheduled_task_personal_resources_clone_connections(uuid, uuid, uuid, bigint, bigint)", "create_scheduled_agent_run_with_admission(uuid, uuid, uuid, uuid, bigint, text, text, text, timestamp with time zone, timestamp with time zone, jsonb)", "materialize_scheduled_task_reusable_session_from_run(uuid, uuid, uuid, uuid, uuid, bigint, text)", "scheduled_task_run_personal_resource_authority(uuid, uuid, uuid)", "scheduled_task_run_connection_authority_subject(uuid, uuid, uuid)", "scheduled_task_personal_resource_authority_subject(uuid, uuid, uuid, bigint)", "record_scheduled_task_revision_authority(uuid, uuid, uuid, bigint)", "clone_scheduled_task_revision_authority(uuid, uuid, uuid, bigint, bigint)", "scheduled_task_revision_authority_subject(uuid, uuid, uuid, bigint)", "scheduled_task_revision_authority_snapshot(uuid, uuid, uuid, bigint)", "validate_scheduled_agent_run_live_authority(uuid, uuid, uuid)", "scheduled_scoped_rig_version_metadata(uuid, uuid, text, uuid, uuid)", "scheduled_variable_set_expected_generation_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid)", "bind_scheduled_task_run_session(uuid, uuid, uuid, uuid)", "transition_scheduled_agent_run(uuid, uuid, uuid, uuid, uuid, text, text)", "ensure_canonical_human_identity(text, text)", "validate_canonical_human_session(text, text, boolean)", "get_canonical_human_identity_projection(text)", "apply_canonical_human_identity_operation(uuid, text, bigint, text, uuid, text, text, text)", "create_task_note_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid, text, text, integer)", "archive_task_note_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid, uuid, integer, text)", "list_task_notes_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, boolean, integer)", "replace_task_note_for_attempt(uuid, uuid, uuid, uuid, uuid, integer, uuid, uuid, uuid, uuid, integer, text, text, integer, text)", "resolve_task_note_knowledge_promotion_source(uuid, uuid, uuid, uuid, uuid, integer, uuid, integer, text, text, text)", "session_private_actor_visible(uuid, uuid, uuid, text)", "session_reference_visible(uuid, uuid, uuid)", "session_visibility_lifecycle_capability_held()", "transition_session_visibility(uuid, uuid, uuid, text, text, integer, text, text, integer)", "xai_subscription_pool_visible(uuid, uuid, text, text, uuid)", "resolve_xai_authority_pool(uuid, uuid, text, jsonb)", "revalidate_xai_subscription_authority(uuid, text, uuid, jsonb)", "xai_provider_account_authority_snapshot_v1_valid(jsonb)"];
3
+ /**
4
+ * Boolean-only predicates that shared-table RLS policies must be able to
5
+ * evaluate under table owners and SECURITY DEFINER roles unknown at migration
6
+ * time. The capability ledger and the routine that mints its opaque token stay
7
+ * private; only these exact policy predicates may be PUBLIC-executable.
8
+ */
9
+ export declare const RUNTIME_TARGET_SCHEMA_PUBLIC_POLICY_PREDICATE_ROUTINES: readonly ["connection_authority_convergence_audit_capability_active(uuid)"];
3
10
  /** Owner-internal helpers that must exist but must never be callable by the runtime role. */
4
- export declare const RUNTIME_TARGET_SCHEMA_FORBIDDEN_ROUTINES: readonly ["organization_private_sessions_enabled(uuid)", "assert_session_tenancy_quiescent(uuid, uuid, uuid, boolean)", "check_tenancy_backfill_activation_evidence(uuid)"];
11
+ export declare const RUNTIME_TARGET_SCHEMA_FORBIDDEN_ROUTINES: readonly ["organization_private_sessions_enabled(uuid)", "assert_session_tenancy_quiescent(uuid, uuid, uuid, boolean)", "check_tenancy_backfill_activation_evidence(uuid)", "document_migration_audit_capability_active(text)", "assert_document_migration_audit_authority(jsonb)"];
5
12
  export declare const RUNTIME_TARGET_SCHEMA_INVOKER_ROUTINES: readonly ["session_reference_visible(uuid, uuid, uuid)", "xai_provider_account_authority_snapshot_v1_valid(jsonb)"];
6
13
  /**
7
14
  * The complete standalone tenant-table contract. Adding or removing a
package/dist/schema.js CHANGED
@@ -306,7 +306,7 @@ import {
306
306
  xaiRotationSettings,
307
307
  xaiSessionAccountPins,
308
308
  xaiSubscriptionCredentials
309
- } from "./chunk-PR2WMLOQ.js";
309
+ } from "./chunk-KRLPEMLH.js";
310
310
  import "./chunk-PZ5AY32C.js";
311
311
  export {
312
312
  agentRunStates,
@@ -12,9 +12,9 @@ import {
12
12
  settleClaimedConnectedMachineBackgroundCommand,
13
13
  settleConnectedMachineSessionBackgroundCommand,
14
14
  settleSessionBackgroundCommandForRetainedProcess
15
- } from "./chunk-ZZ5LJEFX.js";
16
- import "./chunk-SCPUJS53.js";
17
- import "./chunk-PR2WMLOQ.js";
15
+ } from "./chunk-NAB6FKFN.js";
16
+ import "./chunk-AZHW7R5V.js";
17
+ import "./chunk-KRLPEMLH.js";
18
18
  import "./chunk-PZ5AY32C.js";
19
19
  export {
20
20
  backgroundCommandActivityForSessions,
@@ -198,6 +198,8 @@ export declare function submitHumanPromptInTransaction(db: SessionActivityDataba
198
198
  text: string;
199
199
  context: string;
200
200
  };
201
+ /** False when the human input originated inside the active realtime provider session. */
202
+ mirrorToRealtime?: boolean;
201
203
  source: "user" | "api";
202
204
  /** Record the admitted run's durable usage fact in this transaction. */
203
205
  recordAgentRunUsage?: boolean;
@@ -14,9 +14,9 @@ import {
14
14
  replayAppliedSessionFork,
15
15
  sessionTenancyProductActivated,
16
16
  transitionSessionVisibility
17
- } from "./chunk-TIKF3KTI.js";
18
- import "./chunk-SCPUJS53.js";
19
- import "./chunk-PR2WMLOQ.js";
17
+ } from "./chunk-6HMM2R5T.js";
18
+ import "./chunk-AZHW7R5V.js";
19
+ import "./chunk-KRLPEMLH.js";
20
20
  import "./chunk-PZ5AY32C.js";
21
21
  export {
22
22
  SessionTenancyAccessError,
@@ -1,4 +1,5 @@
1
1
  import { type Database } from "./database.js";
2
+ import * as schema from "./schema.js";
2
3
  /** The installation binding's own tenancy: credential, identity, and inbox. */
3
4
  export type SlackRouteHome = {
4
5
  accountId: string;
@@ -84,6 +85,10 @@ export declare function probeSlackActionHandleTenancy(db: Database, input: {
84
85
  connectionId: string;
85
86
  handleId: string;
86
87
  }): Promise<SlackRouteHome | null>;
88
+ /** Every channel route this installation has, for the admin surface. */
89
+ export declare function listSlackChannelRoutes(db: Database, home: SlackRouteHome, input: {
90
+ connectionId: string;
91
+ }): Promise<SlackChannelRoute[]>;
87
92
  export declare function getSlackChannelRoute(db: Database, home: SlackRouteHome, input: {
88
93
  connectionId: string;
89
94
  slackChannelId: string;
@@ -151,3 +156,113 @@ export declare function listNamedSubjectSlackRoutableWorkspaces(db: Database, in
151
156
  accountId: string;
152
157
  subjectId: string;
153
158
  }): Promise<SlackRoutableWorkspace[]>;
159
+ /** The trigger kinds a picker can be opened from, mirroring the table's CHECK. */
160
+ export type SlackRoutePromptTriggerKind = (typeof schema.slackRoutePrompts.$inferSelect)["triggerKind"];
161
+ /** A pending first-use picker plus the workspaces it offered. */
162
+ export type SlackRoutePrompt = {
163
+ id: string;
164
+ accountId: string;
165
+ workspaceId: string;
166
+ connectionId: string;
167
+ inboxId: string;
168
+ slackTeamId: string;
169
+ slackUserId: string;
170
+ slackChannelId: string;
171
+ slackMessageTs: string;
172
+ providerEventId: string;
173
+ triggerKind: SlackRoutePromptTriggerKind;
174
+ requestText: string;
175
+ hasFiles: boolean;
176
+ slackThreadTs: string | null;
177
+ messageOperationId: string;
178
+ status: "pending" | "answered" | "expired" | "cancelled";
179
+ expiresAt: Date;
180
+ options: readonly SlackRoutePromptOption[];
181
+ };
182
+ export type SlackRoutePromptOption = {
183
+ id: string;
184
+ candidateAccountId: string;
185
+ candidateWorkspaceId: string;
186
+ candidateLabel: string;
187
+ position: number;
188
+ };
189
+ /**
190
+ * Open one first-use picker for a conversation, or return the one already open.
191
+ *
192
+ * Three separate uniques make this idempotent from three directions: Slack's
193
+ * retries of one event collide on `(connection_id, provider_event_id)`, a
194
+ * replayed inbox row collides on `(connection_id, inbox_id)`, and a genuinely
195
+ * different message in the same conversation collides on the partial pending
196
+ * index. The last one is why a second message never posts a second card: the
197
+ * person is already being asked the same question.
198
+ */
199
+ export declare function openSlackRoutePrompt(db: Database, home: SlackRouteHome, input: {
200
+ connectionId: string;
201
+ inboxId: string;
202
+ slackTeamId: string;
203
+ slackUserId: string;
204
+ slackChannelId: string;
205
+ slackMessageTs: string;
206
+ providerEventId: string;
207
+ triggerKind: SlackRoutePromptTriggerKind;
208
+ requestText: string;
209
+ hasFiles: boolean;
210
+ slackThreadTs: string | null;
211
+ messageOperationId: string;
212
+ expiresAt: Date;
213
+ candidates: readonly SlackRoutableWorkspace[];
214
+ now?: Date;
215
+ }): Promise<{
216
+ opened: boolean;
217
+ prompt: SlackRoutePrompt;
218
+ } | null>;
219
+ /**
220
+ * The prompt one offered button belongs to.
221
+ *
222
+ * The button's `value` is the option row id, which is a UUID precisely because
223
+ * the block-action normalizer already requires that shape. The option rows are a
224
+ * prompt-time SNAPSHOT and are never authority: the caller must re-authorize the
225
+ * chosen workspace live.
226
+ */
227
+ export declare function getSlackRoutePromptByOption(db: Database, home: SlackRouteHome, optionId: string): Promise<{
228
+ prompt: SlackRoutePrompt;
229
+ chosen: SlackRoutePromptOption;
230
+ } | null>;
231
+ /**
232
+ * Settle a prompt without answering it: the person pressed the cancel action, or
233
+ * it aged out. Only a still-pending row moves, so this cannot overwrite an
234
+ * answer that landed first.
235
+ */
236
+ export declare function settleSlackRoutePrompt(db: Database, home: SlackRouteHome, input: {
237
+ promptId: string;
238
+ status: "expired" | "cancelled";
239
+ }): Promise<boolean>;
240
+ /**
241
+ * Answer a picker: freeze the choice, remember it, and re-queue the request.
242
+ *
243
+ * All three commit together. The route row is the ask-once memory, so a later
244
+ * message in that conversation never asks again, and the re-queued inbox row is
245
+ * what actually starts the work the person asked for before they were
246
+ * interrupted by the question.
247
+ *
248
+ * The re-queued row carries a DERIVED provider event id, not the original one.
249
+ * The original inbox row still exists and is settled, so re-using its id would
250
+ * collide with the inbox's own `(connection_id, provider_event_id)` dedupe and
251
+ * silently queue nothing at all. Deriving it from the prompt keeps the insert
252
+ * idempotent for exactly this answer, so a double-click cannot create two
253
+ * sessions.
254
+ *
255
+ * Only a still-pending prompt answers. A second click, an expiry sweep, or a
256
+ * cancel that landed first all leave `answered: false` and change nothing.
257
+ */
258
+ export declare function answerSlackRoutePrompt(db: Database, home: SlackRouteHome, input: {
259
+ promptId: string;
260
+ targetAccountId: string;
261
+ targetWorkspaceId: string;
262
+ answeredBySubjectId: string;
263
+ decidedBySlackUserId: string;
264
+ now?: Date;
265
+ }): Promise<{
266
+ answered: boolean;
267
+ queuedProviderEventId: string | null;
268
+ }>;
@@ -22,9 +22,32 @@ export type SlackUserLinkAccessMutationInput = {
22
22
  expectedVersion: number;
23
23
  idempotencyKey: string;
24
24
  };
25
+ /**
26
+ * The Slack team one access request was raised from.
27
+ *
28
+ * The public request shape deliberately omits it, but an approver has to
29
+ * resolve the installation binding to know where the identity link belongs, and
30
+ * for a routed request that is not the workspace being granted.
31
+ */
32
+ export declare function slackUserLinkAccessRequestTeam(db: Database, input: {
33
+ workspaceId: string;
34
+ requestId: string;
35
+ }): Promise<{
36
+ slackTeamId: string;
37
+ connectionId: string;
38
+ } | null>;
39
+ /**
40
+ * The tenancy an identity link belongs to. See `withSlackIdentityHomeScope`.
41
+ */
42
+ export type SlackIdentityHome = {
43
+ accountId: string;
44
+ workspaceId: string;
45
+ };
25
46
  export type ApproveSlackUserLinkAccessInput = SlackUserLinkAccessMutationInput & {
26
47
  role?: string;
27
48
  permissions: Permission[];
49
+ /** The installation's tenancy, when it differs from the routed request's. */
50
+ identityHome?: SlackIdentityHome;
28
51
  };
29
52
  /**
30
53
  * Persist one verified Slack bearer as token-free, subject-bound state. A
@@ -36,6 +59,8 @@ export declare function getSlackUserLinkAccessRequestForSubject(db: Database, in
36
59
  workspaceId: string;
37
60
  requestId: string;
38
61
  subjectId: string;
62
+ /** The installation's tenancy, when it differs from the routed request's. */
63
+ identityHome?: SlackIdentityHome;
39
64
  }, now?: Date): Promise<SlackUserLinkAccessRequest | null>;
40
65
  export declare function requestSlackUserLinkWorkspaceAccess(db: Database, input: SlackUserLinkAccessMutationInput, now?: Date): Promise<SlackUserLinkAccessRequest>;
41
66
  export declare function cancelSlackUserLinkAccessRequest(db: Database, input: SlackUserLinkAccessMutationInput, now?: Date): Promise<SlackUserLinkAccessRequest>;
@@ -50,6 +75,8 @@ export declare function completeSlackUserLinkAccessIfGranted(db: Database, input
50
75
  workspaceId: string;
51
76
  requestId: string;
52
77
  subjectId: string;
78
+ /** The installation's tenancy, when it differs from the routed request's. */
79
+ identityHome?: SlackIdentityHome;
53
80
  }, now?: Date): Promise<SlackUserLinkAccessRequest | null>;
54
81
  export declare function listPendingSlackUserLinkAccessRequests(db: Database, workspaceId: string, now?: Date): Promise<SlackUserLinkAccessRequest[]>;
55
82
  export declare function workspaceMembershipPermissionsAllowSlackLink(value: unknown): boolean;
@@ -29,9 +29,9 @@ import {
29
29
  settleVideoGenerationFailure,
30
30
  settleVideoGenerationReady,
31
31
  updateWorkspaceVideoGenerationPolicy
32
- } from "./chunk-NJVZPWXY.js";
33
- import "./chunk-SCPUJS53.js";
34
- import "./chunk-PR2WMLOQ.js";
32
+ } from "./chunk-2PRS4J5Q.js";
33
+ import "./chunk-AZHW7R5V.js";
34
+ import "./chunk-KRLPEMLH.js";
35
35
  import "./chunk-PZ5AY32C.js";
36
36
  export {
37
37
  ACTIVE_VIDEO_GENERATION_STATUSES,
@@ -0,0 +1,32 @@
1
+ -- deployment-mode: rolling
2
+ -- One pending Slack route picker per person per conversation.
3
+ --
4
+ -- `slack_route_prompts` is unique on `(connection_id, inbox_id)` and
5
+ -- `(connection_id, provider_event_id)`, both keyed to the originating event, so
6
+ -- Slack's retries of one event cannot post a second card but two DIFFERENT
7
+ -- messages each open their own. One person would get two cards for the same
8
+ -- question, and answering either would write the route while the other stayed
9
+ -- live and answerable.
10
+ --
11
+ -- The key includes `slack_user_id` on purpose. A shared channel has many people
12
+ -- in it, and asking one of them must not swallow another's request: each person
13
+ -- is asked once. A direct message is already one channel per person, so the same
14
+ -- index covers both surfaces.
15
+ --
16
+ -- Expiry is not part of the predicate, because `now()` is not immutable and a
17
+ -- partial index cannot call it. A timed-out row is settled `expired`
18
+ -- opportunistically by the writer before it opens a new prompt, which is what
19
+ -- keeps a card nobody ever clicked from holding the slot forever.
20
+ --
21
+ -- Rolling and safe to build without CONCURRENTLY: the table has no rows and no
22
+ -- writer until the picker ships in this same change.
23
+
24
+ SET LOCAL lock_timeout = '5s';
25
+ SET LOCAL statement_timeout = '10min';
26
+
27
+ CREATE UNIQUE INDEX "slack_route_prompts_pending_conversation_uq"
28
+ ON "slack_route_prompts" ("connection_id", "slack_channel_id", "slack_user_id")
29
+ WHERE "status" = 'pending';
30
+
31
+ RESET statement_timeout;
32
+ RESET lock_timeout;
@@ -0,0 +1,146 @@
1
+ -- deployment-mode: rolling
2
+ -- Repair the two personal-Document membership reads shipped by 0258. A
3
+ -- row-locking SELECT is also subject to an UPDATE policy; the capability only
4
+ -- grants SELECT, so a real NOSUPERUSER/NOBYPASSRLS migration owner saw zero
5
+ -- memberships and silently selected the legacy workspace-anchored lane.
6
+
7
+ SET LOCAL lock_timeout = '5s';
8
+ SET LOCAL statement_timeout = '5min';
9
+
10
+ -- The checker cannot distinguish the function-body source strings below from
11
+ -- top-level executable membership probes. Keep the migration owner's own
12
+ -- transformation/assertion block inside the house owner-only window; ordinary
13
+ -- runtime roles remain RLS-bound throughout and FORCE is restored atomically.
14
+ ALTER TABLE organization_memberships NO FORCE ROW LEVEL SECURITY;
15
+
16
+ DO $repair_personal_document_membership_reads$
17
+ DECLARE
18
+ data_schema text := pg_catalog.current_schema();
19
+ function_oid regprocedure;
20
+ definition text;
21
+ repaired text;
22
+ old_fragment text;
23
+ new_fragment text;
24
+ BEGIN
25
+ function_oid := pg_catalog.to_regprocedure(
26
+ pg_catalog.format('%I.create_personal_document_authority(uuid,uuid,uuid)', data_schema)
27
+ );
28
+ IF function_oid IS NULL THEN
29
+ RAISE EXCEPTION 'create_personal_document_authority is unavailable for repair'
30
+ USING ERRCODE = '55000';
31
+ END IF;
32
+ definition := pg_catalog.pg_get_functiondef(function_oid);
33
+ old_fragment := $old$
34
+ SELECT membership.* INTO member_row
35
+ FROM organization_memberships membership
36
+ WHERE membership.account_id = p_account_id
37
+ AND membership.subject_id = caller_subject
38
+ AND membership.status = 'active'
39
+ AND membership.revoked_at IS NULL
40
+ FOR SHARE;
41
+ $old$;
42
+ new_fragment := $new$
43
+ SELECT membership.* INTO member_row
44
+ FROM organization_memberships membership
45
+ WHERE membership.account_id = p_account_id
46
+ AND membership.subject_id = caller_subject
47
+ AND membership.status = 'active'
48
+ AND membership.revoked_at IS NULL;
49
+
50
+ -- The plain control probe makes a future command/policy mismatch loud.
51
+ -- With this migration's non-locking read the two predicates are
52
+ -- identical. If a later revision restores a locking read without its
53
+ -- exact policy, the capability-visible control row cannot silently fall
54
+ -- through to the legacy authority lane.
55
+ IF NOT FOUND AND EXISTS (
56
+ SELECT 1
57
+ FROM organization_memberships membership
58
+ WHERE membership.account_id = p_account_id
59
+ AND membership.subject_id = caller_subject
60
+ AND membership.status = 'active'
61
+ AND membership.revoked_at IS NULL
62
+ ) THEN
63
+ RAISE EXCEPTION 'personal document membership read was RLS-blinded'
64
+ USING ERRCODE = '55000';
65
+ END IF;
66
+ $new$;
67
+ repaired := pg_catalog.replace(definition, old_fragment, new_fragment);
68
+ IF repaired = definition THEN
69
+ RAISE EXCEPTION 'create_personal_document_authority repair shape changed'
70
+ USING ERRCODE = '55000';
71
+ END IF;
72
+ EXECUTE repaired;
73
+
74
+ function_oid := pg_catalog.to_regprocedure(
75
+ pg_catalog.format(
76
+ '%I.prepare_session_attempt_personal_document_reads(uuid,uuid,uuid,uuid)',
77
+ data_schema
78
+ )
79
+ );
80
+ IF function_oid IS NULL THEN
81
+ RAISE EXCEPTION 'prepare_session_attempt_personal_document_reads is unavailable for repair'
82
+ USING ERRCODE = '55000';
83
+ END IF;
84
+ definition := pg_catalog.pg_get_functiondef(function_oid);
85
+ old_fragment := $old$
86
+ SELECT membership.* INTO member_row
87
+ FROM organization_memberships membership
88
+ WHERE membership.account_id = p_account_id
89
+ AND membership.subject_id = initiating_subject
90
+ AND membership.status = 'active'
91
+ AND membership.revoked_at IS NULL
92
+ FOR SHARE;
93
+ $old$;
94
+ new_fragment := $new$
95
+ SELECT membership.* INTO member_row
96
+ FROM organization_memberships membership
97
+ WHERE membership.account_id = p_account_id
98
+ AND membership.subject_id = initiating_subject
99
+ AND membership.status = 'active'
100
+ AND membership.revoked_at IS NULL;
101
+
102
+ IF NOT FOUND AND EXISTS (
103
+ SELECT 1
104
+ FROM organization_memberships membership
105
+ WHERE membership.account_id = p_account_id
106
+ AND membership.subject_id = initiating_subject
107
+ AND membership.status = 'active'
108
+ AND membership.revoked_at IS NULL
109
+ ) THEN
110
+ RAISE EXCEPTION 'personal document admission membership read was RLS-blinded'
111
+ USING ERRCODE = '55000';
112
+ END IF;
113
+ $new$;
114
+ repaired := pg_catalog.replace(definition, old_fragment, new_fragment);
115
+ IF repaired = definition THEN
116
+ RAISE EXCEPTION 'prepare_session_attempt_personal_document_reads repair shape changed'
117
+ USING ERRCODE = '55000';
118
+ END IF;
119
+
120
+ -- The later portable-document scan has the same command mismatch: locking
121
+ -- both documents and authorities makes PostgreSQL require UPDATE-applicable
122
+ -- policies, while this admission capability is intentionally read-only.
123
+ -- Snapshot foreign keys take the durable referential pins at insertion.
124
+ definition := repaired;
125
+ old_fragment := $old$
126
+ ORDER BY document_value.id
127
+ FOR SHARE OF document_value, authority
128
+ $old$;
129
+ new_fragment := $new$
130
+ ORDER BY document_value.id
131
+ $new$;
132
+ repaired := pg_catalog.replace(definition, old_fragment, new_fragment);
133
+ IF repaired = definition THEN
134
+ RAISE EXCEPTION 'prepare_session_attempt_personal_document_reads document scan repair shape changed'
135
+ USING ERRCODE = '55000';
136
+ END IF;
137
+ EXECUTE repaired;
138
+ END
139
+ $repair_personal_document_membership_reads$;
140
+
141
+ ALTER TABLE organization_memberships FORCE ROW LEVEL SECURITY;
142
+
143
+ COMMENT ON FUNCTION create_personal_document_authority(uuid, uuid, uuid) IS
144
+ 'Creates portable personal Document authority for an exact active organization membership; 0343 removes an RLS-blind row lock and fails loudly on visibility drift.';
145
+ COMMENT ON FUNCTION prepare_session_attempt_personal_document_reads(uuid, uuid, uuid, uuid) IS
146
+ 'Freezes exact-attempt personal Document reads; 0343 removes RLS-blind membership and portable-document row locks and fails loudly on definition or visibility drift.';
@@ -0,0 +1,85 @@
1
+ -- deployment-mode: rolling
2
+ -- A committed visibility transition replays from its applied command receipt
3
+ -- without issuing another sessions UPDATE. Gate the actual state change so
4
+ -- replay remains recoverable after an owner disables private sessions, while a
5
+ -- fresh shared-workspace transition fails closed. Personal workspaces retain
6
+ -- the same exemption as private create and private fork destinations.
7
+
8
+ -- Migration 0323's settings routines install this marker before reading the
9
+ -- actor membership, but the shared lifecycle policy never admitted it. Keep
10
+ -- this authority narrow and separate from that shared marker list. The UPDATE
11
+ -- policy is required because the mutating seam locks the actor with FOR SHARE.
12
+ DO $organization_private_session_settings_membership_policies$
13
+ DECLARE
14
+ data_schema text := pg_catalog.current_schema();
15
+ migration_owner text := current_user;
16
+ marker constant text :=
17
+ 'current_setting(''opengeni.organization_tenancy_lifecycle'', true) '
18
+ || '= ''organization_private_session_settings'' AND account_id = nullif('
19
+ || 'current_setting(''opengeni.account_id'', true), '''')::uuid';
20
+ BEGIN
21
+ EXECUTE pg_catalog.format(
22
+ 'CREATE POLICY organization_private_session_settings_membership_read '
23
+ || 'ON %I.organization_memberships FOR SELECT '
24
+ || 'USING (current_user = %L AND %s)',
25
+ data_schema, migration_owner, marker
26
+ );
27
+ EXECUTE pg_catalog.format(
28
+ 'CREATE POLICY organization_private_session_settings_membership_lock '
29
+ || 'ON %I.organization_memberships FOR UPDATE '
30
+ || 'USING (current_user = %L AND %s)',
31
+ data_schema, migration_owner, marker
32
+ );
33
+ END
34
+ $organization_private_session_settings_membership_policies$;
35
+
36
+ CREATE FUNCTION guard_private_session_visibility_transition()
37
+ RETURNS trigger
38
+ LANGUAGE plpgsql
39
+ SECURITY DEFINER
40
+ SET search_path FROM CURRENT
41
+ AS $$
42
+ BEGIN
43
+ IF OLD.visibility IS DISTINCT FROM NEW.visibility
44
+ AND NEW.visibility = 'user_private'
45
+ AND NOT EXISTS (
46
+ SELECT 1
47
+ FROM organization_memberships membership
48
+ WHERE membership.account_id = NEW.account_id
49
+ AND membership.personal_workspace_id = NEW.workspace_id
50
+ AND membership.status = 'active'
51
+ )
52
+ AND NOT organization_private_sessions_enabled(NEW.account_id)
53
+ THEN
54
+ RAISE EXCEPTION
55
+ 'private sessions are not enabled for this organization''s shared workspaces'
56
+ USING ERRCODE = '55000';
57
+ END IF;
58
+ RETURN NEW;
59
+ END
60
+ $$;
61
+
62
+ REVOKE ALL ON FUNCTION guard_private_session_visibility_transition() FROM PUBLIC;
63
+
64
+ DROP TRIGGER IF EXISTS session_01_private_visibility_setting_fence ON sessions;
65
+ CREATE TRIGGER session_01_private_visibility_setting_fence
66
+ BEFORE UPDATE OF visibility ON sessions
67
+ FOR EACH ROW
68
+ WHEN (OLD.visibility IS DISTINCT FROM NEW.visibility AND NEW.visibility = 'user_private')
69
+ EXECUTE FUNCTION guard_private_session_visibility_transition();
70
+
71
+ DO $$
72
+ DECLARE
73
+ data_schema text := current_schema();
74
+ BEGIN
75
+ EXECUTE format(
76
+ 'ALTER FUNCTION %I.guard_private_session_visibility_transition() '
77
+ || 'SET search_path = pg_catalog, %I, pg_temp',
78
+ data_schema,
79
+ data_schema
80
+ );
81
+ END
82
+ $$;
83
+
84
+ COMMENT ON FUNCTION guard_private_session_visibility_transition() IS
85
+ 'Refuses a fresh transition to user_private in a shared workspace while the organization private-session setting is disabled; applied receipt replay performs no UPDATE and remains valid.';