feat: add ERP agent pet bridge and startup guide
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][ValidateSet('purchase', 'leave')][string]$Workflow,
|
||||
[Parameter(Mandatory = $true)][string]$OutputPath
|
||||
)
|
||||
|
||||
Set-StrictMode -Version 2.0
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$codes = if ($Workflow -eq 'purchase') {
|
||||
@(
|
||||
'purchase_unique_match_commit', 'purchase_ambiguous_match_blocked',
|
||||
'purchase_overallocation_blocked', 'purchase_permission_denied',
|
||||
'purchase_database_permission_recheck_denied',
|
||||
'purchase_currency_field_missing_blocked',
|
||||
'purchase_currency_crosswalk_unapproved_blocked',
|
||||
'purchase_row_scope_denied',
|
||||
'purchase_runtime_recheck_blocked', 'purchase_transaction_rollback',
|
||||
'purchase_idempotency_replay', 'purchase_idempotency_conflict',
|
||||
'purchase_audit_correlated'
|
||||
)
|
||||
} else {
|
||||
@(
|
||||
'leave_natural_language_resolution',
|
||||
'leave_multi_day_calendar_resolution',
|
||||
'leave_resolution_proof_bypass_blocked', 'leave_ambiguous_type_blocked',
|
||||
'leave_ambiguous_flow_type_blocked',
|
||||
'leave_time_segment_required_blocked',
|
||||
'leave_local_time_zone_rejected',
|
||||
'leave_other_employee_denied', 'leave_create_draft_commit',
|
||||
'leave_permission_denied', 'leave_database_permission_recheck_denied',
|
||||
'leave_submit_separate_confirmation', 'leave_overlap_blocked',
|
||||
'leave_stale_flow_type_blocked',
|
||||
'leave_runtime_recheck_blocked', 'leave_transaction_rollback',
|
||||
'leave_idempotency_replay', 'leave_idempotency_conflict',
|
||||
'leave_audit_correlated'
|
||||
)
|
||||
}
|
||||
$placeholderHash = 'REPLACE_WITH_SHA256'
|
||||
$observedAt = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ss.fffZ')
|
||||
$expectedResults = @{
|
||||
purchase_unique_match_commit = 'purchase_document_created'
|
||||
purchase_ambiguous_match_blocked = 'purchase_match_invalid'
|
||||
purchase_overallocation_blocked = 'purchase_match_invalid'
|
||||
purchase_permission_denied = 'command_access_denied'
|
||||
purchase_database_permission_recheck_denied = 'purchase_write_permission_denied'
|
||||
purchase_currency_field_missing_blocked = 'purchase_currency_field_not_configured'
|
||||
purchase_currency_crosswalk_unapproved_blocked = 'purchase_currency_crosswalk_not_approved'
|
||||
purchase_row_scope_denied = 'purchase_row_scope_denied'
|
||||
purchase_runtime_recheck_blocked = 'purchase_source_changed'
|
||||
purchase_transaction_rollback = 'purchase_legacy_create_failed'
|
||||
purchase_idempotency_replay = 'purchase_document_created'
|
||||
purchase_idempotency_conflict = 'idempotency_key_conflict'
|
||||
purchase_audit_correlated = 'purchase_document_created'
|
||||
leave_natural_language_resolution = 'leave_intent_resolved'
|
||||
leave_multi_day_calendar_resolution = 'leave_intent_resolved'
|
||||
leave_resolution_proof_bypass_blocked = 'leave_resolution_invalid'
|
||||
leave_ambiguous_type_blocked = 'leave_resolution_invalid'
|
||||
leave_ambiguous_flow_type_blocked = 'leave_resolution_invalid'
|
||||
leave_time_segment_required_blocked = 'leave_resolution_invalid'
|
||||
leave_local_time_zone_rejected = 'input_schema_violation'
|
||||
leave_other_employee_denied = 'leave_resolution_invalid'
|
||||
leave_permission_denied = 'command_access_denied'
|
||||
leave_database_permission_recheck_denied = 'leave_write_permission_denied'
|
||||
leave_create_draft_commit = 'leave_draft_created'
|
||||
leave_submit_separate_confirmation = 'leave_submitted'
|
||||
leave_overlap_blocked = 'leave_request_invalid'
|
||||
leave_stale_flow_type_blocked = 'leave_request_changed'
|
||||
leave_runtime_recheck_blocked = 'leave_request_changed'
|
||||
leave_transaction_rollback = 'leave_legacy_create_failed'
|
||||
leave_idempotency_replay = 'leave_draft_created'
|
||||
leave_idempotency_conflict = 'idempotency_key_conflict'
|
||||
leave_audit_correlated = 'leave_draft_created'
|
||||
}
|
||||
$expectedIssues = @{
|
||||
leave_ambiguous_type_blocked = 'leave_type_ambiguous'
|
||||
leave_ambiguous_flow_type_blocked = 'leave_flow_type_ambiguous'
|
||||
leave_time_segment_required_blocked = 'leave_time_segment_required'
|
||||
leave_other_employee_denied = 'leave_employee_reference_unsupported'
|
||||
}
|
||||
$cases = @($codes | ForEach-Object {
|
||||
$caseCode = [string]$_
|
||||
$commandName = if ($caseCode.StartsWith('purchase_', [StringComparison]::Ordinal)) {
|
||||
'purchase.invoice.create'
|
||||
} elseif ($caseCode -in @(
|
||||
'leave_natural_language_resolution',
|
||||
'leave_multi_day_calendar_resolution',
|
||||
'leave_ambiguous_type_blocked',
|
||||
'leave_ambiguous_flow_type_blocked',
|
||||
'leave_time_segment_required_blocked',
|
||||
'leave_other_employee_denied')) {
|
||||
'hr.leave.resolve'
|
||||
} elseif ($caseCode -eq 'leave_submit_separate_confirmation') {
|
||||
'hr.leave.submit'
|
||||
} else {
|
||||
'hr.leave.create'
|
||||
}
|
||||
$planRequired = $caseCode -notin @(
|
||||
'purchase_permission_denied',
|
||||
'leave_permission_denied',
|
||||
'leave_local_time_zone_rejected')
|
||||
$planVersion = if (-not $planRequired) {
|
||||
$null
|
||||
} elseif ($commandName -eq 'purchase.invoice.create') {
|
||||
'1.4'
|
||||
} elseif ($commandName -eq 'hr.leave.resolve') {
|
||||
'1.4'
|
||||
} elseif ($commandName -eq 'hr.leave.submit') {
|
||||
'1.0'
|
||||
} else {
|
||||
'1.2'
|
||||
}
|
||||
$planRisk = if (-not $planRequired) {
|
||||
$null
|
||||
} elseif ($commandName -eq 'hr.leave.resolve') {
|
||||
'draft'
|
||||
} else {
|
||||
'write'
|
||||
}
|
||||
$issueCode = $null
|
||||
if ($expectedIssues.ContainsKey($caseCode)) {
|
||||
$issueCode = [string]$expectedIssues[$caseCode]
|
||||
}
|
||||
[ordered]@{
|
||||
caseCode = $caseCode
|
||||
uatAuthorizationSourceSha256 =
|
||||
'REPLACE_WITH_UAT_AUTHORIZATION_SOURCE_SHA256'
|
||||
uatAuthorizationContentSha256 =
|
||||
'REPLACE_WITH_UAT_AUTHORIZATION_CONTENT_SHA256'
|
||||
uatAuthorizationIdSha256 =
|
||||
'REPLACE_WITH_UAT_AUTHORIZATION_ID_SHA256'
|
||||
uatTokenSha256 = 'REPLACE_WITH_UNIQUE_UAT_CASE_TOKEN_SHA256'
|
||||
runtimeCliVersion = 'REPLACE_WITH_RUNTIME_CLI_VERSION'
|
||||
runtimeCliSha256 = 'REPLACE_WITH_RUNTIME_CLI_SHA256'
|
||||
runtimeCliSignerThumbprint =
|
||||
'REPLACE_WITH_RUNTIME_CLI_SIGNER_THUMBPRINT'
|
||||
passed = $false
|
||||
correlationId = 'REPLACE_WITH_CORRELATION_ID'
|
||||
contextCorrelationBound = $false
|
||||
commandName = $commandName
|
||||
planCommandVersion = $planVersion
|
||||
planModuleCode = $(if ($planRequired) { 'REPLACE_WITH_MODULE_CODE' } else { $null })
|
||||
planRisk = $planRisk
|
||||
accountBookSha256 = $placeholderHash
|
||||
subSystemIdSha256 = $placeholderHash
|
||||
userIdSha256 = $placeholderHash
|
||||
userNameSha256 = $placeholderHash
|
||||
databaseScopeFingerprint = $placeholderHash
|
||||
isAdministrator = $false
|
||||
inputFingerprintSha256 = $placeholderHash
|
||||
planFingerprintSha256 = $null
|
||||
resultCode = [string]$expectedResults[$caseCode]
|
||||
issueCode = $issueCode
|
||||
recordIdSha256 = $null
|
||||
transactionEvidenceIdSha256 = $null
|
||||
businessAuditIdSha256 = $null
|
||||
idempotencyKeySha256 = $null
|
||||
businessMutationCount = 0
|
||||
replayed = $false
|
||||
nativeConfirmationObserved = $false
|
||||
auditEventCount = 1
|
||||
sourceDocumentSetSha256 = $null
|
||||
sourceDocumentPreprocessContracts = @()
|
||||
sourceDocumentInputFingerprintBound = $false
|
||||
sourceDocumentWritePayloadBound = $false
|
||||
sourceDocumentAuditCount = 0
|
||||
observedAtUtc = $observedAt
|
||||
}
|
||||
})
|
||||
$target = [IO.Path]::GetFullPath($OutputPath)
|
||||
$directory = [IO.Path]::GetDirectoryName($target)
|
||||
if ([string]::IsNullOrWhiteSpace($directory) -or -not [IO.Directory]::Exists($directory) -or
|
||||
[IO.File]::Exists($target) -or [IO.Directory]::Exists($target)) {
|
||||
throw 'Output must be a new file in an existing directory.'
|
||||
}
|
||||
$utf8 = New-Object Text.UTF8Encoding($false, $true)
|
||||
$body = $utf8.GetBytes(($cases | ConvertTo-Json -Depth 5) + [Environment]::NewLine)
|
||||
$stream = [IO.File]::Open(
|
||||
$target, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None)
|
||||
try { $stream.Write($body, 0, $body.Length); $stream.Flush() }
|
||||
finally { $stream.Dispose() }
|
||||
|
||||
[ordered]@{
|
||||
outputFile = $target
|
||||
workflow = $Workflow
|
||||
caseCount = $cases.Count
|
||||
ready = $false
|
||||
nextStep = 'Replace every placeholder with observed, redacted evidence; keep passed=false until independently reviewed.'
|
||||
} | ConvertTo-Json -Depth 4
|
||||
Reference in New Issue
Block a user