@opengeni/db 1.0.1 → 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.
- 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-4SR4HKKA.js → chunk-2EH4WRHL.js} +19 -11
- package/dist/chunk-2EH4WRHL.js.map +1 -0
- package/dist/{chunk-CUPM3FGB.js → chunk-2PRS4J5Q.js} +3 -3
- package/dist/chunk-6HMM2R5T.js +390 -0
- package/dist/chunk-6HMM2R5T.js.map +1 -0
- package/dist/{chunk-ZWREYEWA.js → chunk-AZHW7R5V.js} +56 -11
- package/dist/chunk-AZHW7R5V.js.map +1 -0
- package/dist/{chunk-LTG3S6ZY.js → chunk-E6CLMKEE.js} +2 -2
- package/dist/{chunk-6ZYKCRFO.js → chunk-KRLPEMLH.js} +7591 -4417
- package/dist/chunk-KRLPEMLH.js.map +1 -0
- package/dist/chunk-NAB6FKFN.js +516 -0
- package/dist/chunk-NAB6FKFN.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-UZNXG44K.js +4508 -0
- package/dist/chunk-UZNXG44K.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 +85 -0
- package/dist/connection-token-resolver.d.ts +30 -1
- package/dist/database.d.ts +23 -4
- 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 +1606 -81
- package/dist/index.js +21898 -8147
- 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 +29 -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 +43 -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 +268 -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 +28 -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/drizzle/0342_slack_route_prompt_single_pending.sql +32 -0
- package/drizzle/0343_personal_document_force_rls_lock_repair.sql +146 -0
- package/drizzle/0344_private_session_visibility_transition_gate.sql +85 -0
- package/drizzle/0345_tenant_scoped_session_tenancy_fence.sql +2839 -0
- package/drizzle/0346_document_migration_audit_surface.sql +454 -0
- package/drizzle/0347_connection_authority_convergence_evidence.sql +396 -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 +167 -0
- package/src/connection-token-resolver.ts +263 -31
- package/src/database.ts +87 -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 +11676 -1550
- 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 +995 -0
- package/src/pr-review.ts +890 -0
- package/src/preference-registry.ts +31 -1
- package/src/provision-roles.ts +905 -6
- package/src/runtime-posture-cli.ts +2 -0
- package/src/runtime-posture.ts +1317 -72
- package/src/schema.ts +3316 -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 +441 -85
- package/src/session-realtime-context.ts +4 -6
- package/src/session-realtime-ledger.ts +28 -14
- package/src/session-realtime-mirror.ts +1 -1
- package/src/session-tenancy.ts +410 -49
- package/src/session-tool-call-settlement.ts +38 -29
- package/src/slack-routing-personal-workspace.ts +67 -0
- package/src/slack-routing.ts +867 -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 +138 -11
- 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-CUPM3FGB.js.map → chunk-2PRS4J5Q.js.map} +0 -0
- /package/dist/{chunk-LTG3S6ZY.js.map → chunk-E6CLMKEE.js.map} +0 -0
|
@@ -0,0 +1,1170 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
AGENT_AUTHORED_INSTRUCTION_POLICY_CONTENT_MAX_CHARS,
|
|
4
|
+
AGENT_AUTHORED_PREFERENCE_CONTENT_MAX_CHARS,
|
|
5
|
+
CompanyBrainGovernedWriteAttempt,
|
|
6
|
+
CompanyBrainGovernedWriteReceipt,
|
|
7
|
+
CompanyBrainGovernedWriteRequest,
|
|
8
|
+
PREFERENCE_REGISTRY_DESCRIPTOR_DESCRIPTION_MAX_CHARS,
|
|
9
|
+
PREFERENCE_REGISTRY_TITLE_MAX_CHARS,
|
|
10
|
+
agentAuthoredDurableTextTooLongMessage,
|
|
11
|
+
type CompanyBrainGovernedWriteReceipt as CompanyBrainGovernedWriteReceiptType,
|
|
12
|
+
type CompanyBrainGovernedWriteRequest as CompanyBrainGovernedWriteRequestType,
|
|
13
|
+
type ScopedKnowledgeActor,
|
|
14
|
+
} from "@opengeni/contracts";
|
|
15
|
+
import { and, eq, inArray, sql } from "drizzle-orm";
|
|
16
|
+
import type { Database } from "./database";
|
|
17
|
+
import { rawRows, setSubjectRlsContext, withRlsContext } from "./database";
|
|
18
|
+
import { sanitizePreferenceDescriptorText } from "./preference-registry";
|
|
19
|
+
import {
|
|
20
|
+
appendKnowledgeClaim,
|
|
21
|
+
appendKnowledgeClaimReview,
|
|
22
|
+
createKnowledgeChangeProposal,
|
|
23
|
+
linkKnowledgeClaims,
|
|
24
|
+
scopedKnowledgeInputHash,
|
|
25
|
+
ScopedKnowledgeAuthorityError,
|
|
26
|
+
ScopedKnowledgeInvalidOperationError,
|
|
27
|
+
upsertKnowledgeEntity,
|
|
28
|
+
upsertKnowledgeFact,
|
|
29
|
+
} from "./scoped-knowledge";
|
|
30
|
+
import * as schema from "./schema";
|
|
31
|
+
import { createWorkspaceInstructionPolicyKnowledgeProposal } from "./workspace-instruction-policies";
|
|
32
|
+
|
|
33
|
+
export class CompanyBrainGovernedWriteAuthorityError extends Error {
|
|
34
|
+
readonly name = "CompanyBrainGovernedWriteAuthorityError";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class CompanyBrainGovernedWriteInvalidOperationError extends Error {
|
|
38
|
+
readonly name = "CompanyBrainGovernedWriteInvalidOperationError";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type AttemptAuthority = CompanyBrainGovernedWriteAttempt & {
|
|
42
|
+
initiatingHumanSubjectId: string;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
type WorkspaceEvidence = {
|
|
46
|
+
claimId: string;
|
|
47
|
+
evidenceId: string;
|
|
48
|
+
confidenceBps: number;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
type TaskNotePromotionSource = {
|
|
52
|
+
noteId: string;
|
|
53
|
+
rootSessionId: string;
|
|
54
|
+
noteVersion: 1;
|
|
55
|
+
noteText: string;
|
|
56
|
+
noteTextHash: string;
|
|
57
|
+
noteCreatedAt: string;
|
|
58
|
+
initiatingHumanSubjectId: string;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
type TaskNotePromotionRequest = Extract<
|
|
62
|
+
CompanyBrainGovernedWriteRequestType,
|
|
63
|
+
{
|
|
64
|
+
kind:
|
|
65
|
+
| "promote_task_note_knowledge"
|
|
66
|
+
| "promote_task_note_instruction_policy"
|
|
67
|
+
| "promote_task_note_preference";
|
|
68
|
+
}
|
|
69
|
+
>;
|
|
70
|
+
|
|
71
|
+
type InstructionPolicyProposalRequest = Extract<
|
|
72
|
+
CompanyBrainGovernedWriteRequestType,
|
|
73
|
+
{ kind: "propose_instruction_policy" | "promote_task_note_instruction_policy" }
|
|
74
|
+
>;
|
|
75
|
+
|
|
76
|
+
type PreferenceProposalRequest = Extract<
|
|
77
|
+
CompanyBrainGovernedWriteRequestType,
|
|
78
|
+
{ kind: "propose_preference" | "promote_task_note_preference" }
|
|
79
|
+
>;
|
|
80
|
+
|
|
81
|
+
type TaskNoteKnowledgeMaterialization = WorkspaceEvidence & {
|
|
82
|
+
reviewId: string;
|
|
83
|
+
source: TaskNotePromotionSource;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
type NormalizedPreferenceProposal = {
|
|
87
|
+
stableKey: string;
|
|
88
|
+
title: string;
|
|
89
|
+
description: string;
|
|
90
|
+
content: string;
|
|
91
|
+
precedenceRank: number;
|
|
92
|
+
conflictStrategy: "override" | "merge" | "reject" | "inform";
|
|
93
|
+
conflictsWith: string[];
|
|
94
|
+
expiresAt: string | null;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
function isTaskNotePromotion(
|
|
98
|
+
request: CompanyBrainGovernedWriteRequestType,
|
|
99
|
+
): request is TaskNotePromotionRequest {
|
|
100
|
+
return (
|
|
101
|
+
request.kind === "promote_task_note_knowledge" ||
|
|
102
|
+
request.kind === "promote_task_note_instruction_policy" ||
|
|
103
|
+
request.kind === "promote_task_note_preference"
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function derivedOperationId(operationId: string, label: string): string {
|
|
108
|
+
const bytes = Buffer.from(
|
|
109
|
+
createHash("sha256")
|
|
110
|
+
.update(`company-brain-governed-write:v1:${operationId}:${label}`, "utf8")
|
|
111
|
+
.digest("hex")
|
|
112
|
+
.slice(0, 32),
|
|
113
|
+
"hex",
|
|
114
|
+
);
|
|
115
|
+
bytes[6] = (bytes[6]! & 0x0f) | 0x50;
|
|
116
|
+
bytes[8] = (bytes[8]! & 0x3f) | 0x80;
|
|
117
|
+
const hex = bytes.toString("hex");
|
|
118
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function preferenceProposalContent(request: PreferenceProposalRequest, content: string): string {
|
|
122
|
+
return JSON.stringify(normalizePreferenceProposal(request, content));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function normalizePreferenceProposal(
|
|
126
|
+
request: PreferenceProposalRequest,
|
|
127
|
+
content: string,
|
|
128
|
+
): NormalizedPreferenceProposal {
|
|
129
|
+
const title = sanitizePreferenceDescriptorText(request.title)
|
|
130
|
+
.slice(0, PREFERENCE_REGISTRY_TITLE_MAX_CHARS)
|
|
131
|
+
.trim();
|
|
132
|
+
const description = sanitizePreferenceDescriptorText(request.description)
|
|
133
|
+
.slice(0, PREFERENCE_REGISTRY_DESCRIPTOR_DESCRIPTION_MAX_CHARS)
|
|
134
|
+
.trim();
|
|
135
|
+
if (!title || !description) {
|
|
136
|
+
throw new CompanyBrainGovernedWriteInvalidOperationError(
|
|
137
|
+
"Preference proposal title and description must contain visible plain text",
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
stableKey: request.stableKey,
|
|
142
|
+
title,
|
|
143
|
+
description,
|
|
144
|
+
content,
|
|
145
|
+
precedenceRank: request.precedenceRank,
|
|
146
|
+
conflictStrategy: request.conflictStrategy,
|
|
147
|
+
conflictsWith: [...new Set(request.conflictsWith)].sort(),
|
|
148
|
+
expiresAt: request.expiresAt ? new Date(request.expiresAt).toISOString() : null,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async function withCompanyBrainGovernedWriteAuthority<T, P>(
|
|
153
|
+
db: Database,
|
|
154
|
+
attempt: CompanyBrainGovernedWriteAttempt,
|
|
155
|
+
destinationWorkspaceLock: "key_share" | "update",
|
|
156
|
+
prelock: (db: Database) => Promise<P>,
|
|
157
|
+
fn: (db: Database, authority: AttemptAuthority, prelocked: P) => Promise<T>,
|
|
158
|
+
): Promise<T> {
|
|
159
|
+
return await withRlsContext(
|
|
160
|
+
db,
|
|
161
|
+
{ accountId: attempt.accountId, workspaceId: attempt.workspaceId },
|
|
162
|
+
async (scopedDb) => {
|
|
163
|
+
// Instruction-policy lifecycle writes serialize on the workspace row.
|
|
164
|
+
// Acquire that destination lock before Task-note root/session locks so a
|
|
165
|
+
// later nested lifecycle call only re-enters a lock already held by this
|
|
166
|
+
// transaction. Taking KEY SHARE here and upgrading after distinct roots
|
|
167
|
+
// are locked lets two valid promotions deadlock each other.
|
|
168
|
+
if (destinationWorkspaceLock === "update") {
|
|
169
|
+
const lockedWorkspace = await rawRows<{ id: string }>(
|
|
170
|
+
scopedDb,
|
|
171
|
+
sql`
|
|
172
|
+
SELECT workspace.id
|
|
173
|
+
FROM workspaces workspace
|
|
174
|
+
WHERE workspace.id = ${attempt.workspaceId}::uuid
|
|
175
|
+
AND workspace.account_id = ${attempt.accountId}::uuid
|
|
176
|
+
FOR UPDATE OF workspace
|
|
177
|
+
`,
|
|
178
|
+
);
|
|
179
|
+
if (!lockedWorkspace[0]) {
|
|
180
|
+
throw new CompanyBrainGovernedWriteAuthorityError(
|
|
181
|
+
"Governed Company Brain write workspace is unavailable",
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Tree-scoped authorities own the root/current-session lock prefix. Run
|
|
186
|
+
// them before the generic current-session locks below to avoid inverting
|
|
187
|
+
// the canonical Task-note lifecycle order.
|
|
188
|
+
const prelocked = await prelock(scopedDb);
|
|
189
|
+
const rows = await rawRows<{ initiating_human_subject_id: string }>(
|
|
190
|
+
scopedDb,
|
|
191
|
+
sql`
|
|
192
|
+
WITH locked_workspace AS MATERIALIZED (
|
|
193
|
+
SELECT workspace.id, workspace.account_id
|
|
194
|
+
FROM workspaces workspace
|
|
195
|
+
WHERE workspace.id = ${attempt.workspaceId}::uuid
|
|
196
|
+
AND workspace.account_id = ${attempt.accountId}::uuid
|
|
197
|
+
FOR KEY SHARE OF workspace
|
|
198
|
+
), locked_session AS MATERIALIZED (
|
|
199
|
+
SELECT session.id, session.account_id, session.workspace_id, session.active_turn_id
|
|
200
|
+
FROM sessions session
|
|
201
|
+
JOIN locked_workspace workspace
|
|
202
|
+
ON workspace.id = session.workspace_id
|
|
203
|
+
AND workspace.account_id = session.account_id
|
|
204
|
+
WHERE session.id = ${attempt.sessionId}::uuid
|
|
205
|
+
AND session.active_turn_id = ${attempt.turnId}::uuid
|
|
206
|
+
FOR SHARE OF session
|
|
207
|
+
), locked_turn AS MATERIALIZED (
|
|
208
|
+
SELECT turn.id, turn.account_id, turn.workspace_id, turn.session_id,
|
|
209
|
+
turn.active_attempt_id, turn.execution_generation,
|
|
210
|
+
coalesce(
|
|
211
|
+
turn.initiating_human_subject_id,
|
|
212
|
+
case when turn.initiator_kind = 'subject' then turn.initiator_subject_id end
|
|
213
|
+
) as initiating_human_subject_id
|
|
214
|
+
FROM session_turns turn
|
|
215
|
+
JOIN locked_session session
|
|
216
|
+
ON session.id = turn.session_id
|
|
217
|
+
AND session.workspace_id = turn.workspace_id
|
|
218
|
+
AND session.account_id = turn.account_id
|
|
219
|
+
WHERE turn.id = ${attempt.turnId}::uuid
|
|
220
|
+
AND turn.active_attempt_id = ${attempt.attemptId}::uuid
|
|
221
|
+
AND turn.execution_generation = ${attempt.executionGeneration}
|
|
222
|
+
AND turn.status IN ('running', 'requires_action', 'recovering', 'waiting_capacity')
|
|
223
|
+
AND length(btrim(coalesce(
|
|
224
|
+
turn.initiating_human_subject_id,
|
|
225
|
+
case when turn.initiator_kind = 'subject' then turn.initiator_subject_id end
|
|
226
|
+
))) BETWEEN 1 AND 1024
|
|
227
|
+
FOR SHARE OF turn
|
|
228
|
+
), locked_attempt AS MATERIALIZED (
|
|
229
|
+
SELECT attempt.id, attempt.account_id, attempt.workspace_id,
|
|
230
|
+
attempt.session_id, attempt.turn_id, attempt.execution_generation
|
|
231
|
+
FROM session_turn_attempts attempt
|
|
232
|
+
JOIN locked_turn turn
|
|
233
|
+
ON turn.id = attempt.turn_id
|
|
234
|
+
AND turn.session_id = attempt.session_id
|
|
235
|
+
AND turn.workspace_id = attempt.workspace_id
|
|
236
|
+
AND turn.account_id = attempt.account_id
|
|
237
|
+
WHERE attempt.id = ${attempt.attemptId}::uuid
|
|
238
|
+
AND attempt.execution_generation = ${attempt.executionGeneration}
|
|
239
|
+
AND attempt.state IN ('claimed', 'running')
|
|
240
|
+
FOR SHARE OF attempt
|
|
241
|
+
)
|
|
242
|
+
SELECT turn.initiating_human_subject_id
|
|
243
|
+
FROM locked_workspace workspace
|
|
244
|
+
JOIN locked_session session ON true
|
|
245
|
+
JOIN locked_turn turn ON true
|
|
246
|
+
JOIN locked_attempt attempt ON true
|
|
247
|
+
WHERE workspace.account_id = attempt.account_id
|
|
248
|
+
AND workspace.id = attempt.workspace_id
|
|
249
|
+
AND session.id = attempt.session_id
|
|
250
|
+
AND turn.id = attempt.turn_id
|
|
251
|
+
`,
|
|
252
|
+
);
|
|
253
|
+
const initiatingHumanSubjectId = rows[0]?.initiating_human_subject_id;
|
|
254
|
+
if (!initiatingHumanSubjectId) {
|
|
255
|
+
throw new CompanyBrainGovernedWriteAuthorityError(
|
|
256
|
+
"Governed Company Brain writes require the exact current attempt, generation, immutable human initiator, and no live interruption",
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
// Lock acquisition may wait behind Pause/Steer. Under READ COMMITTED, a
|
|
260
|
+
// NOT EXISTS evaluated in that same statement can retain its pre-wait
|
|
261
|
+
// snapshot and miss the newly committed interruption. Recheck in a fresh
|
|
262
|
+
// statement after all canonical rows are locked; interruption writers now
|
|
263
|
+
// cannot advance until this transaction completes.
|
|
264
|
+
const revalidated = await rawRows<{ id: string }>(
|
|
265
|
+
scopedDb,
|
|
266
|
+
sql`
|
|
267
|
+
SELECT attempt.id
|
|
268
|
+
FROM sessions session
|
|
269
|
+
JOIN session_turns turn
|
|
270
|
+
ON turn.account_id = session.account_id
|
|
271
|
+
AND turn.workspace_id = session.workspace_id
|
|
272
|
+
AND turn.session_id = session.id
|
|
273
|
+
JOIN session_turn_attempts attempt
|
|
274
|
+
ON attempt.account_id = turn.account_id
|
|
275
|
+
AND attempt.workspace_id = turn.workspace_id
|
|
276
|
+
AND attempt.session_id = turn.session_id
|
|
277
|
+
AND attempt.turn_id = turn.id
|
|
278
|
+
WHERE session.account_id = ${attempt.accountId}::uuid
|
|
279
|
+
AND session.workspace_id = ${attempt.workspaceId}::uuid
|
|
280
|
+
AND session.id = ${attempt.sessionId}::uuid
|
|
281
|
+
AND session.active_turn_id = ${attempt.turnId}::uuid
|
|
282
|
+
AND turn.id = ${attempt.turnId}::uuid
|
|
283
|
+
AND turn.active_attempt_id = ${attempt.attemptId}::uuid
|
|
284
|
+
AND turn.execution_generation = ${attempt.executionGeneration}
|
|
285
|
+
AND turn.status IN ('running', 'requires_action', 'recovering', 'waiting_capacity')
|
|
286
|
+
AND attempt.id = ${attempt.attemptId}::uuid
|
|
287
|
+
AND attempt.execution_generation = ${attempt.executionGeneration}
|
|
288
|
+
AND attempt.state IN ('claimed', 'running')
|
|
289
|
+
AND NOT EXISTS (
|
|
290
|
+
SELECT 1
|
|
291
|
+
FROM session_attempt_interruptions interruption
|
|
292
|
+
WHERE interruption.workspace_id = attempt.workspace_id
|
|
293
|
+
AND interruption.attempt_id = attempt.id
|
|
294
|
+
AND interruption.state IN ('pending', 'delivered', 'acknowledged')
|
|
295
|
+
)
|
|
296
|
+
`,
|
|
297
|
+
);
|
|
298
|
+
if (!revalidated[0]) {
|
|
299
|
+
throw new CompanyBrainGovernedWriteAuthorityError(
|
|
300
|
+
"Governed Company Brain write authority changed while admission was waiting",
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
await setSubjectRlsContext(scopedDb, initiatingHumanSubjectId);
|
|
304
|
+
return await fn(scopedDb, { ...attempt, initiatingHumanSubjectId }, prelocked);
|
|
305
|
+
},
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
async function requireWorkspaceEvidence(
|
|
310
|
+
db: Database,
|
|
311
|
+
authority: AttemptAuthority,
|
|
312
|
+
claimId: string,
|
|
313
|
+
evidenceId: string,
|
|
314
|
+
replacesClaimId: string | null,
|
|
315
|
+
): Promise<WorkspaceEvidence> {
|
|
316
|
+
const claimIds = replacesClaimId === null ? [claimId] : [claimId, replacesClaimId];
|
|
317
|
+
const [claims, evidenceRows] = await Promise.all([
|
|
318
|
+
db
|
|
319
|
+
.select()
|
|
320
|
+
.from(schema.knowledgeClaims)
|
|
321
|
+
.where(
|
|
322
|
+
and(
|
|
323
|
+
eq(schema.knowledgeClaims.accountId, authority.accountId),
|
|
324
|
+
inArray(schema.knowledgeClaims.id, claimIds),
|
|
325
|
+
),
|
|
326
|
+
),
|
|
327
|
+
db
|
|
328
|
+
.select()
|
|
329
|
+
.from(schema.knowledgeClaimEvidence)
|
|
330
|
+
.where(
|
|
331
|
+
and(
|
|
332
|
+
eq(schema.knowledgeClaimEvidence.accountId, authority.accountId),
|
|
333
|
+
eq(schema.knowledgeClaimEvidence.id, evidenceId),
|
|
334
|
+
),
|
|
335
|
+
)
|
|
336
|
+
.limit(1),
|
|
337
|
+
]);
|
|
338
|
+
const claim = claims.find((candidate) => candidate.id === claimId);
|
|
339
|
+
const replaced = replacesClaimId
|
|
340
|
+
? claims.find((candidate) => candidate.id === replacesClaimId)
|
|
341
|
+
: null;
|
|
342
|
+
const evidence = evidenceRows[0];
|
|
343
|
+
const isExactWorkspaceClaim = (candidate: typeof claim | null): boolean =>
|
|
344
|
+
candidate != null &&
|
|
345
|
+
candidate.scopeKind === "workspace" &&
|
|
346
|
+
candidate.scopeWorkspaceId === authority.workspaceId &&
|
|
347
|
+
candidate.scopeSubjectId === null;
|
|
348
|
+
if (
|
|
349
|
+
!isExactWorkspaceClaim(claim) ||
|
|
350
|
+
!evidence ||
|
|
351
|
+
evidence.claimId !== claimId ||
|
|
352
|
+
evidence.polarity !== "supports" ||
|
|
353
|
+
evidence.scopeKind !== "workspace" ||
|
|
354
|
+
evidence.scopeWorkspaceId !== authority.workspaceId ||
|
|
355
|
+
evidence.scopeSubjectId !== null
|
|
356
|
+
) {
|
|
357
|
+
throw new CompanyBrainGovernedWriteInvalidOperationError(
|
|
358
|
+
"Governed writes require exact supporting evidence for a workspace-local Knowledge claim",
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
if (
|
|
362
|
+
replacesClaimId !== null &&
|
|
363
|
+
(replacesClaimId === claimId || !isExactWorkspaceClaim(replaced))
|
|
364
|
+
) {
|
|
365
|
+
throw new CompanyBrainGovernedWriteInvalidOperationError(
|
|
366
|
+
"Knowledge correction requires a different replaced claim in the same workspace scope",
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
return { claimId, evidenceId, confidenceBps: claim!.confidenceBps };
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
async function createWorkspacePreferenceProposalForAttempt(
|
|
373
|
+
db: Database,
|
|
374
|
+
authority: AttemptAuthority,
|
|
375
|
+
request: PreferenceProposalRequest,
|
|
376
|
+
content: string,
|
|
377
|
+
knowledgeProposalId: string,
|
|
378
|
+
inputHash: string,
|
|
379
|
+
): Promise<{ preferenceId: string; revisionId: string }> {
|
|
380
|
+
const normalized = normalizePreferenceProposal(request, content);
|
|
381
|
+
const [result] = await rawRows<{ preferenceId: string; revisionId: string }>(
|
|
382
|
+
db,
|
|
383
|
+
sql`
|
|
384
|
+
SELECT
|
|
385
|
+
proposal.preference_id AS "preferenceId",
|
|
386
|
+
proposal.revision_id AS "revisionId"
|
|
387
|
+
FROM preference_registry_create_knowledge_proposal_for_attempt(
|
|
388
|
+
${authority.accountId}::uuid,
|
|
389
|
+
${authority.workspaceId}::uuid,
|
|
390
|
+
${authority.sessionId}::uuid,
|
|
391
|
+
${authority.turnId}::uuid,
|
|
392
|
+
${authority.attemptId}::uuid,
|
|
393
|
+
${authority.executionGeneration},
|
|
394
|
+
${request.operationId}::uuid,
|
|
395
|
+
${inputHash},
|
|
396
|
+
${knowledgeProposalId}::uuid,
|
|
397
|
+
${normalized.stableKey},
|
|
398
|
+
${normalized.title},
|
|
399
|
+
${normalized.description},
|
|
400
|
+
${normalized.content},
|
|
401
|
+
${normalized.precedenceRank},
|
|
402
|
+
${normalized.conflictStrategy},
|
|
403
|
+
${JSON.stringify(normalized.conflictsWith)}::jsonb,
|
|
404
|
+
${normalized.expiresAt}::timestamptz,
|
|
405
|
+
${request.reason}
|
|
406
|
+
) proposal
|
|
407
|
+
`,
|
|
408
|
+
);
|
|
409
|
+
if (!result) throw new Error("Preference Knowledge proposal returned no durable receipt");
|
|
410
|
+
return result;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function receipt(
|
|
414
|
+
input: Omit<CompanyBrainGovernedWriteReceiptType, "outcome" | "effectiveBoundary" | "rollback">,
|
|
415
|
+
): CompanyBrainGovernedWriteReceiptType {
|
|
416
|
+
return CompanyBrainGovernedWriteReceipt.parse({
|
|
417
|
+
...input,
|
|
418
|
+
outcome: "proposed",
|
|
419
|
+
effectiveBoundary: "human_review_required",
|
|
420
|
+
rollback: { supported: false, mechanism: "not_applicable_proposal_only" },
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
async function resolveTaskNotePromotionSource(
|
|
425
|
+
db: Database,
|
|
426
|
+
authority: CompanyBrainGovernedWriteAttempt,
|
|
427
|
+
noteId: string,
|
|
428
|
+
expectedNoteVersion: 1,
|
|
429
|
+
evidenceOperationId: string,
|
|
430
|
+
claimOperationId: string,
|
|
431
|
+
actorSubjectId: string,
|
|
432
|
+
): Promise<TaskNotePromotionSource> {
|
|
433
|
+
const [row] = await rawRows<{
|
|
434
|
+
noteId: string;
|
|
435
|
+
rootSessionId: string;
|
|
436
|
+
noteVersion: number;
|
|
437
|
+
noteText: string;
|
|
438
|
+
noteTextHash: string;
|
|
439
|
+
noteCreatedAt: Date | string;
|
|
440
|
+
initiatingHumanSubjectId: string;
|
|
441
|
+
}>(
|
|
442
|
+
db,
|
|
443
|
+
sql`
|
|
444
|
+
SELECT
|
|
445
|
+
source.note_id AS "noteId",
|
|
446
|
+
source.root_session_id AS "rootSessionId",
|
|
447
|
+
source.note_version AS "noteVersion",
|
|
448
|
+
source.note_text AS "noteText",
|
|
449
|
+
source.note_text_hash AS "noteTextHash",
|
|
450
|
+
source.note_created_at AS "noteCreatedAt",
|
|
451
|
+
source.initiating_human_subject_id AS "initiatingHumanSubjectId"
|
|
452
|
+
FROM resolve_task_note_knowledge_promotion_source(
|
|
453
|
+
${authority.accountId}::uuid,
|
|
454
|
+
${authority.workspaceId}::uuid,
|
|
455
|
+
${authority.sessionId}::uuid,
|
|
456
|
+
${authority.turnId}::uuid,
|
|
457
|
+
${authority.attemptId}::uuid,
|
|
458
|
+
${authority.executionGeneration},
|
|
459
|
+
${noteId}::uuid,
|
|
460
|
+
${expectedNoteVersion},
|
|
461
|
+
${evidenceOperationId},
|
|
462
|
+
${claimOperationId},
|
|
463
|
+
${actorSubjectId}
|
|
464
|
+
) source
|
|
465
|
+
`,
|
|
466
|
+
);
|
|
467
|
+
if (!row || row.noteVersion !== 1) {
|
|
468
|
+
throw new CompanyBrainGovernedWriteAuthorityError(
|
|
469
|
+
"Task-note promotion source did not preserve exact attempt authority",
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
return {
|
|
473
|
+
noteId: row.noteId,
|
|
474
|
+
rootSessionId: row.rootSessionId,
|
|
475
|
+
noteVersion: 1,
|
|
476
|
+
noteText: row.noteText,
|
|
477
|
+
noteTextHash: row.noteTextHash,
|
|
478
|
+
noteCreatedAt: new Date(row.noteCreatedAt).toISOString(),
|
|
479
|
+
initiatingHumanSubjectId: row.initiatingHumanSubjectId,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
async function taskNotePromotionAlreadyMaterialized(
|
|
484
|
+
db: Database,
|
|
485
|
+
accountId: string,
|
|
486
|
+
operationId: string,
|
|
487
|
+
): Promise<boolean> {
|
|
488
|
+
const [row] = await db
|
|
489
|
+
.select({ id: schema.knowledgeClaimEvidence.id })
|
|
490
|
+
.from(schema.knowledgeClaimEvidence)
|
|
491
|
+
.where(
|
|
492
|
+
and(
|
|
493
|
+
eq(schema.knowledgeClaimEvidence.accountId, accountId),
|
|
494
|
+
eq(schema.knowledgeClaimEvidence.operationId, operationId),
|
|
495
|
+
),
|
|
496
|
+
)
|
|
497
|
+
.limit(1);
|
|
498
|
+
return row !== undefined;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
async function appendTaskNoteKnowledgeEvidence(
|
|
502
|
+
db: Database,
|
|
503
|
+
input: {
|
|
504
|
+
authority: AttemptAuthority;
|
|
505
|
+
operationId: string;
|
|
506
|
+
actor: ScopedKnowledgeActor;
|
|
507
|
+
claimId: string;
|
|
508
|
+
source: TaskNotePromotionSource;
|
|
509
|
+
},
|
|
510
|
+
): Promise<{ id: string }> {
|
|
511
|
+
const inputHash = scopedKnowledgeInputHash({
|
|
512
|
+
claimId: input.claimId,
|
|
513
|
+
taskNoteId: input.source.noteId,
|
|
514
|
+
taskNoteRootSessionId: input.source.rootSessionId,
|
|
515
|
+
taskNoteVersion: input.source.noteVersion,
|
|
516
|
+
contentHash: input.source.noteTextHash,
|
|
517
|
+
polarity: "supports",
|
|
518
|
+
actor: input.actor,
|
|
519
|
+
});
|
|
520
|
+
const [claim] = await db
|
|
521
|
+
.select()
|
|
522
|
+
.from(schema.knowledgeClaims)
|
|
523
|
+
.where(eq(schema.knowledgeClaims.id, input.claimId))
|
|
524
|
+
.limit(1);
|
|
525
|
+
if (
|
|
526
|
+
!claim ||
|
|
527
|
+
claim.accountId !== input.authority.accountId ||
|
|
528
|
+
claim.scopeKind !== "workspace" ||
|
|
529
|
+
claim.scopeWorkspaceId !== input.authority.workspaceId ||
|
|
530
|
+
claim.scopeSubjectId !== null
|
|
531
|
+
) {
|
|
532
|
+
throw new CompanyBrainGovernedWriteInvalidOperationError(
|
|
533
|
+
"Task-note promotion claim must remain in the source workspace",
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
const [created] = await db
|
|
537
|
+
.insert(schema.knowledgeClaimEvidence)
|
|
538
|
+
.values({
|
|
539
|
+
accountId: input.authority.accountId,
|
|
540
|
+
scopeKind: claim.scopeKind,
|
|
541
|
+
scopeWorkspaceId: claim.scopeWorkspaceId,
|
|
542
|
+
scopeSubjectId: claim.scopeSubjectId,
|
|
543
|
+
scopeKey: claim.scopeKey,
|
|
544
|
+
claimId: claim.id,
|
|
545
|
+
documentVersionId: null,
|
|
546
|
+
taskNoteId: input.source.noteId,
|
|
547
|
+
taskNoteRootSessionId: input.source.rootSessionId,
|
|
548
|
+
taskNoteVersion: input.source.noteVersion,
|
|
549
|
+
polarity: "supports",
|
|
550
|
+
documentChunkId: null,
|
|
551
|
+
chunkIndex: null,
|
|
552
|
+
locator: null,
|
|
553
|
+
quoteHash: null,
|
|
554
|
+
contentHash: input.source.noteTextHash,
|
|
555
|
+
operationId: input.operationId,
|
|
556
|
+
inputHash,
|
|
557
|
+
actorKind: input.actor.kind,
|
|
558
|
+
actorSubjectId: input.actor.subjectId,
|
|
559
|
+
initiatingHumanSubjectId: input.actor.initiatingHumanSubjectId,
|
|
560
|
+
})
|
|
561
|
+
.onConflictDoNothing()
|
|
562
|
+
.returning({ id: schema.knowledgeClaimEvidence.id });
|
|
563
|
+
if (created) return created;
|
|
564
|
+
const [replayed] = await db
|
|
565
|
+
.select({
|
|
566
|
+
id: schema.knowledgeClaimEvidence.id,
|
|
567
|
+
inputHash: schema.knowledgeClaimEvidence.inputHash,
|
|
568
|
+
})
|
|
569
|
+
.from(schema.knowledgeClaimEvidence)
|
|
570
|
+
.where(
|
|
571
|
+
and(
|
|
572
|
+
eq(schema.knowledgeClaimEvidence.accountId, input.authority.accountId),
|
|
573
|
+
eq(schema.knowledgeClaimEvidence.operationId, input.operationId),
|
|
574
|
+
),
|
|
575
|
+
)
|
|
576
|
+
.limit(1);
|
|
577
|
+
if (!replayed || replayed.inputHash !== inputHash) {
|
|
578
|
+
throw new CompanyBrainGovernedWriteInvalidOperationError(
|
|
579
|
+
"Task-note evidence operation was replayed with different immutable input",
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
return { id: replayed.id };
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
async function replayTaskNoteKnowledgeMaterialization(
|
|
586
|
+
db: Database,
|
|
587
|
+
authority: AttemptAuthority,
|
|
588
|
+
operationId: string,
|
|
589
|
+
topLevelInputHash: string,
|
|
590
|
+
): Promise<TaskNoteKnowledgeMaterialization | null> {
|
|
591
|
+
const evidenceOperationId = derivedOperationId(operationId, "task-note-evidence");
|
|
592
|
+
const [evidence] = await db
|
|
593
|
+
.select()
|
|
594
|
+
.from(schema.knowledgeClaimEvidence)
|
|
595
|
+
.where(
|
|
596
|
+
and(
|
|
597
|
+
eq(schema.knowledgeClaimEvidence.accountId, authority.accountId),
|
|
598
|
+
eq(schema.knowledgeClaimEvidence.operationId, evidenceOperationId),
|
|
599
|
+
),
|
|
600
|
+
)
|
|
601
|
+
.limit(1);
|
|
602
|
+
if (!evidence) return null;
|
|
603
|
+
const expectedActor = `service:company-brain-governed-write:${topLevelInputHash}`;
|
|
604
|
+
if (
|
|
605
|
+
evidence.actorSubjectId !== expectedActor ||
|
|
606
|
+
evidence.initiatingHumanSubjectId !== authority.initiatingHumanSubjectId ||
|
|
607
|
+
evidence.scopeKind !== "workspace" ||
|
|
608
|
+
evidence.scopeWorkspaceId !== authority.workspaceId ||
|
|
609
|
+
evidence.scopeSubjectId !== null ||
|
|
610
|
+
evidence.documentVersionId !== null ||
|
|
611
|
+
evidence.taskNoteId === null ||
|
|
612
|
+
evidence.taskNoteRootSessionId === null ||
|
|
613
|
+
evidence.taskNoteVersion !== 1
|
|
614
|
+
) {
|
|
615
|
+
throw new CompanyBrainGovernedWriteInvalidOperationError(
|
|
616
|
+
"Task-note promotion operation was replayed with different immutable input",
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
const [claim] = await db
|
|
620
|
+
.select()
|
|
621
|
+
.from(schema.knowledgeClaims)
|
|
622
|
+
.where(
|
|
623
|
+
and(
|
|
624
|
+
eq(schema.knowledgeClaims.accountId, authority.accountId),
|
|
625
|
+
eq(schema.knowledgeClaims.id, evidence.claimId),
|
|
626
|
+
),
|
|
627
|
+
)
|
|
628
|
+
.limit(1);
|
|
629
|
+
const [fact] = claim
|
|
630
|
+
? await db
|
|
631
|
+
.select()
|
|
632
|
+
.from(schema.knowledgeFacts)
|
|
633
|
+
.where(
|
|
634
|
+
and(
|
|
635
|
+
eq(schema.knowledgeFacts.accountId, authority.accountId),
|
|
636
|
+
eq(schema.knowledgeFacts.id, claim.factId),
|
|
637
|
+
),
|
|
638
|
+
)
|
|
639
|
+
.limit(1)
|
|
640
|
+
: [];
|
|
641
|
+
const noteText = fact?.objectValue;
|
|
642
|
+
if (
|
|
643
|
+
!claim ||
|
|
644
|
+
!fact ||
|
|
645
|
+
claim.extractionMethod !== "task-note-promotion-v1" ||
|
|
646
|
+
claim.scopeKind !== "workspace" ||
|
|
647
|
+
claim.scopeWorkspaceId !== authority.workspaceId ||
|
|
648
|
+
claim.scopeSubjectId !== null ||
|
|
649
|
+
claim.actorKind !== "service" ||
|
|
650
|
+
claim.actorSubjectId !== expectedActor ||
|
|
651
|
+
claim.initiatingHumanSubjectId !== authority.initiatingHumanSubjectId ||
|
|
652
|
+
fact.scopeKind !== "workspace" ||
|
|
653
|
+
fact.scopeWorkspaceId !== authority.workspaceId ||
|
|
654
|
+
fact.scopeSubjectId !== null ||
|
|
655
|
+
fact.actorKind !== "service" ||
|
|
656
|
+
fact.actorSubjectId !== expectedActor ||
|
|
657
|
+
fact.initiatingHumanSubjectId !== authority.initiatingHumanSubjectId ||
|
|
658
|
+
fact.objectKind !== "text" ||
|
|
659
|
+
typeof noteText !== "string" ||
|
|
660
|
+
createHash("sha256").update(noteText, "utf8").digest("hex") !== evidence.contentHash
|
|
661
|
+
) {
|
|
662
|
+
throw new CompanyBrainGovernedWriteInvalidOperationError(
|
|
663
|
+
"Task-note promotion Knowledge lineage was replayed with different immutable input",
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
const [review] = await db
|
|
667
|
+
.select()
|
|
668
|
+
.from(schema.knowledgeClaimReviews)
|
|
669
|
+
.where(
|
|
670
|
+
and(
|
|
671
|
+
eq(schema.knowledgeClaimReviews.accountId, authority.accountId),
|
|
672
|
+
eq(schema.knowledgeClaimReviews.operationId, derivedOperationId(operationId, "guard")),
|
|
673
|
+
eq(schema.knowledgeClaimReviews.claimId, evidence.claimId),
|
|
674
|
+
),
|
|
675
|
+
)
|
|
676
|
+
.limit(1);
|
|
677
|
+
if (
|
|
678
|
+
!review ||
|
|
679
|
+
review.scopeKind !== "workspace" ||
|
|
680
|
+
review.scopeWorkspaceId !== authority.workspaceId ||
|
|
681
|
+
review.scopeSubjectId !== null ||
|
|
682
|
+
review.state !== "proposed" ||
|
|
683
|
+
review.actorKind !== "service" ||
|
|
684
|
+
review.actorSubjectId !== expectedActor ||
|
|
685
|
+
review.initiatingHumanSubjectId !== authority.initiatingHumanSubjectId
|
|
686
|
+
) {
|
|
687
|
+
throw new CompanyBrainGovernedWriteInvalidOperationError(
|
|
688
|
+
"Task-note promotion evidence has no matching proposal review receipt",
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
return {
|
|
692
|
+
claimId: evidence.claimId,
|
|
693
|
+
evidenceId: evidence.id,
|
|
694
|
+
confidenceBps: claim.confidenceBps,
|
|
695
|
+
reviewId: review.id,
|
|
696
|
+
source: {
|
|
697
|
+
noteId: evidence.taskNoteId,
|
|
698
|
+
rootSessionId: evidence.taskNoteRootSessionId,
|
|
699
|
+
noteVersion: 1,
|
|
700
|
+
noteText,
|
|
701
|
+
noteTextHash: evidence.contentHash,
|
|
702
|
+
noteCreatedAt: new Date(claim.effectiveAt).toISOString(),
|
|
703
|
+
initiatingHumanSubjectId: authority.initiatingHumanSubjectId,
|
|
704
|
+
},
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
async function materializeTaskNoteKnowledge(
|
|
709
|
+
db: Database,
|
|
710
|
+
input: {
|
|
711
|
+
authority: AttemptAuthority;
|
|
712
|
+
request: TaskNotePromotionRequest;
|
|
713
|
+
actor: ScopedKnowledgeActor;
|
|
714
|
+
source: TaskNotePromotionSource;
|
|
715
|
+
evidenceOperationId: string;
|
|
716
|
+
claimOperationId: string;
|
|
717
|
+
},
|
|
718
|
+
): Promise<TaskNoteKnowledgeMaterialization> {
|
|
719
|
+
const entity = await upsertKnowledgeEntity(db, {
|
|
720
|
+
accountId: input.authority.accountId,
|
|
721
|
+
workspaceId: input.authority.workspaceId,
|
|
722
|
+
scope: {
|
|
723
|
+
kind: "workspace",
|
|
724
|
+
workspaceId: input.authority.workspaceId,
|
|
725
|
+
subjectId: null,
|
|
726
|
+
},
|
|
727
|
+
operationId: derivedOperationId(input.request.operationId, "task-note-entity"),
|
|
728
|
+
actor: input.actor,
|
|
729
|
+
entityType: input.request.entityType,
|
|
730
|
+
normalizedKey: input.request.normalizedKey,
|
|
731
|
+
displayName: input.request.displayName,
|
|
732
|
+
});
|
|
733
|
+
const fact = await upsertKnowledgeFact(db, {
|
|
734
|
+
accountId: input.authority.accountId,
|
|
735
|
+
workspaceId: input.authority.workspaceId,
|
|
736
|
+
operationId: derivedOperationId(input.request.operationId, "task-note-fact"),
|
|
737
|
+
actor: input.actor,
|
|
738
|
+
subjectEntityId: entity.id,
|
|
739
|
+
predicateKey: input.request.predicateKey,
|
|
740
|
+
object: { kind: "text", value: input.source.noteText },
|
|
741
|
+
});
|
|
742
|
+
const claim = await appendKnowledgeClaim(db, {
|
|
743
|
+
accountId: input.authority.accountId,
|
|
744
|
+
workspaceId: input.authority.workspaceId,
|
|
745
|
+
operationId: input.claimOperationId,
|
|
746
|
+
actor: input.actor,
|
|
747
|
+
factId: fact.id,
|
|
748
|
+
origin: "inferred",
|
|
749
|
+
confidenceBps: input.request.confidenceBps,
|
|
750
|
+
effectiveAt: input.source.noteCreatedAt,
|
|
751
|
+
expiresAt: null,
|
|
752
|
+
extractionMethod: "task-note-promotion-v1",
|
|
753
|
+
extractionMetadata: {
|
|
754
|
+
taskNoteId: input.source.noteId,
|
|
755
|
+
taskNoteRootSessionId: input.source.rootSessionId,
|
|
756
|
+
taskNoteVersion: input.source.noteVersion,
|
|
757
|
+
taskNoteTextHash: input.source.noteTextHash,
|
|
758
|
+
},
|
|
759
|
+
});
|
|
760
|
+
const evidence = await appendTaskNoteKnowledgeEvidence(db, {
|
|
761
|
+
authority: input.authority,
|
|
762
|
+
operationId: input.evidenceOperationId,
|
|
763
|
+
actor: input.actor,
|
|
764
|
+
claimId: claim.id,
|
|
765
|
+
source: input.source,
|
|
766
|
+
});
|
|
767
|
+
const review = await appendKnowledgeClaimReview(db, {
|
|
768
|
+
accountId: input.authority.accountId,
|
|
769
|
+
workspaceId: input.authority.workspaceId,
|
|
770
|
+
operationId: derivedOperationId(input.request.operationId, "guard"),
|
|
771
|
+
actor: input.actor,
|
|
772
|
+
claimId: claim.id,
|
|
773
|
+
state: "proposed",
|
|
774
|
+
reason: input.request.reason,
|
|
775
|
+
});
|
|
776
|
+
return {
|
|
777
|
+
claimId: claim.id,
|
|
778
|
+
evidenceId: evidence.id,
|
|
779
|
+
confidenceBps: claim.confidenceBps,
|
|
780
|
+
reviewId: review.id,
|
|
781
|
+
source: input.source,
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* The identity of a governed write is what was asked for, not the
|
|
787
|
+
* compare-and-set baseline it happened to read on the way in. An
|
|
788
|
+
* instruction-policy proposal carries the live head revision/version so the CAS
|
|
789
|
+
* can reject a stale write, but hashing those into the operation identity made
|
|
790
|
+
* an ordinary turn-recovery replay of the same operationId look like a
|
|
791
|
+
* different operation once the head moved, which surfaced as a replayed-with-
|
|
792
|
+
* different-immutable-input failure. Strip exactly those two fields, and only
|
|
793
|
+
* for that request kind, so every other lane's hash stays byte-identical.
|
|
794
|
+
*/
|
|
795
|
+
function identityRequest(request: CompanyBrainGovernedWriteRequestType): unknown {
|
|
796
|
+
if (!isInstructionPolicyProposal(request)) return request;
|
|
797
|
+
const {
|
|
798
|
+
expectedCurrentRevisionId: _revision,
|
|
799
|
+
expectedActivationVersion: _version,
|
|
800
|
+
...rest
|
|
801
|
+
} = request;
|
|
802
|
+
// Deliberately no longer the request union: this value only ever feeds the
|
|
803
|
+
// identity hash, never a code path that reads those fields.
|
|
804
|
+
return rest;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* Task-note promotion lands in exactly the same destination materialization as
|
|
809
|
+
* a direct `propose_instruction_policy` / `propose_preference`, so the
|
|
810
|
+
* agent-authored prompt budget has to be enforced here too. Without it the note
|
|
811
|
+
* (bounded only by `TASK_NOTE_TEXT_MAX_BYTES`) is a way to write a long
|
|
812
|
+
* procedure into an always-composed rule through the back door.
|
|
813
|
+
*
|
|
814
|
+
* The note bytes stay exact evidence: this rejects the promotion rather than
|
|
815
|
+
* truncating or rewriting anything, and it runs before any evidence, claim, or
|
|
816
|
+
* proposal row is written. A convergent replay of a promotion that was already
|
|
817
|
+
* accepted is deliberately not re-checked, so stored rows are never invalidated
|
|
818
|
+
* after the fact.
|
|
819
|
+
*/
|
|
820
|
+
function assertAgentAuthoredPromotionBudget(
|
|
821
|
+
request: CompanyBrainGovernedWriteRequestType,
|
|
822
|
+
noteText: string,
|
|
823
|
+
): void {
|
|
824
|
+
const kind =
|
|
825
|
+
request.kind === "promote_task_note_instruction_policy"
|
|
826
|
+
? ("instruction_policy" as const)
|
|
827
|
+
: request.kind === "promote_task_note_preference"
|
|
828
|
+
? ("preference" as const)
|
|
829
|
+
: null;
|
|
830
|
+
if (kind === null) return;
|
|
831
|
+
const maxChars =
|
|
832
|
+
kind === "instruction_policy"
|
|
833
|
+
? AGENT_AUTHORED_INSTRUCTION_POLICY_CONTENT_MAX_CHARS
|
|
834
|
+
: AGENT_AUTHORED_PREFERENCE_CONTENT_MAX_CHARS;
|
|
835
|
+
if (noteText.length <= maxChars) return;
|
|
836
|
+
throw new CompanyBrainGovernedWriteInvalidOperationError(
|
|
837
|
+
agentAuthoredDurableTextTooLongMessage({ kind, actualChars: noteText.length }),
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
function isInstructionPolicyProposal(
|
|
842
|
+
request: CompanyBrainGovernedWriteRequestType,
|
|
843
|
+
): request is InstructionPolicyProposalRequest {
|
|
844
|
+
return (
|
|
845
|
+
request.kind === "propose_instruction_policy" ||
|
|
846
|
+
request.kind === "promote_task_note_instruction_policy"
|
|
847
|
+
);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
async function materializeWaysOfWorkingProposal(
|
|
851
|
+
db: Database,
|
|
852
|
+
input: {
|
|
853
|
+
authority: AttemptAuthority;
|
|
854
|
+
request: InstructionPolicyProposalRequest | PreferenceProposalRequest;
|
|
855
|
+
content: string;
|
|
856
|
+
evidence: WorkspaceEvidence;
|
|
857
|
+
reviewId: string;
|
|
858
|
+
actor: ScopedKnowledgeActor;
|
|
859
|
+
inputHash: string;
|
|
860
|
+
taskNoteSource?: TaskNotePromotionSource;
|
|
861
|
+
},
|
|
862
|
+
): Promise<CompanyBrainGovernedWriteReceiptType> {
|
|
863
|
+
const taskNoteSource = input.taskNoteSource
|
|
864
|
+
? {
|
|
865
|
+
noteId: input.taskNoteSource.noteId,
|
|
866
|
+
rootSessionId: input.taskNoteSource.rootSessionId,
|
|
867
|
+
noteVersion: input.taskNoteSource.noteVersion,
|
|
868
|
+
textHash: input.taskNoteSource.noteTextHash,
|
|
869
|
+
}
|
|
870
|
+
: undefined;
|
|
871
|
+
|
|
872
|
+
if (isInstructionPolicyProposal(input.request)) {
|
|
873
|
+
const changeProposal = await createKnowledgeChangeProposal(db, {
|
|
874
|
+
accountId: input.authority.accountId,
|
|
875
|
+
workspaceId: input.authority.workspaceId,
|
|
876
|
+
operationId: derivedOperationId(input.request.operationId, "knowledge-change-proposal"),
|
|
877
|
+
actor: input.actor,
|
|
878
|
+
claimId: input.evidence.claimId,
|
|
879
|
+
evidenceId: input.evidence.evidenceId,
|
|
880
|
+
targetKind: "instruction_policy",
|
|
881
|
+
targetScope: input.request.target.scope,
|
|
882
|
+
targetKey: input.request.target.scope === "role" ? input.request.target.roleKey : null,
|
|
883
|
+
content: input.content,
|
|
884
|
+
});
|
|
885
|
+
const proposal = await createWorkspaceInstructionPolicyKnowledgeProposal(db, {
|
|
886
|
+
operationId: derivedOperationId(input.request.operationId, "instruction-proposal"),
|
|
887
|
+
accountId: input.authority.accountId,
|
|
888
|
+
workspaceId: input.authority.workspaceId,
|
|
889
|
+
...input.request.target,
|
|
890
|
+
content: input.content,
|
|
891
|
+
knowledgeProposalId: changeProposal.id,
|
|
892
|
+
knowledgeProposalContentHash: changeProposal.contentHash,
|
|
893
|
+
confidenceBps: input.evidence.confidenceBps,
|
|
894
|
+
expectedCurrentRevisionId: input.request.expectedCurrentRevisionId,
|
|
895
|
+
expectedActivationVersion: input.request.expectedActivationVersion,
|
|
896
|
+
createdBySubjectId: input.actor.subjectId,
|
|
897
|
+
});
|
|
898
|
+
return receipt({
|
|
899
|
+
operationId: input.request.operationId,
|
|
900
|
+
inputHash: input.inputHash,
|
|
901
|
+
workspaceId: input.authority.workspaceId,
|
|
902
|
+
destination: "instruction_policy",
|
|
903
|
+
claimId: input.evidence.claimId,
|
|
904
|
+
evidenceId: input.evidence.evidenceId,
|
|
905
|
+
relationId: null,
|
|
906
|
+
reviewId: input.reviewId,
|
|
907
|
+
knowledgeChangeProposalId: changeProposal.id,
|
|
908
|
+
destinationProposalId: proposal.id,
|
|
909
|
+
destinationRevisionId: proposal.draft.id,
|
|
910
|
+
taskNoteSource,
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
const changeProposal = await createKnowledgeChangeProposal(db, {
|
|
915
|
+
accountId: input.authority.accountId,
|
|
916
|
+
workspaceId: input.authority.workspaceId,
|
|
917
|
+
operationId: derivedOperationId(input.request.operationId, "knowledge-change-proposal"),
|
|
918
|
+
actor: input.actor,
|
|
919
|
+
claimId: input.evidence.claimId,
|
|
920
|
+
evidenceId: input.evidence.evidenceId,
|
|
921
|
+
targetKind: "preference",
|
|
922
|
+
targetScope: "workspace",
|
|
923
|
+
targetKey: input.request.stableKey,
|
|
924
|
+
content: preferenceProposalContent(input.request, input.content),
|
|
925
|
+
});
|
|
926
|
+
const proposal = await createWorkspacePreferenceProposalForAttempt(
|
|
927
|
+
db,
|
|
928
|
+
input.authority,
|
|
929
|
+
input.request,
|
|
930
|
+
input.content,
|
|
931
|
+
changeProposal.id,
|
|
932
|
+
input.inputHash,
|
|
933
|
+
);
|
|
934
|
+
return receipt({
|
|
935
|
+
operationId: input.request.operationId,
|
|
936
|
+
inputHash: input.inputHash,
|
|
937
|
+
workspaceId: input.authority.workspaceId,
|
|
938
|
+
destination: "preference",
|
|
939
|
+
claimId: input.evidence.claimId,
|
|
940
|
+
evidenceId: input.evidence.evidenceId,
|
|
941
|
+
relationId: null,
|
|
942
|
+
reviewId: input.reviewId,
|
|
943
|
+
knowledgeChangeProposalId: changeProposal.id,
|
|
944
|
+
destinationProposalId: proposal.preferenceId,
|
|
945
|
+
destinationRevisionId: proposal.revisionId,
|
|
946
|
+
taskNoteSource,
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
/**
|
|
951
|
+
* Route one explicit workspace-local proposal. This owns write admission only;
|
|
952
|
+
* selector snapshots, logical-turn receipts, tools, and activation remain out of scope.
|
|
953
|
+
*/
|
|
954
|
+
/**
|
|
955
|
+
* Write result: the agent-facing receipt plus the exact initiating human the
|
|
956
|
+
* accepted attempt froze. The subject id is internal routing authority for the
|
|
957
|
+
* governed-learning evaluator/controller and is stripped from public receipts.
|
|
958
|
+
*/
|
|
959
|
+
export type CompanyBrainGovernedWriteResult = CompanyBrainGovernedWriteReceiptType & {
|
|
960
|
+
initiatingHumanSubjectId: string;
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
export async function writeCompanyBrainGovernedProposal(
|
|
964
|
+
db: Database,
|
|
965
|
+
rawInput: {
|
|
966
|
+
attempt: CompanyBrainGovernedWriteAttempt;
|
|
967
|
+
request: CompanyBrainGovernedWriteRequestType;
|
|
968
|
+
},
|
|
969
|
+
): Promise<CompanyBrainGovernedWriteResult> {
|
|
970
|
+
const attempt = CompanyBrainGovernedWriteAttempt.parse(rawInput.attempt);
|
|
971
|
+
const request = CompanyBrainGovernedWriteRequest.parse(rawInput.request);
|
|
972
|
+
const inputHash = scopedKnowledgeInputHash({
|
|
973
|
+
attempt,
|
|
974
|
+
request: identityRequest(request),
|
|
975
|
+
});
|
|
976
|
+
const actorSubjectId = `service:company-brain-governed-write:${inputHash}`;
|
|
977
|
+
const evidenceOperationId = derivedOperationId(request.operationId, "task-note-evidence");
|
|
978
|
+
const claimOperationId = derivedOperationId(request.operationId, "task-note-claim");
|
|
979
|
+
return await withCompanyBrainGovernedWriteAuthority(
|
|
980
|
+
db,
|
|
981
|
+
attempt,
|
|
982
|
+
isInstructionPolicyProposal(request) ? "update" : "key_share",
|
|
983
|
+
async (scopedDb): Promise<TaskNotePromotionSource | null> => {
|
|
984
|
+
if (!isTaskNotePromotion(request)) return null;
|
|
985
|
+
if (
|
|
986
|
+
await taskNotePromotionAlreadyMaterialized(scopedDb, attempt.accountId, evidenceOperationId)
|
|
987
|
+
) {
|
|
988
|
+
return null;
|
|
989
|
+
}
|
|
990
|
+
return await resolveTaskNotePromotionSource(
|
|
991
|
+
scopedDb,
|
|
992
|
+
attempt,
|
|
993
|
+
request.noteId,
|
|
994
|
+
request.expectedNoteVersion,
|
|
995
|
+
evidenceOperationId,
|
|
996
|
+
claimOperationId,
|
|
997
|
+
actorSubjectId,
|
|
998
|
+
);
|
|
999
|
+
},
|
|
1000
|
+
async (scopedDb, authority, prelockedSource) => ({
|
|
1001
|
+
...(await writeGovernedProposalBody(scopedDb, authority, prelockedSource)),
|
|
1002
|
+
initiatingHumanSubjectId: authority.initiatingHumanSubjectId,
|
|
1003
|
+
}),
|
|
1004
|
+
).catch((error: unknown) => {
|
|
1005
|
+
if (
|
|
1006
|
+
error instanceof CompanyBrainGovernedWriteAuthorityError ||
|
|
1007
|
+
error instanceof CompanyBrainGovernedWriteInvalidOperationError
|
|
1008
|
+
) {
|
|
1009
|
+
throw error;
|
|
1010
|
+
}
|
|
1011
|
+
if (error instanceof ScopedKnowledgeAuthorityError) {
|
|
1012
|
+
throw new CompanyBrainGovernedWriteAuthorityError(error.message);
|
|
1013
|
+
}
|
|
1014
|
+
if (error instanceof ScopedKnowledgeInvalidOperationError) {
|
|
1015
|
+
throw new CompanyBrainGovernedWriteInvalidOperationError(error.message);
|
|
1016
|
+
}
|
|
1017
|
+
throw error;
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
async function writeGovernedProposalBody(
|
|
1021
|
+
scopedDb: Database,
|
|
1022
|
+
authority: AttemptAuthority,
|
|
1023
|
+
prelockedSource: TaskNotePromotionSource | null,
|
|
1024
|
+
): Promise<CompanyBrainGovernedWriteReceiptType> {
|
|
1025
|
+
{
|
|
1026
|
+
const actor: ScopedKnowledgeActor = {
|
|
1027
|
+
kind: "service",
|
|
1028
|
+
subjectId: actorSubjectId,
|
|
1029
|
+
initiatingHumanSubjectId: authority.initiatingHumanSubjectId,
|
|
1030
|
+
};
|
|
1031
|
+
if (isTaskNotePromotion(request)) {
|
|
1032
|
+
let materialization: TaskNoteKnowledgeMaterialization;
|
|
1033
|
+
if (prelockedSource === null) {
|
|
1034
|
+
const replayed = await replayTaskNoteKnowledgeMaterialization(
|
|
1035
|
+
scopedDb,
|
|
1036
|
+
authority,
|
|
1037
|
+
request.operationId,
|
|
1038
|
+
inputHash,
|
|
1039
|
+
);
|
|
1040
|
+
if (!replayed) {
|
|
1041
|
+
throw new CompanyBrainGovernedWriteInvalidOperationError(
|
|
1042
|
+
"Task-note promotion source changed before exact authority admission",
|
|
1043
|
+
);
|
|
1044
|
+
}
|
|
1045
|
+
materialization = replayed;
|
|
1046
|
+
} else {
|
|
1047
|
+
if (prelockedSource.initiatingHumanSubjectId !== authority.initiatingHumanSubjectId) {
|
|
1048
|
+
throw new CompanyBrainGovernedWriteAuthorityError(
|
|
1049
|
+
"Task-note promotion source did not preserve exact attempt authority",
|
|
1050
|
+
);
|
|
1051
|
+
}
|
|
1052
|
+
assertAgentAuthoredPromotionBudget(request, prelockedSource.noteText);
|
|
1053
|
+
materialization = await materializeTaskNoteKnowledge(scopedDb, {
|
|
1054
|
+
authority,
|
|
1055
|
+
request,
|
|
1056
|
+
actor,
|
|
1057
|
+
source: prelockedSource,
|
|
1058
|
+
evidenceOperationId,
|
|
1059
|
+
claimOperationId,
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
if (
|
|
1063
|
+
materialization.source.initiatingHumanSubjectId !== authority.initiatingHumanSubjectId
|
|
1064
|
+
) {
|
|
1065
|
+
throw new CompanyBrainGovernedWriteAuthorityError(
|
|
1066
|
+
"Task-note promotion source did not preserve exact attempt authority",
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
if (request.kind === "promote_task_note_knowledge") {
|
|
1070
|
+
return receipt({
|
|
1071
|
+
operationId: request.operationId,
|
|
1072
|
+
inputHash,
|
|
1073
|
+
workspaceId: authority.workspaceId,
|
|
1074
|
+
destination: "knowledge",
|
|
1075
|
+
claimId: materialization.claimId,
|
|
1076
|
+
evidenceId: materialization.evidenceId,
|
|
1077
|
+
relationId: null,
|
|
1078
|
+
reviewId: materialization.reviewId,
|
|
1079
|
+
knowledgeChangeProposalId: null,
|
|
1080
|
+
destinationProposalId: null,
|
|
1081
|
+
destinationRevisionId: null,
|
|
1082
|
+
taskNoteSource: {
|
|
1083
|
+
noteId: materialization.source.noteId,
|
|
1084
|
+
rootSessionId: materialization.source.rootSessionId,
|
|
1085
|
+
noteVersion: materialization.source.noteVersion,
|
|
1086
|
+
textHash: materialization.source.noteTextHash,
|
|
1087
|
+
},
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
return await materializeWaysOfWorkingProposal(scopedDb, {
|
|
1091
|
+
authority,
|
|
1092
|
+
request,
|
|
1093
|
+
content: materialization.source.noteText,
|
|
1094
|
+
evidence: materialization,
|
|
1095
|
+
reviewId: materialization.reviewId,
|
|
1096
|
+
actor,
|
|
1097
|
+
inputHash,
|
|
1098
|
+
taskNoteSource: materialization.source,
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
const evidence = await requireWorkspaceEvidence(
|
|
1102
|
+
scopedDb,
|
|
1103
|
+
authority,
|
|
1104
|
+
request.claimId,
|
|
1105
|
+
request.evidenceId,
|
|
1106
|
+
request.kind === "correct_knowledge" ? request.replacesClaimId : null,
|
|
1107
|
+
);
|
|
1108
|
+
const review = await appendKnowledgeClaimReview(scopedDb, {
|
|
1109
|
+
accountId: authority.accountId,
|
|
1110
|
+
workspaceId: authority.workspaceId,
|
|
1111
|
+
operationId: derivedOperationId(request.operationId, "guard"),
|
|
1112
|
+
actor,
|
|
1113
|
+
claimId: request.claimId,
|
|
1114
|
+
state: "proposed",
|
|
1115
|
+
reason: request.reason,
|
|
1116
|
+
});
|
|
1117
|
+
|
|
1118
|
+
if (request.kind === "propose_knowledge") {
|
|
1119
|
+
return receipt({
|
|
1120
|
+
operationId: request.operationId,
|
|
1121
|
+
inputHash,
|
|
1122
|
+
workspaceId: authority.workspaceId,
|
|
1123
|
+
destination: "knowledge",
|
|
1124
|
+
claimId: evidence.claimId,
|
|
1125
|
+
evidenceId: evidence.evidenceId,
|
|
1126
|
+
relationId: null,
|
|
1127
|
+
reviewId: review.id,
|
|
1128
|
+
knowledgeChangeProposalId: null,
|
|
1129
|
+
destinationProposalId: null,
|
|
1130
|
+
destinationRevisionId: null,
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
if (request.kind === "correct_knowledge") {
|
|
1135
|
+
const relation = await linkKnowledgeClaims(scopedDb, {
|
|
1136
|
+
accountId: authority.accountId,
|
|
1137
|
+
workspaceId: authority.workspaceId,
|
|
1138
|
+
operationId: derivedOperationId(request.operationId, "knowledge-correction"),
|
|
1139
|
+
actor,
|
|
1140
|
+
relationType: "supersedes",
|
|
1141
|
+
fromClaimId: request.claimId,
|
|
1142
|
+
toClaimId: request.replacesClaimId,
|
|
1143
|
+
});
|
|
1144
|
+
return receipt({
|
|
1145
|
+
operationId: request.operationId,
|
|
1146
|
+
inputHash,
|
|
1147
|
+
workspaceId: authority.workspaceId,
|
|
1148
|
+
destination: "knowledge",
|
|
1149
|
+
claimId: evidence.claimId,
|
|
1150
|
+
evidenceId: evidence.evidenceId,
|
|
1151
|
+
relationId: relation.id,
|
|
1152
|
+
reviewId: review.id,
|
|
1153
|
+
knowledgeChangeProposalId: null,
|
|
1154
|
+
destinationProposalId: null,
|
|
1155
|
+
destinationRevisionId: null,
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
return await materializeWaysOfWorkingProposal(scopedDb, {
|
|
1160
|
+
authority,
|
|
1161
|
+
request,
|
|
1162
|
+
content: request.content,
|
|
1163
|
+
evidence,
|
|
1164
|
+
reviewId: review.id,
|
|
1165
|
+
actor,
|
|
1166
|
+
inputHash,
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
}
|