@opengeni/db 1.0.1 → 3.1.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.
- package/dist/attached-browser-devices.d.ts +7 -0
- package/dist/automations.d.ts +154 -0
- package/dist/canonical-human-identities.js +3 -3
- package/dist/capability-integrations.d.ts +13 -0
- package/dist/child-lifecycle-notices.d.ts +68 -0
- package/dist/{chunk-LTG3S6ZY.js → chunk-EULAN2NP.js} +2 -2
- package/dist/{chunk-CUPM3FGB.js → chunk-NJVZPWXY.js} +3 -3
- package/dist/{chunk-4SR4HKKA.js → chunk-NMUBV7Z5.js} +19 -11
- package/dist/chunk-NMUBV7Z5.js.map +1 -0
- package/dist/chunk-OF5OBB76.js +4457 -0
- package/dist/chunk-OF5OBB76.js.map +1 -0
- package/dist/{chunk-6ZYKCRFO.js → chunk-PR2WMLOQ.js} +7580 -4417
- package/dist/chunk-PR2WMLOQ.js.map +1 -0
- package/dist/{chunk-ZWREYEWA.js → chunk-SCPUJS53.js} +41 -4
- package/dist/chunk-SCPUJS53.js.map +1 -0
- package/dist/{chunk-SK7YYHBI.js → chunk-SIBYBA2D.js} +46 -1
- package/dist/chunk-SIBYBA2D.js.map +1 -0
- package/dist/chunk-TIKF3KTI.js +383 -0
- package/dist/chunk-TIKF3KTI.js.map +1 -0
- package/dist/chunk-ZZ5LJEFX.js +516 -0
- package/dist/chunk-ZZ5LJEFX.js.map +1 -0
- package/dist/codemode-operations.d.ts +1 -6
- package/dist/company-brain-context-selection-schema.d.ts +705 -0
- package/dist/company-brain-context-selection.d.ts +94 -0
- package/dist/company-brain-governed-writes.d.ts +24 -0
- package/dist/company-brain.d.ts +55 -0
- package/dist/company-profile-agent-admin.d.ts +15 -0
- package/dist/company-profile-schema.d.ts +619 -2
- package/dist/company-profile.d.ts +9 -4
- package/dist/connection-authority.d.ts +95 -0
- package/dist/connection-scopes.d.ts +8 -0
- package/dist/connection-tenancy-backfill.d.ts +41 -0
- package/dist/connection-token-resolver.d.ts +30 -1
- package/dist/database.d.ts +19 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.d.ts +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/governed-learning-activation-schema.d.ts +984 -0
- package/dist/governed-learning-activation.d.ts +98 -0
- package/dist/governed-learning-evaluator-schema.d.ts +633 -0
- package/dist/governed-learning-evaluator.d.ts +28 -0
- package/dist/index.d.ts +1595 -81
- package/dist/index.js +21571 -8126
- package/dist/index.js.map +1 -1
- package/dist/insights.d.ts +18 -0
- package/dist/integration-bindings.d.ts +1 -0
- package/dist/integration-facets.d.ts +30 -0
- package/dist/interaction-placement-loss.d.ts +22 -0
- package/dist/managed-human-provisioning.d.ts +25 -0
- package/dist/memory-domain.d.ts +3 -3
- package/dist/migrate.d.ts +11 -1
- package/dist/migrate.js +1 -1
- package/dist/new-session-drafts.d.ts +43 -5
- package/dist/organization-membership-backfill.d.ts +174 -0
- package/dist/organization-membership-lifecycle.d.ts +162 -0
- package/dist/pr-review.d.ts +107 -0
- package/dist/preference-registry-schema.d.ts +2 -0
- package/dist/preference-registry.d.ts +2 -0
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +22 -8
- package/dist/schema.d.ts +24914 -13703
- package/dist/schema.js +99 -1
- package/dist/scoped-knowledge-schema.d.ts +52 -1
- package/dist/session-background-commands.d.ts +125 -0
- package/dist/session-background-commands.js +34 -0
- package/dist/session-background-commands.js.map +1 -0
- package/dist/session-control.d.ts +156 -3
- package/dist/session-goal-pacing.d.ts +68 -0
- package/dist/session-queue-commands.d.ts +41 -4
- package/dist/session-realtime-ledger.d.ts +2 -0
- package/dist/session-tenancy.d.ts +71 -1
- package/dist/session-tenancy.js +25 -3
- package/dist/session-tool-call-settlement.d.ts +9 -4
- package/dist/slack-routing-personal-workspace.d.ts +23 -0
- package/dist/slack-routing.d.ts +153 -0
- package/dist/slack-task-policy-schema.d.ts +34 -0
- package/dist/slack-task-policy.d.ts +8 -0
- package/dist/slack-user-link-access.d.ts +1 -0
- package/dist/task-notes-schema.d.ts +594 -0
- package/dist/task-notes.d.ts +39 -0
- package/dist/turn-initiator.d.ts +2 -0
- package/dist/user-resource-authority.d.ts +109 -0
- package/dist/video-generation.js +3 -3
- package/dist/workspace-authority.d.ts +81 -0
- package/dist/workspace-instruction-policies-schema.d.ts +279 -0
- package/dist/workspace-instruction-policies.d.ts +62 -0
- package/dist/workspace-learning-policy.d.ts +1 -0
- package/dist/workspace-membership-permissions.d.ts +2 -0
- package/drizzle/0240_enrollment_connection_authority.sql +39 -0
- package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
- package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
- package/drizzle/0244_slack_app_home_refresh_queue.sql +120 -0
- package/drizzle/0245_model_context_contribution_facts.sql +88 -0
- package/drizzle/0246_integration_personal_instance_authority.sql +70 -0
- package/drizzle/0247_terraform_stacks_provenance_repair.sql +428 -0
- package/drizzle/0248_terraform_stacks_component_resolution_fence.sql +83 -0
- package/drizzle/0249_personal_resource_delegation_authority_correction.sql +662 -0
- package/drizzle/0250_direct_retained_process_owner_liveness.sql +199 -0
- package/drizzle/0251_connected_machine_operation_policy.sql +45 -0
- package/drizzle/0252_scheduled_personal_resource_delegation.sql +1867 -0
- package/drizzle/0253_common_user_resource_authority_lifecycle.sql +1555 -0
- package/drizzle/0254_scoped_variable_set_authority.sql +1255 -0
- package/drizzle/0255_company_brain_governed_write_proposals.sql +524 -0
- package/drizzle/0256_connection_authority_delegation.sql +703 -0
- package/drizzle/0257_goal_revision_decisions_and_root_constraints.sql +436 -0
- package/drizzle/0258_three_scope_document_knowledge_authority.sql +1273 -0
- package/drizzle/0259_company_brain_context_selection_receipts.sql +869 -0
- package/drizzle/0260_task_note_knowledge_promotion.sql +820 -0
- package/drizzle/0261_preference_knowledge_proposal_actor_binding.sql +471 -0
- package/drizzle/0262_scoped_connected_machines_and_rigs.sql +1700 -0
- package/drizzle/0263_organization_membership_lifecycle.sql +3284 -0
- package/drizzle/0264_connection_authority_runtime_activation.sql +1084 -0
- package/drizzle/0266_company_brain_context_receipt_inspection.sql +156 -0
- package/drizzle/0268_governed_learning_decision_receipts.sql +825 -0
- package/drizzle/0269_governed_learning_activation_controller.sql +1874 -0
- package/drizzle/0270_governed_learning_history_inspection.sql +170 -0
- package/drizzle/0271_company_brain_retrieval_only_default.sql +524 -0
- package/drizzle/0272_human_confirmed_learning_activation.sql +591 -0
- package/drizzle/0273_scheduled_variable_set_materialization.sql +268 -0
- package/drizzle/0274_human_confirmed_knowledge_review.sql +310 -0
- package/drizzle/0275_scheduled_connection_authority.sql +5527 -0
- package/drizzle/0276_onboarding_proposal_initiating_human_guc.sql +198 -0
- package/drizzle/0277_workspace_writer_authority_attribution.sql +393 -0
- package/drizzle/0278_workspace_membership_removal_fencing.sql +1174 -0
- package/drizzle/0279_workspace_connection_use_lane.sql +343 -0
- package/drizzle/0280_connection_and_variable_set_audit_attribution.sql +773 -0
- package/drizzle/0281_viewer_holder_authority_claims.sql +52 -0
- package/drizzle/0282_variable_set_session_attach_attribution.sql +178 -0
- package/drizzle/0283_editable_spreadsheet_authored_state.sql +82 -0
- package/drizzle/0284_truthful_human_confirmed_review_reason.sql +930 -0
- package/drizzle/0285_organization_tenancy_inventory.sql +329 -0
- package/drizzle/0286_widen_task_note_expiry_ceiling.sql +391 -0
- package/drizzle/0287_open_suffix_pending_tool_calls.sql +18 -0
- package/drizzle/0288_attached_browser_reenrollment.sql +64 -0
- package/drizzle/0289_session_composer_policy_authority.sql +597 -0
- package/drizzle/0290_organization_membership_backfill.sql +268 -0
- package/drizzle/0291_resource_authority_classification_assertion.sql +371 -0
- package/drizzle/0292_truthful_tenancy_inventory_counters.sql +291 -0
- package/drizzle/0293_confirm_time_rule_rebaseline.sql +615 -0
- package/drizzle/0294_preference_activation_authority.sql +237 -0
- package/drizzle/0295_retire_legacy_standing_memory_mode.sql +476 -0
- package/drizzle/0296_force_rls_backfill_noop_repair.sql +215 -0
- package/drizzle/0297_session_ownership_classification_and_backfill.sql +752 -0
- package/drizzle/0298_organization_tenancy_parity.sql +609 -0
- package/drizzle/0299_organization_membership_lock_order.sql +291 -0
- package/drizzle/0300_tenancy_backfill_ledger.sql +459 -0
- package/drizzle/0301_session_snapshot_and_pin_visibility.sql +181 -0
- package/drizzle/0302_personal_workspace_session_ownership.sql +303 -0
- package/drizzle/0303_session_tenancy_product_activation.sql +919 -0
- package/drizzle/0304_personal_workspace_private_session_reads.sql +97 -0
- package/drizzle/0305_personal_resource_grant_management.sql +584 -0
- package/drizzle/0306_atomic_personal_resource_attachments.sql +1374 -0
- package/drizzle/0307_session_attention_state.sql +51 -0
- package/drizzle/0308_session_archives.sql +35 -0
- package/drizzle/0309_channel_project_pins.sql +6 -0
- package/drizzle/0310_channel_project_order.sql +27 -0
- package/drizzle/0311_company_scope_and_private_session_create.sql +656 -0
- package/drizzle/0312_quiescent_session_tree_deletion.sql +39 -0
- package/drizzle/0313_private_child_session_authority.sql +365 -0
- package/drizzle/0314_unregistered_organization_invitations.sql +606 -0
- package/drizzle/0315_personal_github_repository_selection.sql +624 -0
- package/drizzle/0316_human_confirmed_activation_resumed_generation.sql +869 -0
- package/drizzle/0317_session_goal_continuation_hold.sql +64 -0
- package/drizzle/0318_session_turn_startup_milestones.sql +115 -0
- package/drizzle/0319_event_triggered_automations.sql +254 -0
- package/drizzle/0320_pr_review_pack.sql +113 -0
- package/drizzle/0321_slack_bot_environment_display_name.sql +15 -0
- package/drizzle/0322_session_turns_unclaimed_prompt_trigger_index.sql +5 -0
- package/drizzle/0323_organization_private_session_enablement.sql +489 -0
- package/drizzle/0324_human_confirmed_company_profile_agent_admin.sql +856 -0
- package/drizzle/0325_child_lifecycle_notices.sql +44 -0
- package/drizzle/0326_interaction_operation_error_codes.sql +62 -0
- package/drizzle/0327_slack_first_task_hint.sql +29 -0
- package/drizzle/0328_session_background_commands.sql +590 -0
- package/drizzle/0329_slack_orchestration_delivery_events.sql +91 -0
- package/drizzle/0330_api_key_descriptions.sql +20 -0
- package/drizzle/0331_managed_organization_creation.sql +163 -0
- package/drizzle/0332_organization_shared_workspace_control_plane.sql +539 -0
- package/drizzle/0333_session_turn_prompt_routing.sql +45 -0
- package/drizzle/0334_connected_machine_workspace_root.sql +99 -0
- package/drizzle/0335_slack_workspace_routing.sql +460 -0
- package/drizzle/0336_atomic_session_fork_visibility.sql +667 -0
- package/drizzle/0337_slack_routed_action_handles.sql +189 -0
- package/drizzle/0338_atomic_connected_machine_attachments.sql +410 -0
- package/drizzle/0339_document_authority_reclassification.sql +1153 -0
- package/drizzle/0340_tenancy_backfill_activation_evidence.sql +1347 -0
- package/drizzle/0341_slack_routing_probe_organization_fence.sql +109 -0
- package/package.json +10 -6
- package/src/attached-browser-devices.ts +233 -5
- package/src/automations.ts +911 -0
- package/src/browser-sessions.ts +10 -0
- package/src/capability-integrations.ts +175 -1
- package/src/child-lifecycle-notices.ts +241 -0
- package/src/codemode-operations.ts +1 -35
- package/src/company-brain-context-selection-schema.ts +100 -0
- package/src/company-brain-context-selection.ts +359 -0
- package/src/company-brain-governed-writes.ts +1170 -0
- package/src/company-brain.ts +309 -0
- package/src/company-profile-agent-admin.ts +225 -0
- package/src/company-profile-schema.ts +121 -1
- package/src/company-profile.ts +21 -0
- package/src/computer-sessions.ts +10 -1
- package/src/connection-authority.ts +290 -0
- package/src/connection-scopes.ts +20 -0
- package/src/connection-tenancy-backfill.ts +81 -0
- package/src/connection-token-resolver.ts +263 -31
- package/src/database.ts +75 -2
- package/src/editable-artifacts-schema.ts +10 -5
- package/src/editable-artifacts.ts +21 -11
- package/src/governed-learning-activation-schema.ts +121 -0
- package/src/governed-learning-activation.ts +588 -0
- package/src/governed-learning-evaluator-schema.ts +72 -0
- package/src/governed-learning-evaluator.ts +217 -0
- package/src/index.ts +11651 -1548
- package/src/insights.ts +107 -0
- package/src/integration-bindings.ts +88 -6
- package/src/integration-facets.ts +287 -84
- package/src/interaction-placement-loss.ts +234 -0
- package/src/managed-human-provisioning.ts +116 -0
- package/src/memory-domain.ts +27 -32
- package/src/migrate.ts +77 -1
- package/src/new-session-drafts.ts +229 -35
- package/src/organization-membership-backfill.ts +735 -0
- package/src/organization-membership-lifecycle.ts +985 -0
- package/src/pr-review.ts +890 -0
- package/src/preference-registry.ts +31 -1
- package/src/provision-roles.ts +877 -6
- package/src/runtime-posture-cli.ts +2 -0
- package/src/runtime-posture.ts +1291 -76
- package/src/schema.ts +3303 -428
- package/src/scoped-knowledge-schema.ts +16 -8
- package/src/scoped-knowledge.ts +1 -1
- package/src/session-background-commands.ts +759 -0
- package/src/session-control.ts +640 -74
- package/src/session-goal-pacing.ts +126 -0
- package/src/session-queue-commands.ts +437 -84
- package/src/session-realtime-context.ts +3 -3
- package/src/session-realtime-ledger.ts +22 -11
- package/src/session-realtime-mirror.ts +1 -1
- package/src/session-tenancy.ts +403 -49
- package/src/session-tool-call-settlement.ts +38 -29
- package/src/slack-routing-personal-workspace.ts +67 -0
- package/src/slack-routing.ts +469 -0
- package/src/slack-task-policy-schema.ts +5 -0
- package/src/slack-task-policy.ts +18 -0
- package/src/slack-user-link-access.ts +17 -1
- package/src/task-notes-schema.ts +74 -0
- package/src/task-notes.ts +124 -2
- package/src/turn-initiator.ts +8 -0
- package/src/user-resource-authority.ts +377 -0
- package/src/workspace-authority.ts +160 -0
- package/src/workspace-instruction-policies-schema.ts +53 -1
- package/src/workspace-instruction-policies.ts +528 -77
- package/src/workspace-learning-policy.ts +21 -5
- package/src/workspace-membership-permissions.ts +9 -0
- package/dist/chunk-4SR4HKKA.js.map +0 -1
- package/dist/chunk-6ZYKCRFO.js.map +0 -1
- package/dist/chunk-NXAFLCQX.js +0 -2468
- package/dist/chunk-NXAFLCQX.js.map +0 -1
- package/dist/chunk-SK7YYHBI.js.map +0 -1
- package/dist/chunk-WD5ROSLL.js +0 -117
- package/dist/chunk-WD5ROSLL.js.map +0 -1
- package/dist/chunk-ZWREYEWA.js.map +0 -1
- /package/dist/{chunk-LTG3S6ZY.js.map → chunk-EULAN2NP.js.map} +0 -0
- /package/dist/{chunk-CUPM3FGB.js.map → chunk-NJVZPWXY.js.map} +0 -0
package/src/slack-task-policy.ts
CHANGED
|
@@ -30,6 +30,14 @@ export type SlackSharedTaskOrigin = {
|
|
|
30
30
|
sourceThreadTs: string;
|
|
31
31
|
initiatingSlackUserId: string;
|
|
32
32
|
policyRevisionId: string;
|
|
33
|
+
/**
|
|
34
|
+
* Home tenancy of the frozen policy revision. The row's own
|
|
35
|
+
* `accountId`/`workspaceId` are the routed task's, which is a different
|
|
36
|
+
* workspace once Slack workspace routing is on. Null on rows written before
|
|
37
|
+
* routing existed, where the two were always equal.
|
|
38
|
+
*/
|
|
39
|
+
policyAccountId: string | null;
|
|
40
|
+
policyWorkspaceId: string | null;
|
|
33
41
|
policyHash: string;
|
|
34
42
|
policyActivationVersion: number;
|
|
35
43
|
publicationMode: "never" | "approval_required" | "allow";
|
|
@@ -310,6 +318,16 @@ export async function saveSlackSharedTaskOrigin(
|
|
|
310
318
|
.limit(1);
|
|
311
319
|
if (!existing) throw new Error("Slack shared-task origin conflict could not be resolved");
|
|
312
320
|
for (const [key, value] of Object.entries(input)) {
|
|
321
|
+
// A row written before Slack workspace routing carries no policy tenancy
|
|
322
|
+
// and implied its own, because the two could not differ then. A replay
|
|
323
|
+
// from a new image supplies it, which is not a change of evidence and
|
|
324
|
+
// must not be reported as one.
|
|
325
|
+
if (
|
|
326
|
+
(key === "policyAccountId" || key === "policyWorkspaceId") &&
|
|
327
|
+
existing[key as keyof OriginRow] === null
|
|
328
|
+
) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
313
331
|
if (existing[key as keyof OriginRow] !== value) {
|
|
314
332
|
throw new SlackTaskPolicyInvalidOperationError(
|
|
315
333
|
"Slack shared-task origin identity conflicted with immutable evidence",
|
|
@@ -9,8 +9,10 @@ import {
|
|
|
9
9
|
import { and, asc, eq, gt, inArray, ne } from "drizzle-orm";
|
|
10
10
|
|
|
11
11
|
import { type Database, withWorkspaceRls } from "./database";
|
|
12
|
+
import { namedSubjectPersonalWorkspaceId } from "./slack-routing-personal-workspace";
|
|
12
13
|
import { withLosslessContentWriteVersion } from "./lossless-json";
|
|
13
14
|
import * as schema from "./schema";
|
|
15
|
+
import { normalizeWorkspaceMembershipPermissions } from "./workspace-membership-permissions";
|
|
14
16
|
|
|
15
17
|
type RequestRow = typeof schema.slackUserLinkAccessRequests.$inferSelect;
|
|
16
18
|
type OperationKind = "request" | "cancel" | "approve" | "deny";
|
|
@@ -563,7 +565,21 @@ async function membershipAllowsSlackLink(database: Database, row: RequestRow) {
|
|
|
563
565
|
),
|
|
564
566
|
)
|
|
565
567
|
.limit(1);
|
|
566
|
-
|
|
568
|
+
if (workspaceMembershipPermissionsAllowSlackLink(membership?.permissions)) return true;
|
|
569
|
+
// A managed human's own personal workspace deliberately has no
|
|
570
|
+
// `workspace_memberships` row, so a bare membership join denies its owner.
|
|
571
|
+
// Once a Slack direct message can land there, that would tell people to
|
|
572
|
+
// request access to their own workspace. The pointer is DERIVED from an
|
|
573
|
+
// active organization membership; it is never accepted from the request row.
|
|
574
|
+
const personalWorkspaceId = await namedSubjectPersonalWorkspaceId(database, {
|
|
575
|
+
accountId: row.accountId,
|
|
576
|
+
subjectId: row.subjectId,
|
|
577
|
+
});
|
|
578
|
+
return personalWorkspaceId === row.workspaceId;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
export function workspaceMembershipPermissionsAllowSlackLink(value: unknown): boolean {
|
|
582
|
+
const permissions = normalizeWorkspaceMembershipPermissions(value);
|
|
567
583
|
return permissions.includes("sessions:create") || permissions.includes("workspace:admin");
|
|
568
584
|
}
|
|
569
585
|
|
package/src/task-notes-schema.ts
CHANGED
|
@@ -133,3 +133,77 @@ export const taskNoteWriteCapabilities = pgTable(
|
|
|
133
133
|
),
|
|
134
134
|
}),
|
|
135
135
|
);
|
|
136
|
+
|
|
137
|
+
// Transaction-local, owner-only admission for the single Task-note evidence
|
|
138
|
+
// insert materialized by a governed promotion. Migration 0260 owns its RLS,
|
|
139
|
+
// one-shot trigger consumption, and runtime-role revocation.
|
|
140
|
+
export const taskNoteKnowledgePromotionCapabilities = pgTable(
|
|
141
|
+
"task_note_knowledge_promotion_capabilities",
|
|
142
|
+
{
|
|
143
|
+
backendPid: integer("backend_pid").notNull(),
|
|
144
|
+
transactionId: xid8("transaction_id").notNull(),
|
|
145
|
+
capabilityId: uuid("capability_id").notNull(),
|
|
146
|
+
accountId: uuid("account_id").notNull(),
|
|
147
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
148
|
+
noteId: uuid("note_id").notNull(),
|
|
149
|
+
rootSessionId: uuid("root_session_id").notNull(),
|
|
150
|
+
noteVersion: integer("note_version").notNull(),
|
|
151
|
+
noteTextHash: text("note_text_hash").notNull(),
|
|
152
|
+
evidenceOperationId: text("evidence_operation_id").notNull(),
|
|
153
|
+
claimOperationId: text("claim_operation_id").notNull(),
|
|
154
|
+
actorSubjectId: text("actor_subject_id").notNull(),
|
|
155
|
+
initiatingHumanSubjectId: text("initiating_human_subject_id").notNull(),
|
|
156
|
+
learningPolicySnapshotId: uuid("learning_policy_snapshot_id").notNull(),
|
|
157
|
+
},
|
|
158
|
+
(table) => ({
|
|
159
|
+
identity: uniqueIndex("task_note_knowledge_promotion_capabilities_identity_uq").on(
|
|
160
|
+
table.backendPid,
|
|
161
|
+
table.transactionId,
|
|
162
|
+
table.capabilityId,
|
|
163
|
+
),
|
|
164
|
+
}),
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
// Immutable, content-free lineage for one atomic archive + replacement create.
|
|
168
|
+
// Migration 0260 owns exact constraints, FORCE RLS, and lifecycle-only writes.
|
|
169
|
+
export const taskNoteReplacementReceipts = pgTable(
|
|
170
|
+
"task_note_replacement_receipts",
|
|
171
|
+
{
|
|
172
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
173
|
+
accountId: uuid("account_id").notNull(),
|
|
174
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
175
|
+
rootSessionId: uuid("root_session_id").notNull(),
|
|
176
|
+
operationId: uuid("operation_id").notNull(),
|
|
177
|
+
inputHash: text("input_hash").notNull(),
|
|
178
|
+
replacedNoteId: uuid("replaced_note_id").notNull(),
|
|
179
|
+
replacedNoteVersion: integer("replaced_note_version").notNull(),
|
|
180
|
+
replacementNoteId: uuid("replacement_note_id").notNull(),
|
|
181
|
+
replacementNoteVersion: integer("replacement_note_version").notNull(),
|
|
182
|
+
archiveOperationId: uuid("archive_operation_id").notNull(),
|
|
183
|
+
createOperationId: uuid("create_operation_id").notNull(),
|
|
184
|
+
actorKind: text("actor_kind").notNull(),
|
|
185
|
+
actorSubjectId: text("actor_subject_id").notNull(),
|
|
186
|
+
initiatingHumanSubjectId: text("initiating_human_subject_id"),
|
|
187
|
+
actorSessionId: uuid("actor_session_id").notNull(),
|
|
188
|
+
actorTurnId: uuid("actor_turn_id").notNull(),
|
|
189
|
+
actorAttemptId: uuid("actor_attempt_id").notNull(),
|
|
190
|
+
actorExecutionGeneration: integer("actor_execution_generation").notNull(),
|
|
191
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
192
|
+
},
|
|
193
|
+
(table) => ({
|
|
194
|
+
workspaceOperation: uniqueIndex("task_note_replacement_receipts_workspace_operation_uq").on(
|
|
195
|
+
table.workspaceId,
|
|
196
|
+
table.operationId,
|
|
197
|
+
),
|
|
198
|
+
workspaceReplacement: uniqueIndex("task_note_replacement_receipts_workspace_replacement_uq").on(
|
|
199
|
+
table.workspaceId,
|
|
200
|
+
table.replacementNoteId,
|
|
201
|
+
),
|
|
202
|
+
rootTimeline: index("task_note_replacement_receipts_root_timeline_idx").on(
|
|
203
|
+
table.workspaceId,
|
|
204
|
+
table.rootSessionId,
|
|
205
|
+
table.createdAt,
|
|
206
|
+
table.id,
|
|
207
|
+
),
|
|
208
|
+
}),
|
|
209
|
+
);
|
package/src/task-notes.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TASK_NOTE_LIST_DEFAULT_LIMIT,
|
|
3
3
|
TASK_NOTE_LIST_MAX_LIMIT,
|
|
4
|
+
TASK_NOTE_MAX_LIFETIME_DAYS,
|
|
4
5
|
TaskNote,
|
|
5
6
|
TaskNoteKind,
|
|
6
7
|
TaskNoteListResponse,
|
|
7
8
|
TaskNoteMutationResult,
|
|
8
9
|
TaskNoteReason,
|
|
10
|
+
TaskNoteReplacementResult,
|
|
9
11
|
TaskNoteText,
|
|
10
12
|
type TaskNoteKind as TaskNoteKindType,
|
|
11
13
|
} from "@opengeni/contracts";
|
|
14
|
+
import { createHash } from "node:crypto";
|
|
12
15
|
import { sql } from "drizzle-orm";
|
|
13
16
|
import type { Database } from "./database";
|
|
14
17
|
import { rawRows, withRlsContext } from "./database";
|
|
@@ -36,6 +39,16 @@ export type ArchiveTaskNoteInput = TaskNoteAttemptClaims & {
|
|
|
36
39
|
reason: string;
|
|
37
40
|
};
|
|
38
41
|
|
|
42
|
+
export type ReplaceTaskNoteInput = TaskNoteAttemptClaims & {
|
|
43
|
+
operationId: string;
|
|
44
|
+
replacedNoteId: string;
|
|
45
|
+
expectedReplacedVersion: number;
|
|
46
|
+
replacementKind: TaskNoteKindType;
|
|
47
|
+
replacementText: string;
|
|
48
|
+
replacementExpiresInDays: number;
|
|
49
|
+
reason: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
39
52
|
export type ListTaskNotesInput = TaskNoteAttemptClaims & {
|
|
40
53
|
includeArchived?: boolean;
|
|
41
54
|
limit?: number;
|
|
@@ -58,6 +71,27 @@ type TaskNoteRow = {
|
|
|
58
71
|
replayed?: boolean;
|
|
59
72
|
};
|
|
60
73
|
|
|
74
|
+
type TaskNoteReplacementRow = {
|
|
75
|
+
operation_id: string;
|
|
76
|
+
input_hash: string;
|
|
77
|
+
replaced_note_id: string;
|
|
78
|
+
replaced_note_version: number;
|
|
79
|
+
replacement_note_id: string;
|
|
80
|
+
root_session_id: string;
|
|
81
|
+
replacement_kind: string;
|
|
82
|
+
replacement_text: string;
|
|
83
|
+
replacement_status: string;
|
|
84
|
+
replacement_version: number;
|
|
85
|
+
replacement_expires_at: Date | string;
|
|
86
|
+
replacement_created_at: Date | string;
|
|
87
|
+
replacement_updated_at: Date | string;
|
|
88
|
+
replacement_archived_at: Date | string | null;
|
|
89
|
+
replacement_actor_kind: string;
|
|
90
|
+
replacement_source_session_id: string;
|
|
91
|
+
replacement_source_turn_id: string;
|
|
92
|
+
replayed: boolean;
|
|
93
|
+
};
|
|
94
|
+
|
|
61
95
|
function iso(value: Date | string): string {
|
|
62
96
|
return (value instanceof Date ? value : new Date(value)).toISOString();
|
|
63
97
|
}
|
|
@@ -88,6 +122,20 @@ function assertAttemptClaims(claims: TaskNoteAttemptClaims): void {
|
|
|
88
122
|
}
|
|
89
123
|
}
|
|
90
124
|
|
|
125
|
+
function derivedTaskNoteOperationId(operationId: string, label: "archive" | "create"): string {
|
|
126
|
+
const bytes = Buffer.from(
|
|
127
|
+
createHash("sha256")
|
|
128
|
+
.update(`task-note-replacement:v1:${operationId}:${label}`, "utf8")
|
|
129
|
+
.digest("hex")
|
|
130
|
+
.slice(0, 32),
|
|
131
|
+
"hex",
|
|
132
|
+
);
|
|
133
|
+
bytes[6] = (bytes[6]! & 0x0f) | 0x50;
|
|
134
|
+
bytes[8] = (bytes[8]! & 0x3f) | 0x80;
|
|
135
|
+
const hex = bytes.toString("hex");
|
|
136
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
137
|
+
}
|
|
138
|
+
|
|
91
139
|
export async function createTaskNote(db: Database, input: CreateTaskNoteInput) {
|
|
92
140
|
assertAttemptClaims(input);
|
|
93
141
|
TaskNoteKind.parse(input.kind);
|
|
@@ -95,9 +143,9 @@ export async function createTaskNote(db: Database, input: CreateTaskNoteInput) {
|
|
|
95
143
|
if (
|
|
96
144
|
!Number.isSafeInteger(input.expiresInDays) ||
|
|
97
145
|
input.expiresInDays < 1 ||
|
|
98
|
-
input.expiresInDays >
|
|
146
|
+
input.expiresInDays > TASK_NOTE_MAX_LIFETIME_DAYS
|
|
99
147
|
) {
|
|
100
|
-
throw new Error(
|
|
148
|
+
throw new Error(`Task note expiry must be 1-${TASK_NOTE_MAX_LIFETIME_DAYS} whole days`);
|
|
101
149
|
}
|
|
102
150
|
const rows = await withRlsContext(
|
|
103
151
|
db,
|
|
@@ -150,6 +198,80 @@ export async function archiveTaskNote(db: Database, input: ArchiveTaskNoteInput)
|
|
|
150
198
|
return TaskNoteMutationResult.parse({ note: noteFromRow(rows[0]!), replayed: rows[0]!.replayed });
|
|
151
199
|
}
|
|
152
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Atomically archive one exact active note and create its immutable replacement.
|
|
203
|
+
* Exact retries return the original linked receipt; changed input or authority fails.
|
|
204
|
+
*/
|
|
205
|
+
export async function replaceTaskNote(db: Database, input: ReplaceTaskNoteInput) {
|
|
206
|
+
assertAttemptClaims(input);
|
|
207
|
+
TaskNoteKind.parse(input.replacementKind);
|
|
208
|
+
TaskNoteText.parse(input.replacementText);
|
|
209
|
+
TaskNoteReason.parse(input.reason);
|
|
210
|
+
if (
|
|
211
|
+
input.expectedReplacedVersion !== 1 ||
|
|
212
|
+
!Number.isSafeInteger(input.replacementExpiresInDays) ||
|
|
213
|
+
input.replacementExpiresInDays < 1 ||
|
|
214
|
+
input.replacementExpiresInDays > TASK_NOTE_MAX_LIFETIME_DAYS
|
|
215
|
+
) {
|
|
216
|
+
throw new Error(
|
|
217
|
+
`Task-note replacement requires version 1 and a 1-${TASK_NOTE_MAX_LIFETIME_DAYS} day expiry`,
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
const archiveOperationId = derivedTaskNoteOperationId(input.operationId, "archive");
|
|
221
|
+
const createOperationId = derivedTaskNoteOperationId(input.operationId, "create");
|
|
222
|
+
const rows = await withRlsContext(
|
|
223
|
+
db,
|
|
224
|
+
{ accountId: input.accountId, workspaceId: input.workspaceId },
|
|
225
|
+
async (tx) =>
|
|
226
|
+
await rawRows<TaskNoteReplacementRow>(
|
|
227
|
+
tx,
|
|
228
|
+
sql`SELECT * FROM replace_task_note_for_attempt(
|
|
229
|
+
${input.accountId}::uuid,
|
|
230
|
+
${input.workspaceId}::uuid,
|
|
231
|
+
${input.sessionId}::uuid,
|
|
232
|
+
${input.turnId}::uuid,
|
|
233
|
+
${input.attemptId}::uuid,
|
|
234
|
+
${input.executionGeneration}::integer,
|
|
235
|
+
${input.operationId}::uuid,
|
|
236
|
+
${archiveOperationId}::uuid,
|
|
237
|
+
${createOperationId}::uuid,
|
|
238
|
+
${input.replacedNoteId}::uuid,
|
|
239
|
+
${input.expectedReplacedVersion}::integer,
|
|
240
|
+
${input.replacementKind}::text,
|
|
241
|
+
${input.replacementText}::text,
|
|
242
|
+
${input.replacementExpiresInDays}::integer,
|
|
243
|
+
${input.reason}::text
|
|
244
|
+
)`,
|
|
245
|
+
),
|
|
246
|
+
);
|
|
247
|
+
const row = rows[0];
|
|
248
|
+
if (!row || rows.length !== 1) throw new Error("Task-note replacement returned no receipt");
|
|
249
|
+
return TaskNoteReplacementResult.parse({
|
|
250
|
+
operationId: row.operation_id,
|
|
251
|
+
inputHash: row.input_hash,
|
|
252
|
+
replaces: {
|
|
253
|
+
noteId: row.replaced_note_id,
|
|
254
|
+
archivedVersion: row.replaced_note_version,
|
|
255
|
+
},
|
|
256
|
+
replacement: noteFromRow({
|
|
257
|
+
note_id: row.replacement_note_id,
|
|
258
|
+
root_session_id: row.root_session_id,
|
|
259
|
+
kind: row.replacement_kind,
|
|
260
|
+
note_text: row.replacement_text,
|
|
261
|
+
status: row.replacement_status,
|
|
262
|
+
version: row.replacement_version,
|
|
263
|
+
expires_at: row.replacement_expires_at,
|
|
264
|
+
created_at: row.replacement_created_at,
|
|
265
|
+
updated_at: row.replacement_updated_at,
|
|
266
|
+
archived_at: row.replacement_archived_at,
|
|
267
|
+
actor_kind: row.replacement_actor_kind,
|
|
268
|
+
source_session_id: row.replacement_source_session_id,
|
|
269
|
+
source_turn_id: row.replacement_source_turn_id,
|
|
270
|
+
}),
|
|
271
|
+
replayed: row.replayed,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
153
275
|
export async function listTaskNotes(db: Database, input: ListTaskNotesInput) {
|
|
154
276
|
assertAttemptClaims(input);
|
|
155
277
|
const limit = input.limit ?? TASK_NOTE_LIST_DEFAULT_LIMIT;
|
package/src/turn-initiator.ts
CHANGED
|
@@ -16,6 +16,8 @@ export const UNATTRIBUTED_LEGACY_INITIATOR: TurnInitiator = {
|
|
|
16
16
|
export type FrozenTurnInitiator = {
|
|
17
17
|
initiator: TurnInitiator;
|
|
18
18
|
context: TurnInitiatorContext;
|
|
19
|
+
/** Exact causal human frozen only after the caller/attempt authority is validated. */
|
|
20
|
+
initiatingHumanSubjectId?: string | null;
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
const MAX_AGENT_PROVENANCE_HOPS = 32;
|
|
@@ -100,6 +102,7 @@ export async function frozenInitiatorForCommandActor(
|
|
|
100
102
|
...(actor.subjectLabel ? { label: actor.subjectLabel } : {}),
|
|
101
103
|
},
|
|
102
104
|
context: { ...(actor.context ?? {}) },
|
|
105
|
+
initiatingHumanSubjectId: null,
|
|
103
106
|
};
|
|
104
107
|
}
|
|
105
108
|
if (actor.type !== "agent_attempt") {
|
|
@@ -110,6 +113,7 @@ export async function frozenInitiatorForCommandActor(
|
|
|
110
113
|
...(subjectLabel ? { label: subjectLabel } : {}),
|
|
111
114
|
},
|
|
112
115
|
context: {},
|
|
116
|
+
initiatingHumanSubjectId: actor.subjectId,
|
|
113
117
|
};
|
|
114
118
|
}
|
|
115
119
|
|
|
@@ -118,6 +122,7 @@ export async function frozenInitiatorForCommandActor(
|
|
|
118
122
|
initiatorKind: schema.sessionTurns.initiatorKind,
|
|
119
123
|
initiatorSubjectId: schema.sessionTurns.initiatorSubjectId,
|
|
120
124
|
initiatorContext: schema.sessionTurns.initiatorContext,
|
|
125
|
+
initiatingHumanSubjectId: schema.sessionTurns.initiatingHumanSubjectId,
|
|
121
126
|
})
|
|
122
127
|
.from(schema.sessionTurns)
|
|
123
128
|
.where(
|
|
@@ -151,5 +156,8 @@ export async function frozenInitiatorForCommandActor(
|
|
|
151
156
|
via: clipped,
|
|
152
157
|
...(hops.length > clipped.length ? { viaTruncated: true } : {}),
|
|
153
158
|
},
|
|
159
|
+
initiatingHumanSubjectId:
|
|
160
|
+
turn.initiatingHumanSubjectId ??
|
|
161
|
+
(turn.initiatorKind === "subject" ? turn.initiatorSubjectId : null),
|
|
154
162
|
};
|
|
155
163
|
}
|